@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.
Files changed (75) hide show
  1. package/BROWSER_API.md +318 -0
  2. package/README.md +216 -0
  3. package/REFACTORING_SUMMARY.txt +250 -0
  4. package/WORKFLOW_SUMMARY.txt +78 -0
  5. package/bin/ncntokar-cli.js +39 -0
  6. package/dist/client.d.ts +26 -0
  7. package/dist/client.js +74 -0
  8. package/dist/emk/client-decoder.d.ts +22 -0
  9. package/dist/emk/client-decoder.js +133 -0
  10. package/dist/emk/server-decode.d.ts +21 -0
  11. package/dist/emk/server-decode.js +123 -0
  12. package/dist/emk-to-kar.browser.d.ts +51 -0
  13. package/dist/emk-to-kar.browser.js +139 -0
  14. package/dist/emk-to-kar.d.ts +53 -0
  15. package/dist/emk-to-kar.js +210 -0
  16. package/dist/index.d.ts +12 -0
  17. package/dist/index.js +64 -0
  18. package/dist/kar-reader.browser.d.ts +46 -0
  19. package/dist/kar-reader.browser.js +209 -0
  20. package/dist/kar-reader.d.ts +42 -0
  21. package/dist/kar-reader.js +197 -0
  22. package/dist/ncntokar.browser.d.ts +99 -0
  23. package/dist/ncntokar.browser.js +296 -0
  24. package/dist/ncntokar.d.ts +88 -0
  25. package/dist/ncntokar.js +340 -0
  26. package/examples/NextJSComponent.tsx +175 -0
  27. package/libs/emk/client-decoder.ts +142 -0
  28. package/libs/emk/server-decode.ts +133 -0
  29. package/libs/ncntokar.js +256 -0
  30. package/package.json +79 -0
  31. package/songs/.gitkeep +3 -0
  32. package/songs/cur/BPL3457.cur +0 -0
  33. package/songs/cur/Z2510006.cur +0 -0
  34. package/songs/cur/Z2510008.cur +0 -0
  35. package/songs/cur/Z2510136.cur +0 -0
  36. package/songs/cur/Z2510137.cur +0 -0
  37. package/songs/cur/Z2510138.cur +0 -0
  38. package/songs/cur/Z2510139.cur +0 -0
  39. package/songs/cur/Z2510140.cur +0 -0
  40. package/songs/cur/Z2510141.cur +0 -0
  41. package/songs/cur/song.cur +0 -0
  42. package/songs/emk/Z2510001.emk +0 -0
  43. package/songs/emk/Z2510002.emk +0 -0
  44. package/songs/emk/Z2510003.emk +0 -0
  45. package/songs/emk/Z2510004.emk +0 -0
  46. package/songs/emk/Z2510005.emk +0 -0
  47. package/songs/emk/Z2510006.emk +0 -0
  48. package/songs/kar/bpl3457.kar +0 -0
  49. package/songs/kar/z2510006.kar +0 -0
  50. package/songs/kar/z2510008.kar +0 -0
  51. package/songs/kar/z2510136.kar +0 -0
  52. package/songs/kar/z2510137.kar +0 -0
  53. package/songs/kar/z2510138.kar +0 -0
  54. package/songs/kar/z2510139.kar +0 -0
  55. package/songs/kar/z2510140.kar +0 -0
  56. package/songs/kar/z2510141.kar +0 -0
  57. package/songs/lyr/BPL3457.lyr +57 -0
  58. package/songs/lyr/Z2510006.lyr +53 -0
  59. package/songs/lyr/Z2510008.lyr +57 -0
  60. package/songs/lyr/Z2510136.lyr +54 -0
  61. package/songs/lyr/Z2510137.lyr +66 -0
  62. package/songs/lyr/Z2510138.lyr +62 -0
  63. package/songs/lyr/Z2510139.lyr +60 -0
  64. package/songs/lyr/Z2510140.lyr +41 -0
  65. package/songs/lyr/Z2510141.lyr +48 -0
  66. package/songs/lyr/song.lyr +37 -0
  67. package/songs/midi/BPL3457.MID +0 -0
  68. package/songs/midi/Z2510006.mid +0 -0
  69. package/songs/midi/Z2510008.mid +0 -0
  70. package/songs/midi/Z2510136.mid +0 -0
  71. package/songs/midi/Z2510137.mid +0 -0
  72. package/songs/midi/Z2510138.mid +0 -0
  73. package/songs/midi/Z2510139.mid +0 -0
  74. package/songs/midi/Z2510140.mid +0 -0
  75. package/songs/midi/Z2510141.mid +0 -0
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Browser-compatible KAR file reader
3
+ * Reads and validates .kar files from buffers
4
+ */
5
+ export interface KarFileInfo {
6
+ isValid: boolean;
7
+ header: {
8
+ format?: number;
9
+ numTracks?: number;
10
+ ticksPerBeat?: number;
11
+ };
12
+ tracks: KarTrack[];
13
+ metadata: {
14
+ title?: string;
15
+ artist?: string;
16
+ hasKaraokeTrack: boolean;
17
+ hasLyricTrack: boolean;
18
+ };
19
+ }
20
+ export interface KarTrack {
21
+ name?: string;
22
+ events: number;
23
+ hasText: boolean;
24
+ hasLyrics: boolean;
25
+ textEvents: string[];
26
+ }
27
+ /**
28
+ * Reads and parses a KAR file from buffer
29
+ */
30
+ export declare function readKarBuffer(buffer: Buffer): KarFileInfo;
31
+ /**
32
+ * Validates that a KAR buffer has the expected structure
33
+ */
34
+ export declare function validateKarBuffer(buffer: Buffer): {
35
+ valid: boolean;
36
+ errors: string[];
37
+ warnings: string[];
38
+ };
39
+ /**
40
+ * Extracts lyrics from a KAR buffer
41
+ */
42
+ export declare function extractLyricsFromKarBuffer(buffer: Buffer): string[];
43
+ /**
44
+ * Helper to read File object as KAR
45
+ */
46
+ export declare function readKarFile(file: File): Promise<KarFileInfo>;
@@ -0,0 +1,209 @@
1
+ "use strict";
2
+ /**
3
+ * Browser-compatible KAR file reader
4
+ * Reads and validates .kar files from buffers
5
+ */
6
+ 'use client';
7
+ /**
8
+ * Browser-compatible KAR file reader
9
+ * Reads and validates .kar files from buffers
10
+ */
11
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ var desc = Object.getOwnPropertyDescriptor(m, k);
14
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
15
+ desc = { enumerable: true, get: function() { return m[k]; } };
16
+ }
17
+ Object.defineProperty(o, k2, desc);
18
+ }) : (function(o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k;
20
+ o[k2] = m[k];
21
+ }));
22
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
23
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
24
+ }) : function(o, v) {
25
+ o["default"] = v;
26
+ });
27
+ var __importStar = (this && this.__importStar) || (function () {
28
+ var ownKeys = function(o) {
29
+ ownKeys = Object.getOwnPropertyNames || function (o) {
30
+ var ar = [];
31
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
32
+ return ar;
33
+ };
34
+ return ownKeys(o);
35
+ };
36
+ return function (mod) {
37
+ if (mod && mod.__esModule) return mod;
38
+ var result = {};
39
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
40
+ __setModuleDefault(result, mod);
41
+ return result;
42
+ };
43
+ })();
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.readKarBuffer = readKarBuffer;
46
+ exports.validateKarBuffer = validateKarBuffer;
47
+ exports.extractLyricsFromKarBuffer = extractLyricsFromKarBuffer;
48
+ exports.readKarFile = readKarFile;
49
+ const midi_file_1 = require("midi-file");
50
+ const iconv = __importStar(require("iconv-lite"));
51
+ /**
52
+ * Reads and parses a KAR file from buffer
53
+ */
54
+ function readKarBuffer(buffer) {
55
+ const midi = (0, midi_file_1.parseMidi)(buffer);
56
+ const info = {
57
+ isValid: true,
58
+ header: {
59
+ format: midi.header.format,
60
+ numTracks: midi.header.numTracks,
61
+ ticksPerBeat: midi.header.ticksPerBeat
62
+ },
63
+ tracks: [],
64
+ metadata: {
65
+ hasKaraokeTrack: false,
66
+ hasLyricTrack: false
67
+ }
68
+ };
69
+ // Process each track
70
+ for (const track of midi.tracks || []) {
71
+ const trackInfo = {
72
+ events: track.length,
73
+ hasText: false,
74
+ hasLyrics: false,
75
+ textEvents: []
76
+ };
77
+ for (const event of track) {
78
+ // Handle different event types
79
+ if (event.type === 'trackName' && 'text' in event) {
80
+ trackInfo.name = event.text;
81
+ }
82
+ else if (event.type === 'text' && 'text' in event) {
83
+ trackInfo.hasText = true;
84
+ const text = event.text;
85
+ trackInfo.textEvents.push(text);
86
+ // Check for karaoke markers
87
+ if (text.startsWith('@T')) {
88
+ if (!info.metadata.title) {
89
+ info.metadata.title = text.substring(2);
90
+ }
91
+ else if (!info.metadata.artist) {
92
+ info.metadata.artist = text.substring(2);
93
+ }
94
+ }
95
+ }
96
+ else if (event.type === 'lyrics' && 'text' in event) {
97
+ trackInfo.hasLyrics = true;
98
+ trackInfo.textEvents.push(event.text);
99
+ }
100
+ else if (event.type === 'unknownMeta' && 'data' in event) {
101
+ // Handle TIS-620 encoded text events
102
+ const data = event.data;
103
+ if (data && data.length > 0) {
104
+ try {
105
+ const buffer = Buffer.from(data);
106
+ const text = iconv.decode(buffer, 'tis-620');
107
+ trackInfo.hasText = true;
108
+ trackInfo.textEvents.push(text);
109
+ if (text.startsWith('@T')) {
110
+ if (!info.metadata.title) {
111
+ info.metadata.title = text.substring(2);
112
+ }
113
+ else if (!info.metadata.artist) {
114
+ info.metadata.artist = text.substring(2);
115
+ }
116
+ }
117
+ }
118
+ catch (e) {
119
+ // Ignore decode errors
120
+ }
121
+ }
122
+ }
123
+ }
124
+ // Identify special tracks
125
+ if (trackInfo.name === 'Words') {
126
+ info.metadata.hasKaraokeTrack = true;
127
+ }
128
+ else if (trackInfo.name === 'Lyric') {
129
+ info.metadata.hasLyricTrack = true;
130
+ }
131
+ else if (trackInfo.name === 'SongTitle' && trackInfo.textEvents.length > 0) {
132
+ info.metadata.title = trackInfo.textEvents[0];
133
+ }
134
+ else if (trackInfo.name === 'Artist' && trackInfo.textEvents.length > 0) {
135
+ info.metadata.artist = trackInfo.textEvents[0];
136
+ }
137
+ info.tracks.push(trackInfo);
138
+ }
139
+ return info;
140
+ }
141
+ /**
142
+ * Validates that a KAR buffer has the expected structure
143
+ */
144
+ function validateKarBuffer(buffer) {
145
+ const errors = [];
146
+ const warnings = [];
147
+ try {
148
+ const info = readKarBuffer(buffer);
149
+ // Check basic structure
150
+ if (!info.header.ticksPerBeat) {
151
+ errors.push('Missing ticksPerBeat in header');
152
+ }
153
+ if (info.tracks.length === 0) {
154
+ errors.push('No tracks found in file');
155
+ }
156
+ // Check for karaoke tracks
157
+ if (!info.metadata.hasKaraokeTrack) {
158
+ warnings.push('No "Words" karaoke track found');
159
+ }
160
+ if (!info.metadata.hasLyricTrack) {
161
+ warnings.push('No "Lyric" track found');
162
+ }
163
+ if (!info.metadata.title) {
164
+ warnings.push('No title metadata found');
165
+ }
166
+ if (!info.metadata.artist) {
167
+ warnings.push('No artist metadata found');
168
+ }
169
+ return {
170
+ valid: errors.length === 0,
171
+ errors,
172
+ warnings
173
+ };
174
+ }
175
+ catch (error) {
176
+ errors.push(`Failed to read KAR buffer: ${error.message}`);
177
+ return {
178
+ valid: false,
179
+ errors,
180
+ warnings
181
+ };
182
+ }
183
+ }
184
+ /**
185
+ * Extracts lyrics from a KAR buffer
186
+ */
187
+ function extractLyricsFromKarBuffer(buffer) {
188
+ const info = readKarBuffer(buffer);
189
+ const lyrics = [];
190
+ for (const track of info.tracks) {
191
+ if (track.name === 'Words' || track.hasText) {
192
+ for (const text of track.textEvents) {
193
+ // Skip metadata markers
194
+ if (!text.startsWith('@')) {
195
+ lyrics.push(text);
196
+ }
197
+ }
198
+ }
199
+ }
200
+ return lyrics;
201
+ }
202
+ /**
203
+ * Helper to read File object as KAR
204
+ */
205
+ async function readKarFile(file) {
206
+ const arrayBuffer = await file.arrayBuffer();
207
+ const buffer = Buffer.from(arrayBuffer);
208
+ return readKarBuffer(buffer);
209
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * KAR file reader utility
3
+ * Reads and validates .kar (MIDI karaoke) files
4
+ */
5
+ export interface KarFileInfo {
6
+ isValid: boolean;
7
+ header: {
8
+ format?: number;
9
+ numTracks?: number;
10
+ ticksPerBeat?: number;
11
+ };
12
+ tracks: KarTrack[];
13
+ metadata: {
14
+ title?: string;
15
+ artist?: string;
16
+ hasKaraokeTrack: boolean;
17
+ hasLyricTrack: boolean;
18
+ };
19
+ }
20
+ export interface KarTrack {
21
+ name?: string;
22
+ events: number;
23
+ hasText: boolean;
24
+ hasLyrics: boolean;
25
+ textEvents: string[];
26
+ }
27
+ /**
28
+ * Reads and parses a KAR file
29
+ */
30
+ export declare function readKarFile(filePath: string): KarFileInfo;
31
+ /**
32
+ * Validates that a KAR file has the expected structure
33
+ */
34
+ export declare function validateKarFile(filePath: string): {
35
+ valid: boolean;
36
+ errors: string[];
37
+ warnings: string[];
38
+ };
39
+ /**
40
+ * Extracts lyrics from a KAR file
41
+ */
42
+ export declare function extractLyricsFromKar(filePath: string): string[];
@@ -0,0 +1,197 @@
1
+ "use strict";
2
+ /**
3
+ * KAR file reader utility
4
+ * Reads and validates .kar (MIDI karaoke) files
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.readKarFile = readKarFile;
41
+ exports.validateKarFile = validateKarFile;
42
+ exports.extractLyricsFromKar = extractLyricsFromKar;
43
+ const fs = __importStar(require("fs"));
44
+ const midi_file_1 = require("midi-file");
45
+ const iconv = __importStar(require("iconv-lite"));
46
+ /**
47
+ * Reads and parses a KAR file
48
+ */
49
+ function readKarFile(filePath) {
50
+ const buffer = fs.readFileSync(filePath);
51
+ const midi = (0, midi_file_1.parseMidi)(buffer);
52
+ const info = {
53
+ isValid: true,
54
+ header: {
55
+ format: midi.header.format,
56
+ numTracks: midi.header.numTracks,
57
+ ticksPerBeat: midi.header.ticksPerBeat
58
+ },
59
+ tracks: [],
60
+ metadata: {
61
+ hasKaraokeTrack: false,
62
+ hasLyricTrack: false
63
+ }
64
+ };
65
+ // Process each track
66
+ for (const track of midi.tracks || []) {
67
+ const trackInfo = {
68
+ events: track.length,
69
+ hasText: false,
70
+ hasLyrics: false,
71
+ textEvents: []
72
+ };
73
+ for (const event of track) {
74
+ // Handle different event types
75
+ if (event.type === 'trackName' && 'text' in event) {
76
+ trackInfo.name = event.text;
77
+ }
78
+ else if (event.type === 'text' && 'text' in event) {
79
+ trackInfo.hasText = true;
80
+ const text = event.text;
81
+ trackInfo.textEvents.push(text);
82
+ // Check for karaoke markers
83
+ if (text.startsWith('@T')) {
84
+ if (!info.metadata.title) {
85
+ info.metadata.title = text.substring(2);
86
+ }
87
+ else if (!info.metadata.artist) {
88
+ info.metadata.artist = text.substring(2);
89
+ }
90
+ }
91
+ }
92
+ else if (event.type === 'lyrics' && 'text' in event) {
93
+ trackInfo.hasLyrics = true;
94
+ trackInfo.textEvents.push(event.text);
95
+ }
96
+ else if (event.type === 'unknownMeta' && 'data' in event) {
97
+ // Handle TIS-620 encoded text events
98
+ const data = event.data;
99
+ if (data && data.length > 0) {
100
+ try {
101
+ const buffer = Buffer.from(data);
102
+ const text = iconv.decode(buffer, 'tis-620');
103
+ trackInfo.hasText = true;
104
+ trackInfo.textEvents.push(text);
105
+ if (text.startsWith('@T')) {
106
+ if (!info.metadata.title) {
107
+ info.metadata.title = text.substring(2);
108
+ }
109
+ else if (!info.metadata.artist) {
110
+ info.metadata.artist = text.substring(2);
111
+ }
112
+ }
113
+ }
114
+ catch (e) {
115
+ // Ignore decode errors
116
+ }
117
+ }
118
+ }
119
+ }
120
+ // Identify special tracks
121
+ if (trackInfo.name === 'Words') {
122
+ info.metadata.hasKaraokeTrack = true;
123
+ }
124
+ else if (trackInfo.name === 'Lyric') {
125
+ info.metadata.hasLyricTrack = true;
126
+ }
127
+ else if (trackInfo.name === 'SongTitle' && trackInfo.textEvents.length > 0) {
128
+ info.metadata.title = trackInfo.textEvents[0];
129
+ }
130
+ else if (trackInfo.name === 'Artist' && trackInfo.textEvents.length > 0) {
131
+ info.metadata.artist = trackInfo.textEvents[0];
132
+ }
133
+ info.tracks.push(trackInfo);
134
+ }
135
+ return info;
136
+ }
137
+ /**
138
+ * Validates that a KAR file has the expected structure
139
+ */
140
+ function validateKarFile(filePath) {
141
+ const errors = [];
142
+ const warnings = [];
143
+ try {
144
+ const info = readKarFile(filePath);
145
+ // Check basic structure
146
+ if (!info.header.ticksPerBeat) {
147
+ errors.push('Missing ticksPerBeat in header');
148
+ }
149
+ if (info.tracks.length === 0) {
150
+ errors.push('No tracks found in file');
151
+ }
152
+ // Check for karaoke tracks
153
+ if (!info.metadata.hasKaraokeTrack) {
154
+ warnings.push('No "Words" karaoke track found');
155
+ }
156
+ if (!info.metadata.hasLyricTrack) {
157
+ warnings.push('No "Lyric" track found');
158
+ }
159
+ if (!info.metadata.title) {
160
+ warnings.push('No title metadata found');
161
+ }
162
+ if (!info.metadata.artist) {
163
+ warnings.push('No artist metadata found');
164
+ }
165
+ return {
166
+ valid: errors.length === 0,
167
+ errors,
168
+ warnings
169
+ };
170
+ }
171
+ catch (error) {
172
+ errors.push(`Failed to read KAR file: ${error.message}`);
173
+ return {
174
+ valid: false,
175
+ errors,
176
+ warnings
177
+ };
178
+ }
179
+ }
180
+ /**
181
+ * Extracts lyrics from a KAR file
182
+ */
183
+ function extractLyricsFromKar(filePath) {
184
+ const info = readKarFile(filePath);
185
+ const lyrics = [];
186
+ for (const track of info.tracks) {
187
+ if (track.name === 'Words' || track.hasText) {
188
+ for (const text of track.textEvents) {
189
+ // Skip metadata markers
190
+ if (!text.startsWith('@')) {
191
+ lyrics.push(text);
192
+ }
193
+ }
194
+ }
195
+ }
196
+ return lyrics;
197
+ }
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Browser-compatible NCN to KAR converter
3
+ * Works with File API and ArrayBuffers instead of fs
4
+ */
5
+ export interface BrowserConversionOptions {
6
+ midiBuffer: Buffer;
7
+ lyricBuffer: Buffer;
8
+ cursorBuffer: Buffer;
9
+ outputFileName?: string;
10
+ }
11
+ export interface BrowserConversionResult {
12
+ success: boolean;
13
+ karBuffer: Buffer;
14
+ fileName: string;
15
+ metadata: {
16
+ title: string;
17
+ artist: string;
18
+ fullLyric: string;
19
+ lines: string[];
20
+ };
21
+ warnings: string[];
22
+ }
23
+ /**
24
+ * Reads text from buffer as TIS-620 (Thai encoding)
25
+ */
26
+ export declare function readBufferTextTIS620(buffer: Buffer): string;
27
+ /**
28
+ * Splits text into lines while keeping line endings
29
+ */
30
+ export declare function splitLinesKeepEndings(text: string): string[];
31
+ /**
32
+ * Removes line endings from a string
33
+ */
34
+ export declare function trimLineEndings(s: string): string;
35
+ /**
36
+ * Creates a MIDI meta event with TIS-620 encoding for Thai text
37
+ */
38
+ export declare function createMetaEvent(subtype: string, deltaTime: number, text: string): any;
39
+ /**
40
+ * Creates an end-of-track MIDI event
41
+ */
42
+ export declare function createEndOfTrack(deltaTime?: number): any;
43
+ /**
44
+ * Simple cursor reader for browser
45
+ */
46
+ export declare class BrowserCursorReader {
47
+ private buf;
48
+ private off;
49
+ constructor(buf: Buffer);
50
+ readU16LE(): number | null;
51
+ readU8(): number | null;
52
+ remaining(): number;
53
+ }
54
+ /**
55
+ * Parses lyric buffer to extract metadata (title, artist, lyrics)
56
+ */
57
+ export declare function parseLyricBuffer(lyricBuffer: Buffer): {
58
+ title: string;
59
+ artist: string;
60
+ fullLyric: string;
61
+ lines: string[];
62
+ };
63
+ /**
64
+ * Builds karaoke track with timing information (browser version)
65
+ */
66
+ export declare function buildKaraokeTrackBrowser(metadata: {
67
+ title: string;
68
+ artist: string;
69
+ fullLyric: string;
70
+ lines: string[];
71
+ }, cursorBuffer: Buffer, ticksPerBeat: number): {
72
+ track: any[];
73
+ warnings: string[];
74
+ };
75
+ /**
76
+ * Builds additional metadata tracks (Lyric, Artist, SongTitle)
77
+ */
78
+ export declare function buildMetadataTracksBrowser(metadata: {
79
+ title: string;
80
+ artist: string;
81
+ fullLyric: string;
82
+ }): {
83
+ lyricTrack: any[];
84
+ artistTrack: any[];
85
+ titleTrack: any[];
86
+ };
87
+ /**
88
+ * Browser-compatible NCN to KAR conversion
89
+ * Works with buffers instead of file paths
90
+ */
91
+ export declare function convertNcnToKarBrowser(options: BrowserConversionOptions): BrowserConversionResult;
92
+ /**
93
+ * Helper to convert File to Buffer for browser use
94
+ */
95
+ export declare function fileToBuffer(file: File): Promise<Buffer>;
96
+ /**
97
+ * Helper to download buffer as file in browser
98
+ */
99
+ export declare function downloadBuffer(buffer: Buffer, fileName: string, mimeType?: string): void;