taglib-wasm 0.2.7 → 0.3.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/README.md +155 -149
- package/build/taglib.js +4 -10
- package/build/taglib.wasm +0 -0
- package/index.ts +17 -3
- package/package.json +9 -9
- package/src/mod.ts +14 -3
- package/src/simple.ts +21 -25
- package/src/taglib.ts +179 -496
- package/src/types.ts +6 -3
- package/src/wasm-workers.ts +9 -1
- package/src/wasm.ts +105 -244
- package/src/workers.ts +50 -29
- package/src/enhanced-api.ts +0 -296
- package/src/simple-jsr.ts +0 -201
- package/src/taglib-embind.ts +0 -231
- package/src/taglib-jsr.ts +0 -544
- package/src/wasm-embind.ts +0 -55
- package/src/wasm-jsr.ts +0 -280
package/src/taglib-jsr.ts
DELETED
|
@@ -1,544 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview JSR-compatible TagLib implementation
|
|
3
|
-
*
|
|
4
|
-
* This version uses direct WASM loading without Emscripten's JS file
|
|
5
|
-
* to be compatible with JSR publishing requirements.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type {
|
|
9
|
-
AudioFormat,
|
|
10
|
-
AudioProperties,
|
|
11
|
-
BitrateControlMode,
|
|
12
|
-
ExtendedTag,
|
|
13
|
-
Picture,
|
|
14
|
-
PropertyMap,
|
|
15
|
-
Tag,
|
|
16
|
-
TagLibConfig,
|
|
17
|
-
} from "./types.ts";
|
|
18
|
-
import {
|
|
19
|
-
cStringToJSJSR,
|
|
20
|
-
jsToCStringJSR,
|
|
21
|
-
loadTagLibModuleJSR,
|
|
22
|
-
type TagLibModule,
|
|
23
|
-
} from "./wasm-jsr.ts";
|
|
24
|
-
import {
|
|
25
|
-
BITRATE_CONTROL_MODE_NAMES,
|
|
26
|
-
BITRATE_CONTROL_MODE_VALUES,
|
|
27
|
-
METADATA_MAPPINGS
|
|
28
|
-
} from "./types.ts";
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* JSR-compatible TagLib singleton for WASM module management
|
|
32
|
-
*/
|
|
33
|
-
export class TagLibJSR {
|
|
34
|
-
private static instance: TagLibJSR | null = null;
|
|
35
|
-
private module: TagLibModule | null = null;
|
|
36
|
-
private initialized = false;
|
|
37
|
-
|
|
38
|
-
private constructor() {}
|
|
39
|
-
|
|
40
|
-
static getInstance(): TagLibJSR {
|
|
41
|
-
if (!TagLibJSR.instance) {
|
|
42
|
-
TagLibJSR.instance = new TagLibJSR();
|
|
43
|
-
}
|
|
44
|
-
return TagLibJSR.instance;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
async initialize(config?: TagLibConfig): Promise<void> {
|
|
48
|
-
if (this.initialized) return;
|
|
49
|
-
|
|
50
|
-
this.module = await loadTagLibModuleJSR(config);
|
|
51
|
-
this.initialized = true;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
getModule(): TagLibModule {
|
|
55
|
-
if (!this.module) {
|
|
56
|
-
throw new Error(
|
|
57
|
-
"TagLib not initialized. Call TagLib.initialize() first.",
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
return this.module;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
isInitialized(): boolean {
|
|
64
|
-
return this.initialized;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Initialize taglib-wasm module
|
|
69
|
-
*/
|
|
70
|
-
static async initialize(config?: TagLibConfig): Promise<void> {
|
|
71
|
-
const instance = TagLibJSR.getInstance();
|
|
72
|
-
await instance.initialize(config);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Get the WASM module instance
|
|
77
|
-
*/
|
|
78
|
-
static getModule(): TagLibModule {
|
|
79
|
-
return TagLibJSR.getInstance().getModule();
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Check if TagLib is initialized
|
|
84
|
-
*/
|
|
85
|
-
static isInitialized(): boolean {
|
|
86
|
-
return TagLibJSR.getInstance().isInitialized();
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* JSR-compatible audio file handling class
|
|
92
|
-
*/
|
|
93
|
-
export class AudioFileJSR {
|
|
94
|
-
private fileId: number = 0;
|
|
95
|
-
private module: TagLibModule;
|
|
96
|
-
private dataPtr: number = 0;
|
|
97
|
-
|
|
98
|
-
constructor(data: Uint8Array) {
|
|
99
|
-
this.module = TagLibJSR.getModule();
|
|
100
|
-
|
|
101
|
-
// Allocate memory for file data
|
|
102
|
-
this.dataPtr = this.module.allocate(data, this.module.ALLOC_NORMAL);
|
|
103
|
-
|
|
104
|
-
// Create TagLib file from buffer
|
|
105
|
-
this.fileId = this.module._taglib_file_new_from_buffer(
|
|
106
|
-
this.dataPtr,
|
|
107
|
-
data.length,
|
|
108
|
-
);
|
|
109
|
-
|
|
110
|
-
if (!this.isValid()) {
|
|
111
|
-
this.cleanup();
|
|
112
|
-
throw new Error(
|
|
113
|
-
"Failed to load audio file - invalid format or corrupted data",
|
|
114
|
-
);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Check if the file is valid
|
|
120
|
-
*/
|
|
121
|
-
isValid(): boolean {
|
|
122
|
-
return this.module._taglib_file_is_valid(this.fileId) === 1;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Get the audio format
|
|
127
|
-
*/
|
|
128
|
-
getFormat(): AudioFormat {
|
|
129
|
-
const formatId = this.module._taglib_file_format(this.fileId);
|
|
130
|
-
const formats: Record<number, AudioFormat> = {
|
|
131
|
-
1: "MP3",
|
|
132
|
-
2: "FLAC",
|
|
133
|
-
3: "OGG",
|
|
134
|
-
4: "MP4",
|
|
135
|
-
5: "WMA",
|
|
136
|
-
6: "APE",
|
|
137
|
-
7: "MPC",
|
|
138
|
-
8: "WV",
|
|
139
|
-
9: "OPUS",
|
|
140
|
-
10: "TTA",
|
|
141
|
-
11: "WAV",
|
|
142
|
-
12: "AIFF",
|
|
143
|
-
13: "MOD",
|
|
144
|
-
14: "S3M",
|
|
145
|
-
15: "XM",
|
|
146
|
-
16: "IT",
|
|
147
|
-
};
|
|
148
|
-
return formats[formatId] || "MP3";
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Get basic tag information
|
|
153
|
-
*/
|
|
154
|
-
getTag(): Tag {
|
|
155
|
-
const tagPtr = this.module._taglib_file_tag(this.fileId);
|
|
156
|
-
if (tagPtr === 0) {
|
|
157
|
-
return {
|
|
158
|
-
title: "",
|
|
159
|
-
artist: "",
|
|
160
|
-
album: "",
|
|
161
|
-
comment: "",
|
|
162
|
-
genre: "",
|
|
163
|
-
year: 0,
|
|
164
|
-
track: 0,
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
return {
|
|
169
|
-
title: cStringToJSJSR(this.module, this.module._taglib_tag_title(tagPtr)),
|
|
170
|
-
artist: cStringToJSJSR(
|
|
171
|
-
this.module,
|
|
172
|
-
this.module._taglib_tag_artist(tagPtr),
|
|
173
|
-
),
|
|
174
|
-
album: cStringToJSJSR(this.module, this.module._taglib_tag_album(tagPtr)),
|
|
175
|
-
comment: cStringToJSJSR(
|
|
176
|
-
this.module,
|
|
177
|
-
this.module._taglib_tag_comment(tagPtr),
|
|
178
|
-
),
|
|
179
|
-
genre: cStringToJSJSR(this.module, this.module._taglib_tag_genre(tagPtr)),
|
|
180
|
-
year: this.module._taglib_tag_year(tagPtr),
|
|
181
|
-
track: this.module._taglib_tag_track(tagPtr),
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Set basic tag information
|
|
187
|
-
*/
|
|
188
|
-
setTag(tag: Partial<Tag>): void {
|
|
189
|
-
const tagPtr = this.module._taglib_file_tag(this.fileId);
|
|
190
|
-
if (tagPtr === 0) return;
|
|
191
|
-
|
|
192
|
-
if (tag.title !== undefined) {
|
|
193
|
-
const titlePtr = jsToCStringJSR(this.module, tag.title);
|
|
194
|
-
this.module._taglib_tag_set_title(tagPtr, titlePtr);
|
|
195
|
-
this.module._free(titlePtr);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
if (tag.artist !== undefined) {
|
|
199
|
-
const artistPtr = jsToCStringJSR(this.module, tag.artist);
|
|
200
|
-
this.module._taglib_tag_set_artist(tagPtr, artistPtr);
|
|
201
|
-
this.module._free(artistPtr);
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
if (tag.album !== undefined) {
|
|
205
|
-
const albumPtr = jsToCStringJSR(this.module, tag.album);
|
|
206
|
-
this.module._taglib_tag_set_album(tagPtr, albumPtr);
|
|
207
|
-
this.module._free(albumPtr);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
if (tag.comment !== undefined) {
|
|
211
|
-
const commentPtr = jsToCStringJSR(this.module, tag.comment);
|
|
212
|
-
this.module._taglib_tag_set_comment(tagPtr, commentPtr);
|
|
213
|
-
this.module._free(commentPtr);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
if (tag.genre !== undefined) {
|
|
217
|
-
const genrePtr = jsToCStringJSR(this.module, tag.genre);
|
|
218
|
-
this.module._taglib_tag_set_genre(tagPtr, genrePtr);
|
|
219
|
-
this.module._free(genrePtr);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
if (tag.year !== undefined) {
|
|
223
|
-
this.module._taglib_tag_set_year(tagPtr, tag.year);
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
if (tag.track !== undefined) {
|
|
227
|
-
this.module._taglib_tag_set_track(tagPtr, tag.track);
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
/**
|
|
232
|
-
* Get audio properties
|
|
233
|
-
*/
|
|
234
|
-
getAudioProperties(): AudioProperties {
|
|
235
|
-
const propsPtr = this.module._taglib_file_audioproperties(this.fileId);
|
|
236
|
-
if (propsPtr === 0) {
|
|
237
|
-
return {
|
|
238
|
-
length: 0,
|
|
239
|
-
bitrate: 0,
|
|
240
|
-
sampleRate: 0,
|
|
241
|
-
channels: 0,
|
|
242
|
-
format: this.getFormat(),
|
|
243
|
-
};
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
return {
|
|
247
|
-
length: this.module._taglib_audioproperties_length(propsPtr),
|
|
248
|
-
bitrate: this.module._taglib_audioproperties_bitrate(propsPtr),
|
|
249
|
-
sampleRate: this.module._taglib_audioproperties_samplerate(propsPtr),
|
|
250
|
-
channels: this.module._taglib_audioproperties_channels(propsPtr),
|
|
251
|
-
format: this.getFormat(),
|
|
252
|
-
};
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
/**
|
|
256
|
-
* Get extended tag information (placeholder for JSR version)
|
|
257
|
-
*/
|
|
258
|
-
getExtendedTag(): ExtendedTag {
|
|
259
|
-
// For JSR compatibility, return basic implementation
|
|
260
|
-
const basicTag = this.getTag();
|
|
261
|
-
return {
|
|
262
|
-
...basicTag,
|
|
263
|
-
|
|
264
|
-
// Fingerprinting & identification - placeholder
|
|
265
|
-
acoustidFingerprint: "",
|
|
266
|
-
acoustidId: "",
|
|
267
|
-
musicbrainzTrackId: "",
|
|
268
|
-
musicbrainzReleaseId: "",
|
|
269
|
-
musicbrainzArtistId: "",
|
|
270
|
-
musicbrainzReleaseGroupId: "",
|
|
271
|
-
albumArtist: "",
|
|
272
|
-
composer: "",
|
|
273
|
-
discNumber: 0,
|
|
274
|
-
totalTracks: 0,
|
|
275
|
-
totalDiscs: 0,
|
|
276
|
-
bpm: 0,
|
|
277
|
-
compilation: false,
|
|
278
|
-
titleSort: "",
|
|
279
|
-
artistSort: "",
|
|
280
|
-
albumSort: "",
|
|
281
|
-
|
|
282
|
-
// Volume normalization - placeholder
|
|
283
|
-
replayGainTrackGain: "",
|
|
284
|
-
replayGainTrackPeak: "",
|
|
285
|
-
replayGainAlbumGain: "",
|
|
286
|
-
replayGainAlbumPeak: "",
|
|
287
|
-
appleSoundCheck: "",
|
|
288
|
-
};
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
/**
|
|
292
|
-
* Set extended tag fields (placeholder for JSR version)
|
|
293
|
-
*/
|
|
294
|
-
setExtendedTag(extendedTag: Partial<ExtendedTag>): void {
|
|
295
|
-
// Set basic fields
|
|
296
|
-
this.setTag(extendedTag);
|
|
297
|
-
|
|
298
|
-
// Extended fields are placeholder for JSR version
|
|
299
|
-
// Full implementation would require PropertyMap integration
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
/**
|
|
303
|
-
* Get pictures from the file (placeholder for JSR version)
|
|
304
|
-
*/
|
|
305
|
-
getPictures(): Picture[] {
|
|
306
|
-
// Placeholder - full implementation would require format-specific picture extraction
|
|
307
|
-
return [];
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
/**
|
|
311
|
-
* Set pictures in the file (placeholder for JSR version)
|
|
312
|
-
*/
|
|
313
|
-
setPictures(pictures: Picture[]): void {
|
|
314
|
-
// Placeholder - full implementation would require format-specific picture handling
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
// Placeholder methods for extended metadata (same as main implementation)
|
|
318
|
-
getAcoustidFingerprint(): string {
|
|
319
|
-
return "";
|
|
320
|
-
}
|
|
321
|
-
setAcoustidFingerprint(fingerprint: string): void {}
|
|
322
|
-
getMusicbrainzTrackId(): string {
|
|
323
|
-
return "";
|
|
324
|
-
}
|
|
325
|
-
setMusicbrainzTrackId(id: string): void {}
|
|
326
|
-
getMusicbrainzRecordingId(): string {
|
|
327
|
-
return "";
|
|
328
|
-
}
|
|
329
|
-
setMusicbrainzRecordingId(id: string): void {}
|
|
330
|
-
getMusicbrainzArtistId(): string {
|
|
331
|
-
return "";
|
|
332
|
-
}
|
|
333
|
-
setMusicbrainzArtistId(id: string): void {}
|
|
334
|
-
getMusicbrainzAlbumId(): string {
|
|
335
|
-
return "";
|
|
336
|
-
}
|
|
337
|
-
setMusicbrainzAlbumId(id: string): void {}
|
|
338
|
-
getMusicbrainzAlbumArtistId(): string {
|
|
339
|
-
return "";
|
|
340
|
-
}
|
|
341
|
-
setMusicbrainzAlbumArtistId(id: string): void {}
|
|
342
|
-
getMusicbrainzReleaseGroupId(): string {
|
|
343
|
-
return "";
|
|
344
|
-
}
|
|
345
|
-
setMusicbrainzReleaseGroupId(id: string): void {}
|
|
346
|
-
getReplayGainTrackGain(): string {
|
|
347
|
-
return "";
|
|
348
|
-
}
|
|
349
|
-
setReplayGainTrackGain(gain: string): void {}
|
|
350
|
-
getReplayGainTrackPeak(): string {
|
|
351
|
-
return "";
|
|
352
|
-
}
|
|
353
|
-
setReplayGainTrackPeak(peak: string): void {}
|
|
354
|
-
getReplayGainAlbumGain(): string {
|
|
355
|
-
return "";
|
|
356
|
-
}
|
|
357
|
-
setReplayGainAlbumGain(gain: string): void {}
|
|
358
|
-
getReplayGainAlbumPeak(): string {
|
|
359
|
-
return "";
|
|
360
|
-
}
|
|
361
|
-
setReplayGainAlbumPeak(peak: string): void {}
|
|
362
|
-
getAppleSoundCheck(): string {
|
|
363
|
-
return "";
|
|
364
|
-
}
|
|
365
|
-
setAppleSoundCheck(soundCheck: string): void {}
|
|
366
|
-
|
|
367
|
-
/**
|
|
368
|
-
* Get all properties as a PropertyMap
|
|
369
|
-
*/
|
|
370
|
-
properties(): PropertyMap {
|
|
371
|
-
const jsonPtr = this.module._taglib_file_properties_json(this.fileId);
|
|
372
|
-
if (jsonPtr === 0) return {};
|
|
373
|
-
|
|
374
|
-
const jsonStr = cStringToJSJSR(this.module, jsonPtr);
|
|
375
|
-
try {
|
|
376
|
-
return JSON.parse(jsonStr);
|
|
377
|
-
} catch {
|
|
378
|
-
return {};
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
/**
|
|
383
|
-
* Set properties from a PropertyMap
|
|
384
|
-
*/
|
|
385
|
-
setProperties(properties: PropertyMap): boolean {
|
|
386
|
-
const jsonStr = JSON.stringify(properties);
|
|
387
|
-
const jsonPtr = jsToCStringJSR(this.module, jsonStr);
|
|
388
|
-
try {
|
|
389
|
-
return this.module._taglib_file_set_properties_json(this.fileId, jsonPtr) !== 0;
|
|
390
|
-
} finally {
|
|
391
|
-
this.module._free(jsonPtr);
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
/**
|
|
396
|
-
* Get a specific property value
|
|
397
|
-
*/
|
|
398
|
-
getProperty(key: string): string[] | undefined {
|
|
399
|
-
const keyPtr = jsToCStringJSR(this.module, key);
|
|
400
|
-
try {
|
|
401
|
-
const valuePtr = this.module._taglib_file_get_property(this.fileId, keyPtr);
|
|
402
|
-
if (valuePtr === 0) return undefined;
|
|
403
|
-
|
|
404
|
-
const value = cStringToJSJSR(this.module, valuePtr);
|
|
405
|
-
return value ? [value] : undefined;
|
|
406
|
-
} finally {
|
|
407
|
-
this.module._free(keyPtr);
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
/**
|
|
412
|
-
* Set a specific property value
|
|
413
|
-
*/
|
|
414
|
-
setProperty(key: string, values: string | string[]): boolean {
|
|
415
|
-
const value = Array.isArray(values) ? values[0] : values;
|
|
416
|
-
if (!value) return false;
|
|
417
|
-
|
|
418
|
-
const keyPtr = jsToCStringJSR(this.module, key);
|
|
419
|
-
const valuePtr = jsToCStringJSR(this.module, value);
|
|
420
|
-
try {
|
|
421
|
-
return this.module._taglib_file_set_property(this.fileId, keyPtr, valuePtr) !== 0;
|
|
422
|
-
} finally {
|
|
423
|
-
this.module._free(keyPtr);
|
|
424
|
-
this.module._free(valuePtr);
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
/**
|
|
429
|
-
* Check if this is an MP4 file
|
|
430
|
-
*/
|
|
431
|
-
isMP4(): boolean {
|
|
432
|
-
return this.module._taglib_file_is_mp4(this.fileId) !== 0;
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
/**
|
|
436
|
-
* Get MP4-specific item (for custom atoms)
|
|
437
|
-
*/
|
|
438
|
-
getMP4Item(key: string): string | undefined {
|
|
439
|
-
if (!this.isMP4()) return undefined;
|
|
440
|
-
|
|
441
|
-
const keyPtr = jsToCStringJSR(this.module, key);
|
|
442
|
-
try {
|
|
443
|
-
const valuePtr = this.module._taglib_mp4_get_item(this.fileId, keyPtr);
|
|
444
|
-
if (valuePtr === 0) return undefined;
|
|
445
|
-
|
|
446
|
-
return cStringToJSJSR(this.module, valuePtr);
|
|
447
|
-
} finally {
|
|
448
|
-
this.module._free(keyPtr);
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
/**
|
|
453
|
-
* Set MP4-specific item (for custom atoms)
|
|
454
|
-
*/
|
|
455
|
-
setMP4Item(key: string, value: string): boolean {
|
|
456
|
-
if (!this.isMP4()) return false;
|
|
457
|
-
|
|
458
|
-
const keyPtr = jsToCStringJSR(this.module, key);
|
|
459
|
-
const valuePtr = jsToCStringJSR(this.module, value);
|
|
460
|
-
try {
|
|
461
|
-
return this.module._taglib_mp4_set_item(this.fileId, keyPtr, valuePtr) !== 0;
|
|
462
|
-
} finally {
|
|
463
|
-
this.module._free(keyPtr);
|
|
464
|
-
this.module._free(valuePtr);
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
/**
|
|
469
|
-
* Remove MP4-specific item
|
|
470
|
-
*/
|
|
471
|
-
removeMP4Item(key: string): boolean {
|
|
472
|
-
if (!this.isMP4()) return false;
|
|
473
|
-
|
|
474
|
-
const keyPtr = jsToCStringJSR(this.module, key);
|
|
475
|
-
try {
|
|
476
|
-
return this.module._taglib_mp4_remove_item(this.fileId, keyPtr) !== 0;
|
|
477
|
-
} finally {
|
|
478
|
-
this.module._free(keyPtr);
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
/**
|
|
483
|
-
* Get bitrate control mode (MP4/M4A specific)
|
|
484
|
-
* Reads from the 'acbf' atom
|
|
485
|
-
*/
|
|
486
|
-
getBitrateControlMode(): BitrateControlMode | undefined {
|
|
487
|
-
if (!this.isMP4()) return undefined;
|
|
488
|
-
|
|
489
|
-
const value = this.getMP4Item("acbf");
|
|
490
|
-
if (!value) return undefined;
|
|
491
|
-
|
|
492
|
-
const numValue = parseInt(value, 10);
|
|
493
|
-
if (isNaN(numValue) || numValue < 0 || numValue > 3) return undefined;
|
|
494
|
-
|
|
495
|
-
return BITRATE_CONTROL_MODE_NAMES[numValue];
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
/**
|
|
499
|
-
* Set bitrate control mode (MP4/M4A specific)
|
|
500
|
-
* Writes to the 'acbf' atom
|
|
501
|
-
*/
|
|
502
|
-
setBitrateControlMode(mode: BitrateControlMode): boolean {
|
|
503
|
-
if (!this.isMP4()) return false;
|
|
504
|
-
|
|
505
|
-
const numValue = BITRATE_CONTROL_MODE_VALUES[mode];
|
|
506
|
-
if (numValue === undefined) return false;
|
|
507
|
-
|
|
508
|
-
return this.setMP4Item("acbf", numValue.toString());
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
/**
|
|
512
|
-
* Save changes to the file
|
|
513
|
-
*/
|
|
514
|
-
save(): Uint8Array {
|
|
515
|
-
if (!this.module._taglib_file_save(this.fileId)) {
|
|
516
|
-
throw new Error("Failed to save audio file");
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
// In a real implementation, we'd need to extract the modified file data
|
|
520
|
-
// For now, return empty array as placeholder
|
|
521
|
-
return new Uint8Array(0);
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
/**
|
|
525
|
-
* Clean up resources
|
|
526
|
-
*/
|
|
527
|
-
cleanup(): void {
|
|
528
|
-
if (this.fileId) {
|
|
529
|
-
this.module._taglib_file_delete(this.fileId);
|
|
530
|
-
this.fileId = 0;
|
|
531
|
-
}
|
|
532
|
-
if (this.dataPtr) {
|
|
533
|
-
this.module._free(this.dataPtr);
|
|
534
|
-
this.dataPtr = 0;
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
/**
|
|
539
|
-
* Destructor to ensure cleanup
|
|
540
|
-
*/
|
|
541
|
-
destroy(): void {
|
|
542
|
-
this.cleanup();
|
|
543
|
-
}
|
|
544
|
-
}
|
package/src/wasm-embind.ts
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* WebAssembly module interface for Embind version
|
|
3
|
-
*/
|
|
4
|
-
export interface WasmModule {
|
|
5
|
-
// Memory access
|
|
6
|
-
HEAP8: Int8Array;
|
|
7
|
-
HEAP16: Int16Array;
|
|
8
|
-
HEAP32: Int32Array;
|
|
9
|
-
HEAPU8: Uint8Array;
|
|
10
|
-
HEAPU16: Uint16Array;
|
|
11
|
-
HEAPU32: Uint32Array;
|
|
12
|
-
HEAPF32: Float32Array;
|
|
13
|
-
HEAPF64: Float64Array;
|
|
14
|
-
|
|
15
|
-
// Runtime methods
|
|
16
|
-
allocate: (size: number, type: number) => number;
|
|
17
|
-
_malloc: (size: number) => number;
|
|
18
|
-
_free: (ptr: number) => void;
|
|
19
|
-
getValue: (ptr: number, type: string) => number;
|
|
20
|
-
setValue: (ptr: number, value: number, type: string) => void;
|
|
21
|
-
UTF8ToString: (ptr: number) => string;
|
|
22
|
-
stringToUTF8: (str: string, outPtr: number, maxBytesToWrite: number) => void;
|
|
23
|
-
lengthBytesUTF8: (str: string) => number;
|
|
24
|
-
|
|
25
|
-
// Allocation types
|
|
26
|
-
ALLOC_NORMAL: number;
|
|
27
|
-
ALLOC_STACK: number;
|
|
28
|
-
|
|
29
|
-
// Embind classes (these will be available after module loads)
|
|
30
|
-
FileHandle: any;
|
|
31
|
-
TagWrapper: any;
|
|
32
|
-
AudioPropertiesWrapper: any;
|
|
33
|
-
createFileHandle: () => any;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Extended module interface with our Embind classes
|
|
38
|
-
*/
|
|
39
|
-
export interface TagLibModule extends WasmModule {
|
|
40
|
-
// These are the actual class constructors from Embind
|
|
41
|
-
FileHandle: {
|
|
42
|
-
new(): any;
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
TagWrapper: {
|
|
46
|
-
new(tagPtr: number): any;
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
AudioPropertiesWrapper: {
|
|
50
|
-
new(propsPtr: number): any;
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
// Factory function
|
|
54
|
-
createFileHandle: () => any;
|
|
55
|
-
}
|