@juandinella/audio-bands 0.4.7 → 0.6.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 +96 -16
- package/dist/{chunk-33JHLQZJ.js → chunk-EGVVFGLZ.js} +144 -20
- package/dist/chunk-EGVVFGLZ.js.map +1 -0
- package/dist/core-entry.cjs +143 -19
- package/dist/core-entry.cjs.map +1 -1
- package/dist/core-entry.d.cts +17 -4
- package/dist/core-entry.d.ts +17 -4
- package/dist/core-entry.js +1 -1
- package/dist/index.cjs +143 -19
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/react-entry.cjs +271 -62
- package/dist/react-entry.cjs.map +1 -1
- package/dist/react-entry.d.cts +12 -4
- package/dist/react-entry.d.ts +12 -4
- package/dist/react-entry.js +129 -44
- package/dist/react-entry.js.map +1 -1
- package/dist/{types-CiYwsfgy.d.cts → types-0KQJLMV2.d.cts} +10 -2
- package/dist/{types-CiYwsfgy.d.ts → types-0KQJLMV2.d.ts} +10 -2
- package/package.json +15 -2
- package/dist/chunk-33JHLQZJ.js.map +0 -1
package/dist/react-entry.cjs
CHANGED
|
@@ -144,6 +144,7 @@ var AudioBands = class {
|
|
|
144
144
|
micActive: false,
|
|
145
145
|
hasTrack: false,
|
|
146
146
|
loadError: null,
|
|
147
|
+
playbackError: null,
|
|
147
148
|
micError: null
|
|
148
149
|
};
|
|
149
150
|
this.ctx = null;
|
|
@@ -157,6 +158,10 @@ var AudioBands = class {
|
|
|
157
158
|
this.musicSource = null;
|
|
158
159
|
this.micSource = null;
|
|
159
160
|
this.micStream = null;
|
|
161
|
+
this.musicEventCleanup = null;
|
|
162
|
+
this.pendingLoadCleanup = null;
|
|
163
|
+
this.pendingLoadReject = null;
|
|
164
|
+
this.trackLoop = false;
|
|
160
165
|
this.destroyed = false;
|
|
161
166
|
this.options = options;
|
|
162
167
|
this.musicConfig = normalizeAnalyserConfig(options.music, DEFAULT_MUSIC_ANALYSER);
|
|
@@ -177,41 +182,96 @@ var AudioBands = class {
|
|
|
177
182
|
try {
|
|
178
183
|
ctx = this.ensureCtx();
|
|
179
184
|
} catch (error) {
|
|
180
|
-
throw this.handleError("load", error);
|
|
185
|
+
throw this.handleError("load", error, "load_error");
|
|
181
186
|
}
|
|
182
187
|
this.teardownMusic();
|
|
183
188
|
const audio = new Audio();
|
|
184
189
|
audio.crossOrigin = "anonymous";
|
|
190
|
+
audio.preload = "auto";
|
|
185
191
|
audio.src = url;
|
|
186
|
-
audio.loop =
|
|
192
|
+
audio.loop = this.trackLoop;
|
|
193
|
+
this.bindMusicElementEvents(audio);
|
|
187
194
|
this.audioEl = audio;
|
|
188
|
-
this.setState({ hasTrack:
|
|
195
|
+
this.setState({ hasTrack: false, loadError: null, playbackError: null });
|
|
189
196
|
const source = ctx.createMediaElementSource(audio);
|
|
190
197
|
source.connect(this.musicAnalyser);
|
|
191
198
|
this.musicSource = source;
|
|
199
|
+
await new Promise((resolve, reject) => {
|
|
200
|
+
const finalize = () => {
|
|
201
|
+
cleanup();
|
|
202
|
+
this.pendingLoadCleanup = null;
|
|
203
|
+
this.pendingLoadReject = null;
|
|
204
|
+
};
|
|
205
|
+
const handleReady = () => {
|
|
206
|
+
finalize();
|
|
207
|
+
this.setState({ hasTrack: true, loadError: null });
|
|
208
|
+
resolve();
|
|
209
|
+
};
|
|
210
|
+
const handleFailure = (event) => {
|
|
211
|
+
finalize();
|
|
212
|
+
const mediaError = event?.target?.error ?? audio.error ?? event;
|
|
213
|
+
reject(this.handleLoadFailure(mediaError));
|
|
214
|
+
};
|
|
215
|
+
const cleanup = () => {
|
|
216
|
+
audio.removeEventListener("loadedmetadata", handleReady);
|
|
217
|
+
audio.removeEventListener("canplay", handleReady);
|
|
218
|
+
audio.removeEventListener("error", handleFailure);
|
|
219
|
+
};
|
|
220
|
+
this.pendingLoadCleanup = cleanup;
|
|
221
|
+
this.pendingLoadReject = reject;
|
|
222
|
+
audio.addEventListener("loadedmetadata", handleReady, { once: true });
|
|
223
|
+
audio.addEventListener("canplay", handleReady, { once: true });
|
|
224
|
+
audio.addEventListener("error", handleFailure, { once: true });
|
|
225
|
+
audio.load();
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
async play() {
|
|
229
|
+
const audio = this.audioEl;
|
|
230
|
+
if (!audio) return;
|
|
192
231
|
try {
|
|
193
232
|
await audio.play();
|
|
194
|
-
this.setState({
|
|
195
|
-
this.options.onPlay?.();
|
|
233
|
+
this.setState({ playbackError: null });
|
|
196
234
|
} catch (error) {
|
|
197
|
-
throw this.handleError("
|
|
235
|
+
throw this.handleError("playback", error, "playback_error");
|
|
198
236
|
}
|
|
199
237
|
}
|
|
200
|
-
|
|
238
|
+
pause() {
|
|
239
|
+
const audio = this.audioEl;
|
|
240
|
+
if (!audio || audio.paused) return;
|
|
241
|
+
audio.pause();
|
|
242
|
+
}
|
|
243
|
+
async togglePlayPause() {
|
|
201
244
|
const audio = this.audioEl;
|
|
202
245
|
if (!audio) return;
|
|
203
246
|
if (audio.paused) {
|
|
204
|
-
|
|
205
|
-
this.setState({ isPlaying: true, loadError: null });
|
|
206
|
-
this.options.onPlay?.();
|
|
207
|
-
}).catch((error) => {
|
|
208
|
-
this.handleError("load", error, "playback_error");
|
|
209
|
-
});
|
|
247
|
+
await this.play();
|
|
210
248
|
return;
|
|
211
249
|
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
250
|
+
this.pause();
|
|
251
|
+
}
|
|
252
|
+
setLoop(loop) {
|
|
253
|
+
this.trackLoop = loop;
|
|
254
|
+
if (this.audioEl) this.audioEl.loop = loop;
|
|
255
|
+
}
|
|
256
|
+
seek(seconds) {
|
|
257
|
+
if (!Number.isFinite(seconds) || seconds < 0) {
|
|
258
|
+
throw new AudioBandsError(
|
|
259
|
+
"config",
|
|
260
|
+
"invalid_config",
|
|
261
|
+
"seek time must be a finite number greater than or equal to 0"
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
if (!this.audioEl) return;
|
|
265
|
+
const duration = Number.isFinite(this.audioEl.duration) ? this.audioEl.duration : null;
|
|
266
|
+
this.audioEl.currentTime = duration === null ? seconds : Math.min(seconds, duration);
|
|
267
|
+
}
|
|
268
|
+
getDuration() {
|
|
269
|
+
if (!this.audioEl) return null;
|
|
270
|
+
return Number.isFinite(this.audioEl.duration) ? this.audioEl.duration : null;
|
|
271
|
+
}
|
|
272
|
+
getCurrentTime() {
|
|
273
|
+
if (!this.audioEl) return null;
|
|
274
|
+
return Number.isFinite(this.audioEl.currentTime) ? this.audioEl.currentTime : null;
|
|
215
275
|
}
|
|
216
276
|
async enableMic() {
|
|
217
277
|
let ctx;
|
|
@@ -270,6 +330,16 @@ var AudioBands = class {
|
|
|
270
330
|
getWaveform(source = "music") {
|
|
271
331
|
return this.readWaveformData(source);
|
|
272
332
|
}
|
|
333
|
+
snapshot(source = "music") {
|
|
334
|
+
const fft = this.readFrequencyData(source);
|
|
335
|
+
const waveform = this.readWaveformData(source);
|
|
336
|
+
return {
|
|
337
|
+
bands: fft ? computeBands(fft, this.classicRanges) : { ...ZERO },
|
|
338
|
+
customBands: fft ? computeCustomBands(fft, this.customBandRanges) : computeCustomBands(new Uint8Array(1), this.customBandRanges),
|
|
339
|
+
fft,
|
|
340
|
+
waveform
|
|
341
|
+
};
|
|
342
|
+
}
|
|
273
343
|
destroy() {
|
|
274
344
|
if (this.destroyed) return;
|
|
275
345
|
this.teardownMusic();
|
|
@@ -337,16 +407,19 @@ var AudioBands = class {
|
|
|
337
407
|
analyser.smoothingTimeConstant = config.smoothingTimeConstant;
|
|
338
408
|
return analyser;
|
|
339
409
|
}
|
|
340
|
-
handleError(kind, error, fallbackCode = kind === "mic" ? "mic_error" : "load_error") {
|
|
410
|
+
handleError(kind, error, fallbackCode = kind === "mic" ? "mic_error" : kind === "playback" ? "playback_error" : "load_error") {
|
|
341
411
|
const wrapped = error instanceof AudioBandsError ? error : new AudioBandsError(
|
|
342
412
|
kind,
|
|
343
413
|
fallbackCode,
|
|
344
|
-
kind === "mic" ? "Failed to access microphone input" : "Failed to
|
|
414
|
+
kind === "mic" ? "Failed to access microphone input" : kind === "playback" ? "Failed to play audio track" : "Failed to load audio track",
|
|
345
415
|
error
|
|
346
416
|
);
|
|
347
417
|
if (kind === "load") {
|
|
348
418
|
this.setState({ isPlaying: false, loadError: wrapped });
|
|
349
419
|
this.options.onLoadError?.(wrapped);
|
|
420
|
+
} else if (kind === "playback") {
|
|
421
|
+
this.setState({ isPlaying: false, playbackError: wrapped });
|
|
422
|
+
this.options.onPlaybackError?.(wrapped);
|
|
350
423
|
} else {
|
|
351
424
|
this.setState({ micActive: false, micError: wrapped });
|
|
352
425
|
this.options.onMicError?.(wrapped);
|
|
@@ -354,6 +427,36 @@ var AudioBands = class {
|
|
|
354
427
|
this.options.onError?.(wrapped);
|
|
355
428
|
return wrapped;
|
|
356
429
|
}
|
|
430
|
+
bindMusicElementEvents(audio) {
|
|
431
|
+
this.musicEventCleanup?.();
|
|
432
|
+
const handlePlay = () => {
|
|
433
|
+
if (this.audioEl !== audio) return;
|
|
434
|
+
this.setState({ isPlaying: true, playbackError: null });
|
|
435
|
+
this.options.onPlay?.();
|
|
436
|
+
};
|
|
437
|
+
const handlePause = () => {
|
|
438
|
+
if (this.audioEl !== audio) return;
|
|
439
|
+
this.setState({ isPlaying: false });
|
|
440
|
+
this.options.onPause?.();
|
|
441
|
+
};
|
|
442
|
+
const handleEnded = () => {
|
|
443
|
+
if (this.audioEl !== audio) return;
|
|
444
|
+
this.setState({ isPlaying: false });
|
|
445
|
+
};
|
|
446
|
+
audio.addEventListener("play", handlePlay);
|
|
447
|
+
audio.addEventListener("pause", handlePause);
|
|
448
|
+
audio.addEventListener("ended", handleEnded);
|
|
449
|
+
this.musicEventCleanup = () => {
|
|
450
|
+
audio.removeEventListener("play", handlePlay);
|
|
451
|
+
audio.removeEventListener("pause", handlePause);
|
|
452
|
+
audio.removeEventListener("ended", handleEnded);
|
|
453
|
+
if (this.musicEventCleanup) this.musicEventCleanup = null;
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
handleLoadFailure(error) {
|
|
457
|
+
this.teardownMusic();
|
|
458
|
+
return this.handleError("load", error, "load_error");
|
|
459
|
+
}
|
|
357
460
|
setState(patch) {
|
|
358
461
|
let changed = false;
|
|
359
462
|
for (const [key, value] of Object.entries(patch)) {
|
|
@@ -365,6 +468,23 @@ var AudioBands = class {
|
|
|
365
468
|
if (changed) this.options.onStateChange?.(this.getState());
|
|
366
469
|
}
|
|
367
470
|
teardownMusic() {
|
|
471
|
+
this.musicEventCleanup?.();
|
|
472
|
+
if (this.pendingLoadReject) {
|
|
473
|
+
const reject = this.pendingLoadReject;
|
|
474
|
+
this.pendingLoadReject = null;
|
|
475
|
+
this.pendingLoadCleanup?.();
|
|
476
|
+
this.pendingLoadCleanup = null;
|
|
477
|
+
reject(
|
|
478
|
+
new AudioBandsError(
|
|
479
|
+
"load",
|
|
480
|
+
"load_error",
|
|
481
|
+
"Audio track loading was interrupted before completion"
|
|
482
|
+
)
|
|
483
|
+
);
|
|
484
|
+
} else if (this.pendingLoadCleanup) {
|
|
485
|
+
this.pendingLoadCleanup();
|
|
486
|
+
this.pendingLoadCleanup = null;
|
|
487
|
+
}
|
|
368
488
|
this.audioEl?.pause();
|
|
369
489
|
if (this.audioEl) {
|
|
370
490
|
this.audioEl.src = "";
|
|
@@ -377,7 +497,11 @@ var AudioBands = class {
|
|
|
377
497
|
}
|
|
378
498
|
this.musicSource = null;
|
|
379
499
|
this.musicWaveformData = this.musicAnalyser ? new Uint8Array(this.musicAnalyser.fftSize) : null;
|
|
380
|
-
this.setState({
|
|
500
|
+
this.setState({
|
|
501
|
+
isPlaying: false,
|
|
502
|
+
hasTrack: false,
|
|
503
|
+
playbackError: null
|
|
504
|
+
});
|
|
381
505
|
}
|
|
382
506
|
};
|
|
383
507
|
|
|
@@ -387,83 +511,168 @@ var INITIAL_STATE = {
|
|
|
387
511
|
micActive: false,
|
|
388
512
|
hasTrack: false,
|
|
389
513
|
loadError: null,
|
|
514
|
+
playbackError: null,
|
|
390
515
|
micError: null
|
|
391
516
|
};
|
|
517
|
+
function stableStringify(value) {
|
|
518
|
+
if (Array.isArray(value)) {
|
|
519
|
+
return `[${value.map((item) => stableStringify(item)).join(",")}]`;
|
|
520
|
+
}
|
|
521
|
+
if (value && typeof value === "object") {
|
|
522
|
+
return `{${Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([key, nestedValue]) => `${JSON.stringify(key)}:${stableStringify(nestedValue)}`).join(",")}}`;
|
|
523
|
+
}
|
|
524
|
+
return JSON.stringify(value) ?? "null";
|
|
525
|
+
}
|
|
526
|
+
function getStructuralOptionsKey(options) {
|
|
527
|
+
return stableStringify({
|
|
528
|
+
music: options.music,
|
|
529
|
+
mic: options.mic,
|
|
530
|
+
bandRanges: options.bandRanges,
|
|
531
|
+
customBands: options.customBands
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
function createAudioBandsInstance(options, latestOptions, setState, instanceRef) {
|
|
535
|
+
const next = new AudioBands({
|
|
536
|
+
...options,
|
|
537
|
+
onPlay: () => {
|
|
538
|
+
if (instanceRef.current !== next) return;
|
|
539
|
+
latestOptions.current.onPlay?.();
|
|
540
|
+
},
|
|
541
|
+
onPause: () => {
|
|
542
|
+
if (instanceRef.current !== next) return;
|
|
543
|
+
latestOptions.current.onPause?.();
|
|
544
|
+
},
|
|
545
|
+
onError: (error) => {
|
|
546
|
+
if (instanceRef.current !== next) return;
|
|
547
|
+
latestOptions.current.onError?.(error);
|
|
548
|
+
},
|
|
549
|
+
onLoadError: (error) => {
|
|
550
|
+
if (instanceRef.current !== next) return;
|
|
551
|
+
latestOptions.current.onLoadError?.(error);
|
|
552
|
+
},
|
|
553
|
+
onPlaybackError: (error) => {
|
|
554
|
+
if (instanceRef.current !== next) return;
|
|
555
|
+
latestOptions.current.onPlaybackError?.(error);
|
|
556
|
+
},
|
|
557
|
+
onMicError: (error) => {
|
|
558
|
+
if (instanceRef.current !== next) return;
|
|
559
|
+
latestOptions.current.onMicError?.(error);
|
|
560
|
+
},
|
|
561
|
+
onMicStart: () => {
|
|
562
|
+
if (instanceRef.current !== next) return;
|
|
563
|
+
latestOptions.current.onMicStart?.();
|
|
564
|
+
},
|
|
565
|
+
onMicStop: () => {
|
|
566
|
+
if (instanceRef.current !== next) return;
|
|
567
|
+
latestOptions.current.onMicStop?.();
|
|
568
|
+
},
|
|
569
|
+
onStateChange: (nextState) => {
|
|
570
|
+
if (instanceRef.current !== next) return;
|
|
571
|
+
setState(nextState);
|
|
572
|
+
latestOptions.current.onStateChange?.(nextState);
|
|
573
|
+
}
|
|
574
|
+
});
|
|
575
|
+
return next;
|
|
576
|
+
}
|
|
392
577
|
function useAudioBands(options = {}) {
|
|
393
578
|
const [state, setState] = (0, import_react.useState)(INITIAL_STATE);
|
|
394
579
|
const latestOptions = (0, import_react.useRef)(options);
|
|
395
580
|
const instance = (0, import_react.useRef)(null);
|
|
581
|
+
const structuralOptionsKey = getStructuralOptionsKey(options);
|
|
582
|
+
const structuralOptionsKeyRef = (0, import_react.useRef)(structuralOptionsKey);
|
|
396
583
|
latestOptions.current = options;
|
|
397
|
-
|
|
398
|
-
instance.current
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
},
|
|
406
|
-
onError: (error) => {
|
|
407
|
-
latestOptions.current.onError?.(error);
|
|
408
|
-
},
|
|
409
|
-
onLoadError: (error) => {
|
|
410
|
-
latestOptions.current.onLoadError?.(error);
|
|
411
|
-
},
|
|
412
|
-
onMicError: (error) => {
|
|
413
|
-
latestOptions.current.onMicError?.(error);
|
|
414
|
-
},
|
|
415
|
-
onMicStart: () => {
|
|
416
|
-
latestOptions.current.onMicStart?.();
|
|
417
|
-
},
|
|
418
|
-
onMicStop: () => {
|
|
419
|
-
latestOptions.current.onMicStop?.();
|
|
420
|
-
},
|
|
421
|
-
onStateChange: (nextState) => {
|
|
422
|
-
setState(nextState);
|
|
423
|
-
latestOptions.current.onStateChange?.(nextState);
|
|
424
|
-
}
|
|
425
|
-
});
|
|
426
|
-
}
|
|
584
|
+
const getOrCreateInstance = () => {
|
|
585
|
+
if (instance.current) return instance.current;
|
|
586
|
+
const next = createAudioBandsInstance(options, latestOptions, setState, instance);
|
|
587
|
+
instance.current = next;
|
|
588
|
+
structuralOptionsKeyRef.current = structuralOptionsKey;
|
|
589
|
+
return next;
|
|
590
|
+
};
|
|
591
|
+
getOrCreateInstance();
|
|
427
592
|
(0, import_react.useEffect)(() => {
|
|
428
|
-
|
|
429
|
-
|
|
593
|
+
const current = getOrCreateInstance();
|
|
594
|
+
setState(current.getState());
|
|
595
|
+
return () => {
|
|
596
|
+
if (instance.current !== current) return;
|
|
597
|
+
current.destroy();
|
|
598
|
+
instance.current = null;
|
|
599
|
+
};
|
|
430
600
|
}, []);
|
|
601
|
+
(0, import_react.useEffect)(() => {
|
|
602
|
+
if (structuralOptionsKeyRef.current === structuralOptionsKey) return;
|
|
603
|
+
const previous = instance.current;
|
|
604
|
+
const next = createAudioBandsInstance(options, latestOptions, setState, instance);
|
|
605
|
+
instance.current = next;
|
|
606
|
+
structuralOptionsKeyRef.current = structuralOptionsKey;
|
|
607
|
+
setState(next.getState());
|
|
608
|
+
previous?.destroy();
|
|
609
|
+
}, [options, structuralOptionsKey]);
|
|
431
610
|
const loadTrack = (0, import_react.useCallback)(async (url) => {
|
|
432
|
-
await
|
|
611
|
+
await getOrCreateInstance().load(url);
|
|
612
|
+
}, []);
|
|
613
|
+
const play = (0, import_react.useCallback)(async () => {
|
|
614
|
+
await getOrCreateInstance().play();
|
|
433
615
|
}, []);
|
|
434
|
-
const
|
|
435
|
-
|
|
616
|
+
const pause = (0, import_react.useCallback)(() => {
|
|
617
|
+
getOrCreateInstance().pause();
|
|
618
|
+
}, []);
|
|
619
|
+
const setLoop = (0, import_react.useCallback)((loop) => {
|
|
620
|
+
getOrCreateInstance().setLoop(loop);
|
|
621
|
+
}, []);
|
|
622
|
+
const seek = (0, import_react.useCallback)((seconds) => {
|
|
623
|
+
getOrCreateInstance().seek(seconds);
|
|
624
|
+
}, []);
|
|
625
|
+
const getDuration = (0, import_react.useCallback)(() => {
|
|
626
|
+
return getOrCreateInstance().getDuration();
|
|
627
|
+
}, []);
|
|
628
|
+
const getCurrentTime = (0, import_react.useCallback)(() => {
|
|
629
|
+
return getOrCreateInstance().getCurrentTime();
|
|
630
|
+
}, []);
|
|
631
|
+
const togglePlayPause = (0, import_react.useCallback)(async () => {
|
|
632
|
+
await getOrCreateInstance().togglePlayPause();
|
|
436
633
|
}, []);
|
|
437
634
|
const toggleMic = (0, import_react.useCallback)(async () => {
|
|
438
|
-
|
|
439
|
-
|
|
635
|
+
const current = getOrCreateInstance();
|
|
636
|
+
if (current.getState().micActive) {
|
|
637
|
+
current.disableMic();
|
|
440
638
|
} else {
|
|
441
|
-
await
|
|
639
|
+
await current.enableMic();
|
|
442
640
|
}
|
|
443
641
|
}, []);
|
|
642
|
+
const snapshot = (0, import_react.useCallback)((source) => {
|
|
643
|
+
return getOrCreateInstance().snapshot(source);
|
|
644
|
+
}, []);
|
|
444
645
|
const getBands = (0, import_react.useCallback)((source) => {
|
|
445
|
-
return
|
|
646
|
+
return getOrCreateInstance().getBands(source);
|
|
446
647
|
}, []);
|
|
447
648
|
const getCustomBands = (0, import_react.useCallback)((source) => {
|
|
448
|
-
return
|
|
649
|
+
return getOrCreateInstance().getCustomBands(source);
|
|
449
650
|
}, []);
|
|
450
651
|
const getFftData = (0, import_react.useCallback)((source) => {
|
|
451
|
-
return
|
|
652
|
+
return getOrCreateInstance().getFftData(source);
|
|
452
653
|
}, []);
|
|
453
654
|
const getWaveform = (0, import_react.useCallback)((source) => {
|
|
454
|
-
return
|
|
655
|
+
return getOrCreateInstance().getWaveform(source);
|
|
455
656
|
}, []);
|
|
456
657
|
return {
|
|
457
658
|
isPlaying: state.isPlaying,
|
|
458
659
|
micActive: state.micActive,
|
|
459
660
|
hasTrack: state.hasTrack,
|
|
460
|
-
audioError: Boolean(state.loadError || state.micError),
|
|
661
|
+
audioError: Boolean(state.loadError || state.playbackError || state.micError),
|
|
461
662
|
loadError: state.loadError,
|
|
663
|
+
playbackError: state.playbackError,
|
|
462
664
|
micError: state.micError,
|
|
463
665
|
state,
|
|
464
666
|
loadTrack,
|
|
667
|
+
play,
|
|
668
|
+
pause,
|
|
669
|
+
setLoop,
|
|
670
|
+
seek,
|
|
671
|
+
getDuration,
|
|
672
|
+
getCurrentTime,
|
|
465
673
|
togglePlayPause,
|
|
466
674
|
toggleMic,
|
|
675
|
+
snapshot,
|
|
467
676
|
getBands,
|
|
468
677
|
getCustomBands,
|
|
469
678
|
getFftData,
|
package/dist/react-entry.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/react-entry.ts","../src/react.ts","../src/errors.ts","../src/core.ts"],"sourcesContent":["export { useAudioBands } from './react';\nexport { AudioBandsError } from './errors';\nexport type { UseAudioBandsReturn } from './react';\nexport type {\n AudioAnalyserConfig,\n AudioBandsCallbacks,\n AudioBandsErrorCode,\n AudioBandsErrorKind,\n AudioBandsOptions,\n AudioBandsState,\n AudioSource,\n BandRange,\n Bands,\n ClassicBandRanges,\n CustomBandRanges,\n} from './types';\n","'use client';\n\nimport { useRef, useState, useCallback, useEffect } from 'react';\nimport { AudioBands } from './core';\nimport type { AudioBandsOptions, AudioBandsState, AudioSource, Bands } from './types';\nimport type { AudioBandsError } from './errors';\n\nexport type UseAudioBandsReturn = {\n isPlaying: boolean;\n micActive: boolean;\n hasTrack: boolean;\n audioError: boolean;\n loadError: AudioBandsError | null;\n micError: AudioBandsError | null;\n state: AudioBandsState;\n loadTrack: (url: string) => Promise<void>;\n togglePlayPause: () => void;\n toggleMic: () => Promise<void>;\n getBands: (source?: AudioSource) => Bands;\n getCustomBands: (source?: AudioSource) => Record<string, number>;\n getFftData: (source?: AudioSource) => Uint8Array<ArrayBuffer> | null;\n getWaveform: (source?: AudioSource) => Uint8Array<ArrayBuffer> | null;\n};\n\nconst INITIAL_STATE: AudioBandsState = {\n isPlaying: false,\n micActive: false,\n hasTrack: false,\n loadError: null,\n micError: null,\n};\n\n/**\n * React hook — thin wrapper over AudioBands.\n * Handles lifecycle (destroy on unmount) and exposes state for re-renders.\n */\nexport function useAudioBands(options: AudioBandsOptions = {}): UseAudioBandsReturn {\n const [state, setState] = useState<AudioBandsState>(INITIAL_STATE);\n const latestOptions = useRef(options);\n const instance = useRef<AudioBands | null>(null);\n\n latestOptions.current = options;\n\n if (!instance.current) {\n instance.current = new AudioBands({\n ...options,\n onPlay: () => {\n latestOptions.current.onPlay?.();\n },\n onPause: () => {\n latestOptions.current.onPause?.();\n },\n onError: (error) => {\n latestOptions.current.onError?.(error);\n },\n onLoadError: (error) => {\n latestOptions.current.onLoadError?.(error);\n },\n onMicError: (error) => {\n latestOptions.current.onMicError?.(error);\n },\n onMicStart: () => {\n latestOptions.current.onMicStart?.();\n },\n onMicStop: () => {\n latestOptions.current.onMicStop?.();\n },\n onStateChange: (nextState) => {\n setState(nextState);\n latestOptions.current.onStateChange?.(nextState);\n },\n });\n }\n\n useEffect(() => {\n setState(instance.current!.getState());\n return () => instance.current?.destroy();\n }, []);\n\n const loadTrack = useCallback(async (url: string) => {\n await instance.current!.load(url);\n }, []);\n\n const togglePlayPause = useCallback(() => {\n instance.current!.togglePlayPause();\n }, []);\n\n const toggleMic = useCallback(async () => {\n if (instance.current!.getState().micActive) {\n instance.current!.disableMic();\n } else {\n await instance.current!.enableMic();\n }\n }, []);\n\n const getBands = useCallback((source?: AudioSource) => {\n return instance.current!.getBands(source);\n }, []);\n\n const getCustomBands = useCallback((source?: AudioSource) => {\n return instance.current!.getCustomBands(source);\n }, []);\n\n const getFftData = useCallback((source?: AudioSource) => {\n return instance.current!.getFftData(source);\n }, []);\n\n const getWaveform = useCallback((source?: AudioSource) => {\n return instance.current!.getWaveform(source);\n }, []);\n\n return {\n isPlaying: state.isPlaying,\n micActive: state.micActive,\n hasTrack: state.hasTrack,\n audioError: Boolean(state.loadError || state.micError),\n loadError: state.loadError,\n micError: state.micError,\n state,\n loadTrack,\n togglePlayPause,\n toggleMic,\n getBands,\n getCustomBands,\n getFftData,\n getWaveform,\n };\n}\n","import type { AudioBandsErrorCode, AudioBandsErrorKind } from './types';\n\nexport class AudioBandsError extends Error {\n readonly kind: AudioBandsErrorKind;\n readonly code: AudioBandsErrorCode;\n readonly cause?: unknown;\n\n constructor(\n kind: AudioBandsErrorKind,\n code: AudioBandsErrorCode,\n message: string,\n cause?: unknown,\n ) {\n super(message);\n this.name = 'AudioBandsError';\n this.kind = kind;\n this.code = code;\n this.cause = cause;\n }\n}\n","import { AudioBandsError } from './errors';\nimport type {\n AudioAnalyserConfig,\n AudioBandsOptions,\n AudioBandsState,\n AudioSource,\n BandRange,\n Bands,\n ClassicBandRanges,\n CustomBandRanges,\n} from './types';\n\nconst DEFAULT_MUSIC_ANALYSER: Required<AudioAnalyserConfig> = {\n fftSize: 256,\n smoothingTimeConstant: 0.85,\n};\n\nconst DEFAULT_MIC_ANALYSER: Required<AudioAnalyserConfig> = {\n fftSize: 256,\n smoothingTimeConstant: 0.8,\n};\n\nconst DEFAULT_CLASSIC_RANGES: Record<keyof Omit<Bands, 'overall'>, BandRange> = {\n bass: { from: 0, to: 0.08 },\n mid: { from: 0.08, to: 0.4 },\n high: { from: 0.4, to: 1 },\n};\n\nconst ZERO: Bands = { bass: 0, mid: 0, high: 0, overall: 0 };\n\nfunction avg(arr: Uint8Array<ArrayBuffer>, from: number, to: number): number {\n let sum = 0;\n for (let i = from; i < to; i++) sum += arr[i];\n return sum / (to - from);\n}\n\nfunction isPowerOfTwo(value: number): boolean {\n return (value & (value - 1)) === 0;\n}\n\nfunction normalizeAnalyserConfig(\n config: AudioAnalyserConfig | undefined,\n fallback: Required<AudioAnalyserConfig>,\n): Required<AudioAnalyserConfig> {\n const fftSize = config?.fftSize ?? fallback.fftSize;\n const smoothingTimeConstant =\n config?.smoothingTimeConstant ?? fallback.smoothingTimeConstant;\n\n if (\n !Number.isInteger(fftSize) ||\n fftSize < 32 ||\n fftSize > 32768 ||\n !isPowerOfTwo(fftSize)\n ) {\n throw new AudioBandsError(\n 'config',\n 'invalid_config',\n 'fftSize must be a power of two between 32 and 32768',\n );\n }\n\n if (\n typeof smoothingTimeConstant !== 'number' ||\n smoothingTimeConstant < 0 ||\n smoothingTimeConstant > 1\n ) {\n throw new AudioBandsError(\n 'config',\n 'invalid_config',\n 'smoothingTimeConstant must be between 0 and 1',\n );\n }\n\n return { fftSize, smoothingTimeConstant };\n}\n\nfunction normalizeRange(name: string, range: BandRange | undefined): BandRange {\n const normalized = range ?? DEFAULT_CLASSIC_RANGES[name as keyof typeof DEFAULT_CLASSIC_RANGES];\n\n if (\n typeof normalized?.from !== 'number' ||\n typeof normalized?.to !== 'number' ||\n normalized.from < 0 ||\n normalized.to > 1 ||\n normalized.from >= normalized.to\n ) {\n throw new AudioBandsError(\n 'config',\n 'invalid_config',\n `Band range \"${name}\" must satisfy 0 <= from < to <= 1`,\n );\n }\n\n return normalized;\n}\n\nfunction normalizeClassicRanges(\n ranges: ClassicBandRanges | undefined,\n): Record<keyof Omit<Bands, 'overall'>, BandRange> {\n return {\n bass: normalizeRange('bass', ranges?.bass),\n mid: normalizeRange('mid', ranges?.mid),\n high: normalizeRange('high', ranges?.high),\n };\n}\n\nfunction normalizeCustomBands(customBands: CustomBandRanges | undefined): CustomBandRanges {\n if (!customBands) return {};\n\n return Object.fromEntries(\n Object.entries(customBands).map(([name, range]) => [name, normalizeRange(name, range)]),\n );\n}\n\nfunction getIndexes(len: number, range: BandRange): [number, number] {\n const from = Math.max(0, Math.min(len - 1, Math.floor(len * range.from)));\n const to = Math.max(from + 1, Math.min(len, Math.floor(len * range.to)));\n return [from, to];\n}\n\nfunction getRangeValue(data: Uint8Array<ArrayBuffer>, range: BandRange): number {\n const [from, to] = getIndexes(data.length, range);\n return avg(data, from, to) / 255;\n}\n\nfunction fillFrequencyData(\n analyser: AnalyserNode,\n data: Uint8Array<ArrayBuffer>,\n): Uint8Array<ArrayBuffer> {\n analyser.getByteFrequencyData(data);\n return data;\n}\n\nfunction computeBands(\n data: Uint8Array<ArrayBuffer>,\n ranges: Record<keyof Omit<Bands, 'overall'>, BandRange>,\n): Bands {\n const bass = getRangeValue(data, ranges.bass);\n const mid = getRangeValue(data, ranges.mid);\n const high = getRangeValue(data, ranges.high);\n\n return {\n bass,\n mid,\n high,\n overall: bass * 0.5 + mid * 0.3 + high * 0.2,\n };\n}\n\nfunction computeCustomBands(\n data: Uint8Array<ArrayBuffer>,\n ranges: CustomBandRanges,\n): Record<string, number> {\n return Object.fromEntries(\n Object.entries(ranges).map(([name, range]) => [name, getRangeValue(data, range)]),\n );\n}\n\nfunction cloneState(state: AudioBandsState): AudioBandsState {\n return { ...state };\n}\n\n/**\n * Vanilla JS class — no framework dependency.\n * Works in React, Vue, Svelte, or plain HTML.\n */\nexport class AudioBands {\n private options: AudioBandsOptions;\n private readonly musicConfig: Required<AudioAnalyserConfig>;\n private readonly micConfig: Required<AudioAnalyserConfig>;\n private readonly classicRanges: Record<keyof Omit<Bands, 'overall'>, BandRange>;\n private readonly customBandRanges: CustomBandRanges;\n\n private readonly state: AudioBandsState = {\n isPlaying: false,\n micActive: false,\n hasTrack: false,\n loadError: null,\n micError: null,\n };\n\n private ctx: AudioContext | null = null;\n private musicAnalyser: AnalyserNode | null = null;\n private musicData: Uint8Array<ArrayBuffer> | null = null;\n private musicWaveformData: Uint8Array<ArrayBuffer> | null = null;\n private micAnalyser: AnalyserNode | null = null;\n private micData: Uint8Array<ArrayBuffer> | null = null;\n private micWaveformData: Uint8Array<ArrayBuffer> | null = null;\n private audioEl: HTMLAudioElement | null = null;\n private musicSource: MediaElementAudioSourceNode | null = null;\n private micSource: MediaStreamAudioSourceNode | null = null;\n private micStream: MediaStream | null = null;\n private destroyed = false;\n\n constructor(options: AudioBandsOptions = {}) {\n this.options = options;\n this.musicConfig = normalizeAnalyserConfig(options.music, DEFAULT_MUSIC_ANALYSER);\n this.micConfig = normalizeAnalyserConfig(options.mic, DEFAULT_MIC_ANALYSER);\n this.classicRanges = normalizeClassicRanges(options.bandRanges);\n this.customBandRanges = normalizeCustomBands(options.customBands);\n }\n\n getState(): AudioBandsState {\n return cloneState(this.state);\n }\n\n getCustomBands(source: AudioSource = 'music'): Record<string, number> {\n const data = this.readFrequencyData(source);\n if (!data) return computeCustomBands(new Uint8Array(1) as Uint8Array<ArrayBuffer>, this.customBandRanges);\n return computeCustomBands(data, this.customBandRanges);\n }\n\n async load(url: string): Promise<void> {\n let ctx: AudioContext;\n try {\n ctx = this.ensureCtx();\n } catch (error) {\n throw this.handleError('load', error);\n }\n\n this.teardownMusic();\n\n const audio = new Audio();\n audio.crossOrigin = 'anonymous';\n audio.src = url;\n audio.loop = true;\n this.audioEl = audio;\n this.setState({ hasTrack: true, loadError: null });\n\n const source = ctx.createMediaElementSource(audio);\n source.connect(this.musicAnalyser!);\n this.musicSource = source;\n\n try {\n await audio.play();\n this.setState({ isPlaying: true, loadError: null });\n this.options.onPlay?.();\n } catch (error) {\n throw this.handleError('load', error, 'load_error');\n }\n }\n\n togglePlayPause(): void {\n const audio = this.audioEl;\n if (!audio) return;\n\n if (audio.paused) {\n void audio\n .play()\n .then(() => {\n this.setState({ isPlaying: true, loadError: null });\n this.options.onPlay?.();\n })\n .catch((error) => {\n this.handleError('load', error, 'playback_error');\n });\n return;\n }\n\n audio.pause();\n this.setState({ isPlaying: false });\n this.options.onPause?.();\n }\n\n async enableMic(): Promise<void> {\n let ctx: AudioContext;\n try {\n ctx = this.ensureCtx();\n } catch (error) {\n throw this.handleError('mic', error);\n }\n\n if (this.micStream) return;\n\n try {\n const stream = await navigator.mediaDevices.getUserMedia({\n audio: true,\n video: false,\n });\n this.micStream = stream;\n\n const analyser = this.createAnalyser(ctx, this.micConfig);\n this.micAnalyser = analyser;\n this.micData = new Uint8Array(\n analyser.frequencyBinCount,\n ) as Uint8Array<ArrayBuffer>;\n this.micWaveformData = new Uint8Array(\n analyser.fftSize,\n ) as Uint8Array<ArrayBuffer>;\n\n const source = ctx.createMediaStreamSource(stream);\n source.connect(analyser);\n this.micSource = source;\n\n this.setState({ micActive: true, micError: null });\n this.options.onMicStart?.();\n } catch (error) {\n throw this.handleError('mic', error, 'mic_error');\n }\n }\n\n disableMic(): void {\n const hadMic = Boolean(this.micStream || this.micSource || this.micAnalyser);\n this.micStream?.getTracks().forEach((track) => track.stop());\n this.micStream = null;\n\n try {\n this.micSource?.disconnect();\n } catch {\n /* already disconnected */\n }\n\n this.micSource = null;\n this.micAnalyser = null;\n this.micData = null;\n this.micWaveformData = null;\n this.setState({ micActive: false });\n\n if (hadMic) this.options.onMicStop?.();\n }\n\n getBands(source: AudioSource = 'music'): Bands {\n const data = this.readFrequencyData(source);\n if (!data) return { ...ZERO };\n return computeBands(data, this.classicRanges);\n }\n\n getFftData(source: AudioSource = 'music'): Uint8Array<ArrayBuffer> | null {\n return this.readFrequencyData(source);\n }\n\n getWaveform(source: AudioSource = 'music'): Uint8Array<ArrayBuffer> | null {\n return this.readWaveformData(source);\n }\n\n destroy(): void {\n if (this.destroyed) return;\n\n this.teardownMusic();\n this.disableMic();\n void this.ctx?.close();\n this.ctx = null;\n this.musicAnalyser = null;\n this.musicData = null;\n this.musicWaveformData = null;\n this.setState({ isPlaying: false, micActive: false, hasTrack: false });\n this.options = {};\n this.destroyed = true;\n }\n\n private readFrequencyData(source: AudioSource): Uint8Array<ArrayBuffer> | null {\n if (source === 'mic') {\n if (!this.micAnalyser || !this.micData) return null;\n return fillFrequencyData(this.micAnalyser, this.micData);\n }\n\n if (!this.musicAnalyser || !this.musicData) return null;\n return fillFrequencyData(this.musicAnalyser, this.musicData);\n }\n\n private readWaveformData(source: AudioSource): Uint8Array<ArrayBuffer> | null {\n if (source === 'mic') {\n if (!this.micAnalyser || !this.micWaveformData) return null;\n this.micAnalyser.getByteTimeDomainData(this.micWaveformData);\n return this.micWaveformData;\n }\n\n if (!this.musicAnalyser || !this.musicWaveformData) return null;\n this.musicAnalyser.getByteTimeDomainData(this.musicWaveformData);\n return this.musicWaveformData;\n }\n\n private ensureCtx(): AudioContext {\n if (this.destroyed) {\n throw new AudioBandsError(\n 'lifecycle',\n 'destroyed',\n 'This AudioBands instance was destroyed',\n );\n }\n\n if (this.ctx) return this.ctx;\n\n const Ctx =\n window.AudioContext ||\n (window as unknown as { webkitAudioContext?: typeof AudioContext })\n .webkitAudioContext;\n\n if (!Ctx) {\n throw new AudioBandsError(\n 'lifecycle',\n 'unsupported_audio_context',\n 'AudioContext is not supported in this environment',\n );\n }\n\n const ctx = new Ctx();\n const analyser = this.createAnalyser(ctx, this.musicConfig);\n analyser.connect(ctx.destination);\n\n this.ctx = ctx;\n this.musicAnalyser = analyser;\n this.musicData = new Uint8Array(\n analyser.frequencyBinCount,\n ) as Uint8Array<ArrayBuffer>;\n this.musicWaveformData = new Uint8Array(\n analyser.fftSize,\n ) as Uint8Array<ArrayBuffer>;\n\n return ctx;\n }\n\n private createAnalyser(\n ctx: AudioContext,\n config: Required<AudioAnalyserConfig>,\n ): AnalyserNode {\n const analyser = ctx.createAnalyser();\n analyser.fftSize = config.fftSize;\n analyser.smoothingTimeConstant = config.smoothingTimeConstant;\n return analyser;\n }\n\n private handleError(\n kind: 'load' | 'mic',\n error: unknown,\n fallbackCode: 'load_error' | 'playback_error' | 'mic_error' = kind === 'mic'\n ? 'mic_error'\n : 'load_error',\n ): AudioBandsError {\n const wrapped =\n error instanceof AudioBandsError\n ? error\n : new AudioBandsError(\n kind,\n fallbackCode,\n kind === 'mic'\n ? 'Failed to access microphone input'\n : 'Failed to load or play audio track',\n error,\n );\n\n if (kind === 'load') {\n this.setState({ isPlaying: false, loadError: wrapped });\n this.options.onLoadError?.(wrapped);\n } else {\n this.setState({ micActive: false, micError: wrapped });\n this.options.onMicError?.(wrapped);\n }\n\n this.options.onError?.(wrapped);\n return wrapped;\n }\n\n private setState(patch: Partial<AudioBandsState>): void {\n let changed = false;\n\n for (const [key, value] of Object.entries(patch) as Array<\n [keyof AudioBandsState, AudioBandsState[keyof AudioBandsState]]\n >) {\n if (this.state[key] !== value) {\n this.state[key] = value as never;\n changed = true;\n }\n }\n\n if (changed) this.options.onStateChange?.(this.getState());\n }\n\n private teardownMusic(): void {\n this.audioEl?.pause();\n if (this.audioEl) {\n this.audioEl.src = '';\n this.audioEl.load();\n }\n this.audioEl = null;\n\n try {\n this.musicSource?.disconnect();\n } catch {\n /* already disconnected */\n }\n\n this.musicSource = null;\n this.musicWaveformData = this.musicAnalyser\n ? new Uint8Array(this.musicAnalyser.fftSize) as Uint8Array<ArrayBuffer>\n : null;\n this.setState({ isPlaying: false, hasTrack: false });\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEA,mBAAyD;;;ACAlD,IAAM,kBAAN,cAA8B,MAAM;AAAA,EAKzC,YACE,MACA,MACA,SACA,OACA;AACA,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,OAAO;AACZ,SAAK,OAAO;AACZ,SAAK,QAAQ;AAAA,EACf;AACF;;;ACPA,IAAM,yBAAwD;AAAA,EAC5D,SAAS;AAAA,EACT,uBAAuB;AACzB;AAEA,IAAM,uBAAsD;AAAA,EAC1D,SAAS;AAAA,EACT,uBAAuB;AACzB;AAEA,IAAM,yBAA0E;AAAA,EAC9E,MAAM,EAAE,MAAM,GAAG,IAAI,KAAK;AAAA,EAC1B,KAAK,EAAE,MAAM,MAAM,IAAI,IAAI;AAAA,EAC3B,MAAM,EAAE,MAAM,KAAK,IAAI,EAAE;AAC3B;AAEA,IAAM,OAAc,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,SAAS,EAAE;AAE3D,SAAS,IAAI,KAA8B,MAAc,IAAoB;AAC3E,MAAI,MAAM;AACV,WAAS,IAAI,MAAM,IAAI,IAAI,IAAK,QAAO,IAAI,CAAC;AAC5C,SAAO,OAAO,KAAK;AACrB;AAEA,SAAS,aAAa,OAAwB;AAC5C,UAAQ,QAAS,QAAQ,OAAQ;AACnC;AAEA,SAAS,wBACP,QACA,UAC+B;AAC/B,QAAM,UAAU,QAAQ,WAAW,SAAS;AAC5C,QAAM,wBACJ,QAAQ,yBAAyB,SAAS;AAE5C,MACE,CAAC,OAAO,UAAU,OAAO,KACzB,UAAU,MACV,UAAU,SACV,CAAC,aAAa,OAAO,GACrB;AACA,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,MACE,OAAO,0BAA0B,YACjC,wBAAwB,KACxB,wBAAwB,GACxB;AACA,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,SAAS,sBAAsB;AAC1C;AAEA,SAAS,eAAe,MAAc,OAAyC;AAC7E,QAAM,aAAa,SAAS,uBAAuB,IAA2C;AAE9F,MACE,OAAO,YAAY,SAAS,YAC5B,OAAO,YAAY,OAAO,YAC1B,WAAW,OAAO,KAClB,WAAW,KAAK,KAChB,WAAW,QAAQ,WAAW,IAC9B;AACA,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA,eAAe,IAAI;AAAA,IACrB;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,uBACP,QACiD;AACjD,SAAO;AAAA,IACL,MAAM,eAAe,QAAQ,QAAQ,IAAI;AAAA,IACzC,KAAK,eAAe,OAAO,QAAQ,GAAG;AAAA,IACtC,MAAM,eAAe,QAAQ,QAAQ,IAAI;AAAA,EAC3C;AACF;AAEA,SAAS,qBAAqB,aAA6D;AACzF,MAAI,CAAC,YAAa,QAAO,CAAC;AAE1B,SAAO,OAAO;AAAA,IACZ,OAAO,QAAQ,WAAW,EAAE,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,eAAe,MAAM,KAAK,CAAC,CAAC;AAAA,EACxF;AACF;AAEA,SAAS,WAAW,KAAa,OAAoC;AACnE,QAAM,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,MAAM,GAAG,KAAK,MAAM,MAAM,MAAM,IAAI,CAAC,CAAC;AACxE,QAAM,KAAK,KAAK,IAAI,OAAO,GAAG,KAAK,IAAI,KAAK,KAAK,MAAM,MAAM,MAAM,EAAE,CAAC,CAAC;AACvE,SAAO,CAAC,MAAM,EAAE;AAClB;AAEA,SAAS,cAAc,MAA+B,OAA0B;AAC9E,QAAM,CAAC,MAAM,EAAE,IAAI,WAAW,KAAK,QAAQ,KAAK;AAChD,SAAO,IAAI,MAAM,MAAM,EAAE,IAAI;AAC/B;AAEA,SAAS,kBACP,UACA,MACyB;AACzB,WAAS,qBAAqB,IAAI;AAClC,SAAO;AACT;AAEA,SAAS,aACP,MACA,QACO;AACP,QAAM,OAAO,cAAc,MAAM,OAAO,IAAI;AAC5C,QAAM,MAAM,cAAc,MAAM,OAAO,GAAG;AAC1C,QAAM,OAAO,cAAc,MAAM,OAAO,IAAI;AAE5C,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS,OAAO,MAAM,MAAM,MAAM,OAAO;AAAA,EAC3C;AACF;AAEA,SAAS,mBACP,MACA,QACwB;AACxB,SAAO,OAAO;AAAA,IACZ,OAAO,QAAQ,MAAM,EAAE,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,cAAc,MAAM,KAAK,CAAC,CAAC;AAAA,EAClF;AACF;AAEA,SAAS,WAAW,OAAyC;AAC3D,SAAO,EAAE,GAAG,MAAM;AACpB;AAMO,IAAM,aAAN,MAAiB;AAAA,EA4BtB,YAAY,UAA6B,CAAC,GAAG;AArB7C,SAAiB,QAAyB;AAAA,MACxC,WAAW;AAAA,MACX,WAAW;AAAA,MACX,UAAU;AAAA,MACV,WAAW;AAAA,MACX,UAAU;AAAA,IACZ;AAEA,SAAQ,MAA2B;AACnC,SAAQ,gBAAqC;AAC7C,SAAQ,YAA4C;AACpD,SAAQ,oBAAoD;AAC5D,SAAQ,cAAmC;AAC3C,SAAQ,UAA0C;AAClD,SAAQ,kBAAkD;AAC1D,SAAQ,UAAmC;AAC3C,SAAQ,cAAkD;AAC1D,SAAQ,YAA+C;AACvD,SAAQ,YAAgC;AACxC,SAAQ,YAAY;AAGlB,SAAK,UAAU;AACf,SAAK,cAAc,wBAAwB,QAAQ,OAAO,sBAAsB;AAChF,SAAK,YAAY,wBAAwB,QAAQ,KAAK,oBAAoB;AAC1E,SAAK,gBAAgB,uBAAuB,QAAQ,UAAU;AAC9D,SAAK,mBAAmB,qBAAqB,QAAQ,WAAW;AAAA,EAClE;AAAA,EAEA,WAA4B;AAC1B,WAAO,WAAW,KAAK,KAAK;AAAA,EAC9B;AAAA,EAEA,eAAe,SAAsB,SAAiC;AACpE,UAAM,OAAO,KAAK,kBAAkB,MAAM;AAC1C,QAAI,CAAC,KAAM,QAAO,mBAAmB,IAAI,WAAW,CAAC,GAA8B,KAAK,gBAAgB;AACxG,WAAO,mBAAmB,MAAM,KAAK,gBAAgB;AAAA,EACvD;AAAA,EAEA,MAAM,KAAK,KAA4B;AACrC,QAAI;AACJ,QAAI;AACF,YAAM,KAAK,UAAU;AAAA,IACvB,SAAS,OAAO;AACd,YAAM,KAAK,YAAY,QAAQ,KAAK;AAAA,IACtC;AAEA,SAAK,cAAc;AAEnB,UAAM,QAAQ,IAAI,MAAM;AACxB,UAAM,cAAc;AACpB,UAAM,MAAM;AACZ,UAAM,OAAO;AACb,SAAK,UAAU;AACf,SAAK,SAAS,EAAE,UAAU,MAAM,WAAW,KAAK,CAAC;AAEjD,UAAM,SAAS,IAAI,yBAAyB,KAAK;AACjD,WAAO,QAAQ,KAAK,aAAc;AAClC,SAAK,cAAc;AAEnB,QAAI;AACF,YAAM,MAAM,KAAK;AACjB,WAAK,SAAS,EAAE,WAAW,MAAM,WAAW,KAAK,CAAC;AAClD,WAAK,QAAQ,SAAS;AAAA,IACxB,SAAS,OAAO;AACd,YAAM,KAAK,YAAY,QAAQ,OAAO,YAAY;AAAA,IACpD;AAAA,EACF;AAAA,EAEA,kBAAwB;AACtB,UAAM,QAAQ,KAAK;AACnB,QAAI,CAAC,MAAO;AAEZ,QAAI,MAAM,QAAQ;AAChB,WAAK,MACF,KAAK,EACL,KAAK,MAAM;AACV,aAAK,SAAS,EAAE,WAAW,MAAM,WAAW,KAAK,CAAC;AAClD,aAAK,QAAQ,SAAS;AAAA,MACxB,CAAC,EACA,MAAM,CAAC,UAAU;AAChB,aAAK,YAAY,QAAQ,OAAO,gBAAgB;AAAA,MAClD,CAAC;AACH;AAAA,IACF;AAEA,UAAM,MAAM;AACZ,SAAK,SAAS,EAAE,WAAW,MAAM,CAAC;AAClC,SAAK,QAAQ,UAAU;AAAA,EACzB;AAAA,EAEA,MAAM,YAA2B;AAC/B,QAAI;AACJ,QAAI;AACF,YAAM,KAAK,UAAU;AAAA,IACvB,SAAS,OAAO;AACd,YAAM,KAAK,YAAY,OAAO,KAAK;AAAA,IACrC;AAEA,QAAI,KAAK,UAAW;AAEpB,QAAI;AACF,YAAM,SAAS,MAAM,UAAU,aAAa,aAAa;AAAA,QACvD,OAAO;AAAA,QACP,OAAO;AAAA,MACT,CAAC;AACD,WAAK,YAAY;AAEjB,YAAM,WAAW,KAAK,eAAe,KAAK,KAAK,SAAS;AACxD,WAAK,cAAc;AACnB,WAAK,UAAU,IAAI;AAAA,QACjB,SAAS;AAAA,MACX;AACA,WAAK,kBAAkB,IAAI;AAAA,QACzB,SAAS;AAAA,MACX;AAEA,YAAM,SAAS,IAAI,wBAAwB,MAAM;AACjD,aAAO,QAAQ,QAAQ;AACvB,WAAK,YAAY;AAEjB,WAAK,SAAS,EAAE,WAAW,MAAM,UAAU,KAAK,CAAC;AACjD,WAAK,QAAQ,aAAa;AAAA,IAC5B,SAAS,OAAO;AACd,YAAM,KAAK,YAAY,OAAO,OAAO,WAAW;AAAA,IAClD;AAAA,EACF;AAAA,EAEA,aAAmB;AACjB,UAAM,SAAS,QAAQ,KAAK,aAAa,KAAK,aAAa,KAAK,WAAW;AAC3E,SAAK,WAAW,UAAU,EAAE,QAAQ,CAAC,UAAU,MAAM,KAAK,CAAC;AAC3D,SAAK,YAAY;AAEjB,QAAI;AACF,WAAK,WAAW,WAAW;AAAA,IAC7B,QAAQ;AAAA,IAER;AAEA,SAAK,YAAY;AACjB,SAAK,cAAc;AACnB,SAAK,UAAU;AACf,SAAK,kBAAkB;AACvB,SAAK,SAAS,EAAE,WAAW,MAAM,CAAC;AAElC,QAAI,OAAQ,MAAK,QAAQ,YAAY;AAAA,EACvC;AAAA,EAEA,SAAS,SAAsB,SAAgB;AAC7C,UAAM,OAAO,KAAK,kBAAkB,MAAM;AAC1C,QAAI,CAAC,KAAM,QAAO,EAAE,GAAG,KAAK;AAC5B,WAAO,aAAa,MAAM,KAAK,aAAa;AAAA,EAC9C;AAAA,EAEA,WAAW,SAAsB,SAAyC;AACxE,WAAO,KAAK,kBAAkB,MAAM;AAAA,EACtC;AAAA,EAEA,YAAY,SAAsB,SAAyC;AACzE,WAAO,KAAK,iBAAiB,MAAM;AAAA,EACrC;AAAA,EAEA,UAAgB;AACd,QAAI,KAAK,UAAW;AAEpB,SAAK,cAAc;AACnB,SAAK,WAAW;AAChB,SAAK,KAAK,KAAK,MAAM;AACrB,SAAK,MAAM;AACX,SAAK,gBAAgB;AACrB,SAAK,YAAY;AACjB,SAAK,oBAAoB;AACzB,SAAK,SAAS,EAAE,WAAW,OAAO,WAAW,OAAO,UAAU,MAAM,CAAC;AACrE,SAAK,UAAU,CAAC;AAChB,SAAK,YAAY;AAAA,EACnB;AAAA,EAEQ,kBAAkB,QAAqD;AAC7E,QAAI,WAAW,OAAO;AACpB,UAAI,CAAC,KAAK,eAAe,CAAC,KAAK,QAAS,QAAO;AAC/C,aAAO,kBAAkB,KAAK,aAAa,KAAK,OAAO;AAAA,IACzD;AAEA,QAAI,CAAC,KAAK,iBAAiB,CAAC,KAAK,UAAW,QAAO;AACnD,WAAO,kBAAkB,KAAK,eAAe,KAAK,SAAS;AAAA,EAC7D;AAAA,EAEQ,iBAAiB,QAAqD;AAC5E,QAAI,WAAW,OAAO;AACpB,UAAI,CAAC,KAAK,eAAe,CAAC,KAAK,gBAAiB,QAAO;AACvD,WAAK,YAAY,sBAAsB,KAAK,eAAe;AAC3D,aAAO,KAAK;AAAA,IACd;AAEA,QAAI,CAAC,KAAK,iBAAiB,CAAC,KAAK,kBAAmB,QAAO;AAC3D,SAAK,cAAc,sBAAsB,KAAK,iBAAiB;AAC/D,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,YAA0B;AAChC,QAAI,KAAK,WAAW;AAClB,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,QAAI,KAAK,IAAK,QAAO,KAAK;AAE1B,UAAM,MACJ,OAAO,gBACN,OACE;AAEL,QAAI,CAAC,KAAK;AACR,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,UAAM,MAAM,IAAI,IAAI;AACpB,UAAM,WAAW,KAAK,eAAe,KAAK,KAAK,WAAW;AAC1D,aAAS,QAAQ,IAAI,WAAW;AAEhC,SAAK,MAAM;AACX,SAAK,gBAAgB;AACrB,SAAK,YAAY,IAAI;AAAA,MACnB,SAAS;AAAA,IACX;AACA,SAAK,oBAAoB,IAAI;AAAA,MAC3B,SAAS;AAAA,IACX;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,eACN,KACA,QACc;AACd,UAAM,WAAW,IAAI,eAAe;AACpC,aAAS,UAAU,OAAO;AAC1B,aAAS,wBAAwB,OAAO;AACxC,WAAO;AAAA,EACT;AAAA,EAEQ,YACN,MACA,OACA,eAA8D,SAAS,QACnE,cACA,cACa;AACjB,UAAM,UACJ,iBAAiB,kBACb,QACA,IAAI;AAAA,MACF;AAAA,MACA;AAAA,MACA,SAAS,QACL,sCACA;AAAA,MACJ;AAAA,IACF;AAEN,QAAI,SAAS,QAAQ;AACnB,WAAK,SAAS,EAAE,WAAW,OAAO,WAAW,QAAQ,CAAC;AACtD,WAAK,QAAQ,cAAc,OAAO;AAAA,IACpC,OAAO;AACL,WAAK,SAAS,EAAE,WAAW,OAAO,UAAU,QAAQ,CAAC;AACrD,WAAK,QAAQ,aAAa,OAAO;AAAA,IACnC;AAEA,SAAK,QAAQ,UAAU,OAAO;AAC9B,WAAO;AAAA,EACT;AAAA,EAEQ,SAAS,OAAuC;AACtD,QAAI,UAAU;AAEd,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAE5C;AACD,UAAI,KAAK,MAAM,GAAG,MAAM,OAAO;AAC7B,aAAK,MAAM,GAAG,IAAI;AAClB,kBAAU;AAAA,MACZ;AAAA,IACF;AAEA,QAAI,QAAS,MAAK,QAAQ,gBAAgB,KAAK,SAAS,CAAC;AAAA,EAC3D;AAAA,EAEQ,gBAAsB;AAC5B,SAAK,SAAS,MAAM;AACpB,QAAI,KAAK,SAAS;AAChB,WAAK,QAAQ,MAAM;AACnB,WAAK,QAAQ,KAAK;AAAA,IACpB;AACA,SAAK,UAAU;AAEf,QAAI;AACF,WAAK,aAAa,WAAW;AAAA,IAC/B,QAAQ;AAAA,IAER;AAEA,SAAK,cAAc;AACnB,SAAK,oBAAoB,KAAK,gBAC1B,IAAI,WAAW,KAAK,cAAc,OAAO,IACzC;AACJ,SAAK,SAAS,EAAE,WAAW,OAAO,UAAU,MAAM,CAAC;AAAA,EACrD;AACF;;;AFhdA,IAAM,gBAAiC;AAAA,EACrC,WAAW;AAAA,EACX,WAAW;AAAA,EACX,UAAU;AAAA,EACV,WAAW;AAAA,EACX,UAAU;AACZ;AAMO,SAAS,cAAc,UAA6B,CAAC,GAAwB;AAClF,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAA0B,aAAa;AACjE,QAAM,oBAAgB,qBAAO,OAAO;AACpC,QAAM,eAAW,qBAA0B,IAAI;AAE/C,gBAAc,UAAU;AAExB,MAAI,CAAC,SAAS,SAAS;AACrB,aAAS,UAAU,IAAI,WAAW;AAAA,MAChC,GAAG;AAAA,MACH,QAAQ,MAAM;AACZ,sBAAc,QAAQ,SAAS;AAAA,MACjC;AAAA,MACA,SAAS,MAAM;AACb,sBAAc,QAAQ,UAAU;AAAA,MAClC;AAAA,MACA,SAAS,CAAC,UAAU;AAClB,sBAAc,QAAQ,UAAU,KAAK;AAAA,MACvC;AAAA,MACA,aAAa,CAAC,UAAU;AACtB,sBAAc,QAAQ,cAAc,KAAK;AAAA,MAC3C;AAAA,MACA,YAAY,CAAC,UAAU;AACrB,sBAAc,QAAQ,aAAa,KAAK;AAAA,MAC1C;AAAA,MACA,YAAY,MAAM;AAChB,sBAAc,QAAQ,aAAa;AAAA,MACrC;AAAA,MACA,WAAW,MAAM;AACf,sBAAc,QAAQ,YAAY;AAAA,MACpC;AAAA,MACA,eAAe,CAAC,cAAc;AAC5B,iBAAS,SAAS;AAClB,sBAAc,QAAQ,gBAAgB,SAAS;AAAA,MACjD;AAAA,IACF,CAAC;AAAA,EACH;AAEA,8BAAU,MAAM;AACd,aAAS,SAAS,QAAS,SAAS,CAAC;AACrC,WAAO,MAAM,SAAS,SAAS,QAAQ;AAAA,EACzC,GAAG,CAAC,CAAC;AAEL,QAAM,gBAAY,0BAAY,OAAO,QAAgB;AACnD,UAAM,SAAS,QAAS,KAAK,GAAG;AAAA,EAClC,GAAG,CAAC,CAAC;AAEL,QAAM,sBAAkB,0BAAY,MAAM;AACxC,aAAS,QAAS,gBAAgB;AAAA,EACpC,GAAG,CAAC,CAAC;AAEL,QAAM,gBAAY,0BAAY,YAAY;AACxC,QAAI,SAAS,QAAS,SAAS,EAAE,WAAW;AAC1C,eAAS,QAAS,WAAW;AAAA,IAC/B,OAAO;AACL,YAAM,SAAS,QAAS,UAAU;AAAA,IACpC;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,eAAW,0BAAY,CAAC,WAAyB;AACrD,WAAO,SAAS,QAAS,SAAS,MAAM;AAAA,EAC1C,GAAG,CAAC,CAAC;AAEL,QAAM,qBAAiB,0BAAY,CAAC,WAAyB;AAC3D,WAAO,SAAS,QAAS,eAAe,MAAM;AAAA,EAChD,GAAG,CAAC,CAAC;AAEL,QAAM,iBAAa,0BAAY,CAAC,WAAyB;AACvD,WAAO,SAAS,QAAS,WAAW,MAAM;AAAA,EAC5C,GAAG,CAAC,CAAC;AAEL,QAAM,kBAAc,0BAAY,CAAC,WAAyB;AACxD,WAAO,SAAS,QAAS,YAAY,MAAM;AAAA,EAC7C,GAAG,CAAC,CAAC;AAEL,SAAO;AAAA,IACL,WAAW,MAAM;AAAA,IACjB,WAAW,MAAM;AAAA,IACjB,UAAU,MAAM;AAAA,IAChB,YAAY,QAAQ,MAAM,aAAa,MAAM,QAAQ;AAAA,IACrD,WAAW,MAAM;AAAA,IACjB,UAAU,MAAM;AAAA,IAChB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/react-entry.ts","../src/react.ts","../src/errors.ts","../src/core.ts"],"sourcesContent":["export { useAudioBands } from './react';\nexport { AudioBandsError } from './errors';\nexport type { UseAudioBandsReturn } from './react';\nexport type {\n AudioAnalyserConfig,\n AudioBandsCallbacks,\n AudioBandsErrorCode,\n AudioBandsErrorKind,\n AudioBandsOptions,\n AudioBandsSnapshot,\n AudioBandsState,\n AudioSource,\n BandRange,\n Bands,\n ClassicBandRanges,\n CustomBandRanges,\n} from './types';\n","'use client';\n\nimport { useRef, useState, useCallback, useEffect } from 'react';\nimport type { Dispatch, MutableRefObject, SetStateAction } from 'react';\nimport { AudioBands } from './core';\nimport type {\n AudioBandsOptions,\n AudioBandsSnapshot,\n AudioBandsState,\n AudioSource,\n Bands,\n} from './types';\nimport type { AudioBandsError } from './errors';\n\nexport type UseAudioBandsReturn = {\n isPlaying: boolean;\n micActive: boolean;\n hasTrack: boolean;\n audioError: boolean;\n loadError: AudioBandsError | null;\n playbackError: AudioBandsError | null;\n micError: AudioBandsError | null;\n state: AudioBandsState;\n loadTrack: (url: string) => Promise<void>;\n play: () => Promise<void>;\n pause: () => void;\n setLoop: (loop: boolean) => void;\n seek: (seconds: number) => void;\n getDuration: () => number | null;\n getCurrentTime: () => number | null;\n togglePlayPause: () => Promise<void>;\n toggleMic: () => Promise<void>;\n snapshot: (source?: AudioSource) => AudioBandsSnapshot;\n getBands: (source?: AudioSource) => Bands;\n getCustomBands: (source?: AudioSource) => Record<string, number>;\n getFftData: (source?: AudioSource) => Uint8Array<ArrayBuffer> | null;\n getWaveform: (source?: AudioSource) => Uint8Array<ArrayBuffer> | null;\n};\n\nconst INITIAL_STATE: AudioBandsState = {\n isPlaying: false,\n micActive: false,\n hasTrack: false,\n loadError: null,\n playbackError: null,\n micError: null,\n};\n\nfunction stableStringify(value: unknown): string {\n if (Array.isArray(value)) {\n return `[${value.map((item) => stableStringify(item)).join(',')}]`;\n }\n\n if (value && typeof value === 'object') {\n return `{${Object.entries(value as Record<string, unknown>)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([key, nestedValue]) => `${JSON.stringify(key)}:${stableStringify(nestedValue)}`)\n .join(',')}}`;\n }\n\n return JSON.stringify(value) ?? 'null';\n}\n\nfunction getStructuralOptionsKey(options: AudioBandsOptions): string {\n return stableStringify({\n music: options.music,\n mic: options.mic,\n bandRanges: options.bandRanges,\n customBands: options.customBands,\n });\n}\n\nfunction createAudioBandsInstance(\n options: AudioBandsOptions,\n latestOptions: MutableRefObject<AudioBandsOptions>,\n setState: Dispatch<SetStateAction<AudioBandsState>>,\n instanceRef: MutableRefObject<AudioBands | null>,\n): AudioBands {\n const next = new AudioBands({\n ...options,\n onPlay: () => {\n if (instanceRef.current !== next) return;\n latestOptions.current.onPlay?.();\n },\n onPause: () => {\n if (instanceRef.current !== next) return;\n latestOptions.current.onPause?.();\n },\n onError: (error) => {\n if (instanceRef.current !== next) return;\n latestOptions.current.onError?.(error);\n },\n onLoadError: (error) => {\n if (instanceRef.current !== next) return;\n latestOptions.current.onLoadError?.(error);\n },\n onPlaybackError: (error) => {\n if (instanceRef.current !== next) return;\n latestOptions.current.onPlaybackError?.(error);\n },\n onMicError: (error) => {\n if (instanceRef.current !== next) return;\n latestOptions.current.onMicError?.(error);\n },\n onMicStart: () => {\n if (instanceRef.current !== next) return;\n latestOptions.current.onMicStart?.();\n },\n onMicStop: () => {\n if (instanceRef.current !== next) return;\n latestOptions.current.onMicStop?.();\n },\n onStateChange: (nextState) => {\n if (instanceRef.current !== next) return;\n setState(nextState);\n latestOptions.current.onStateChange?.(nextState);\n },\n });\n\n return next;\n}\n\n/**\n * React hook — thin wrapper over AudioBands.\n * Handles lifecycle (destroy on unmount) and exposes state for re-renders.\n */\nexport function useAudioBands(options: AudioBandsOptions = {}): UseAudioBandsReturn {\n const [state, setState] = useState<AudioBandsState>(INITIAL_STATE);\n const latestOptions = useRef(options);\n const instance = useRef<AudioBands | null>(null);\n const structuralOptionsKey = getStructuralOptionsKey(options);\n const structuralOptionsKeyRef = useRef(structuralOptionsKey);\n\n latestOptions.current = options;\n\n const getOrCreateInstance = (): AudioBands => {\n if (instance.current) return instance.current;\n\n const next = createAudioBandsInstance(options, latestOptions, setState, instance);\n instance.current = next;\n structuralOptionsKeyRef.current = structuralOptionsKey;\n return next;\n };\n\n getOrCreateInstance();\n\n useEffect(() => {\n const current = getOrCreateInstance();\n setState(current.getState());\n\n return () => {\n if (instance.current !== current) return;\n current.destroy();\n instance.current = null;\n };\n }, []);\n\n useEffect(() => {\n if (structuralOptionsKeyRef.current === structuralOptionsKey) return;\n\n const previous = instance.current;\n const next = createAudioBandsInstance(options, latestOptions, setState, instance);\n instance.current = next;\n structuralOptionsKeyRef.current = structuralOptionsKey;\n setState(next.getState());\n previous?.destroy();\n }, [options, structuralOptionsKey]);\n\n const loadTrack = useCallback(async (url: string) => {\n await getOrCreateInstance().load(url);\n }, []);\n\n const play = useCallback(async () => {\n await getOrCreateInstance().play();\n }, []);\n\n const pause = useCallback(() => {\n getOrCreateInstance().pause();\n }, []);\n\n const setLoop = useCallback((loop: boolean) => {\n getOrCreateInstance().setLoop(loop);\n }, []);\n\n const seek = useCallback((seconds: number) => {\n getOrCreateInstance().seek(seconds);\n }, []);\n\n const getDuration = useCallback(() => {\n return getOrCreateInstance().getDuration();\n }, []);\n\n const getCurrentTime = useCallback(() => {\n return getOrCreateInstance().getCurrentTime();\n }, []);\n\n const togglePlayPause = useCallback(async () => {\n await getOrCreateInstance().togglePlayPause();\n }, []);\n\n const toggleMic = useCallback(async () => {\n const current = getOrCreateInstance();\n if (current.getState().micActive) {\n current.disableMic();\n } else {\n await current.enableMic();\n }\n }, []);\n\n const snapshot = useCallback((source?: AudioSource) => {\n return getOrCreateInstance().snapshot(source);\n }, []);\n\n const getBands = useCallback((source?: AudioSource) => {\n return getOrCreateInstance().getBands(source);\n }, []);\n\n const getCustomBands = useCallback((source?: AudioSource) => {\n return getOrCreateInstance().getCustomBands(source);\n }, []);\n\n const getFftData = useCallback((source?: AudioSource) => {\n return getOrCreateInstance().getFftData(source);\n }, []);\n\n const getWaveform = useCallback((source?: AudioSource) => {\n return getOrCreateInstance().getWaveform(source);\n }, []);\n\n return {\n isPlaying: state.isPlaying,\n micActive: state.micActive,\n hasTrack: state.hasTrack,\n audioError: Boolean(state.loadError || state.playbackError || state.micError),\n loadError: state.loadError,\n playbackError: state.playbackError,\n micError: state.micError,\n state,\n loadTrack,\n play,\n pause,\n setLoop,\n seek,\n getDuration,\n getCurrentTime,\n togglePlayPause,\n toggleMic,\n snapshot,\n getBands,\n getCustomBands,\n getFftData,\n getWaveform,\n };\n}\n","import type { AudioBandsErrorCode, AudioBandsErrorKind } from './types';\n\nexport class AudioBandsError extends Error {\n readonly kind: AudioBandsErrorKind;\n readonly code: AudioBandsErrorCode;\n readonly cause?: unknown;\n\n constructor(\n kind: AudioBandsErrorKind,\n code: AudioBandsErrorCode,\n message: string,\n cause?: unknown,\n ) {\n super(message);\n this.name = 'AudioBandsError';\n this.kind = kind;\n this.code = code;\n this.cause = cause;\n }\n}\n","import { AudioBandsError } from './errors';\nimport type {\n AudioAnalyserConfig,\n AudioBandsOptions,\n AudioBandsSnapshot,\n AudioBandsState,\n AudioSource,\n BandRange,\n Bands,\n ClassicBandRanges,\n CustomBandRanges,\n} from './types';\n\nconst DEFAULT_MUSIC_ANALYSER: Required<AudioAnalyserConfig> = {\n fftSize: 256,\n smoothingTimeConstant: 0.85,\n};\n\nconst DEFAULT_MIC_ANALYSER: Required<AudioAnalyserConfig> = {\n fftSize: 256,\n smoothingTimeConstant: 0.8,\n};\n\nconst DEFAULT_CLASSIC_RANGES: Record<keyof Omit<Bands, 'overall'>, BandRange> = {\n bass: { from: 0, to: 0.08 },\n mid: { from: 0.08, to: 0.4 },\n high: { from: 0.4, to: 1 },\n};\n\nconst ZERO: Bands = { bass: 0, mid: 0, high: 0, overall: 0 };\n\nfunction avg(arr: Uint8Array<ArrayBuffer>, from: number, to: number): number {\n let sum = 0;\n for (let i = from; i < to; i++) sum += arr[i];\n return sum / (to - from);\n}\n\nfunction isPowerOfTwo(value: number): boolean {\n return (value & (value - 1)) === 0;\n}\n\nfunction normalizeAnalyserConfig(\n config: AudioAnalyserConfig | undefined,\n fallback: Required<AudioAnalyserConfig>,\n): Required<AudioAnalyserConfig> {\n const fftSize = config?.fftSize ?? fallback.fftSize;\n const smoothingTimeConstant =\n config?.smoothingTimeConstant ?? fallback.smoothingTimeConstant;\n\n if (\n !Number.isInteger(fftSize) ||\n fftSize < 32 ||\n fftSize > 32768 ||\n !isPowerOfTwo(fftSize)\n ) {\n throw new AudioBandsError(\n 'config',\n 'invalid_config',\n 'fftSize must be a power of two between 32 and 32768',\n );\n }\n\n if (\n typeof smoothingTimeConstant !== 'number' ||\n smoothingTimeConstant < 0 ||\n smoothingTimeConstant > 1\n ) {\n throw new AudioBandsError(\n 'config',\n 'invalid_config',\n 'smoothingTimeConstant must be between 0 and 1',\n );\n }\n\n return { fftSize, smoothingTimeConstant };\n}\n\nfunction normalizeRange(name: string, range: BandRange | undefined): BandRange {\n const normalized = range ?? DEFAULT_CLASSIC_RANGES[name as keyof typeof DEFAULT_CLASSIC_RANGES];\n\n if (\n typeof normalized?.from !== 'number' ||\n typeof normalized?.to !== 'number' ||\n normalized.from < 0 ||\n normalized.to > 1 ||\n normalized.from >= normalized.to\n ) {\n throw new AudioBandsError(\n 'config',\n 'invalid_config',\n `Band range \"${name}\" must satisfy 0 <= from < to <= 1`,\n );\n }\n\n return normalized;\n}\n\nfunction normalizeClassicRanges(\n ranges: ClassicBandRanges | undefined,\n): Record<keyof Omit<Bands, 'overall'>, BandRange> {\n return {\n bass: normalizeRange('bass', ranges?.bass),\n mid: normalizeRange('mid', ranges?.mid),\n high: normalizeRange('high', ranges?.high),\n };\n}\n\nfunction normalizeCustomBands(customBands: CustomBandRanges | undefined): CustomBandRanges {\n if (!customBands) return {};\n\n return Object.fromEntries(\n Object.entries(customBands).map(([name, range]) => [name, normalizeRange(name, range)]),\n );\n}\n\nfunction getIndexes(len: number, range: BandRange): [number, number] {\n const from = Math.max(0, Math.min(len - 1, Math.floor(len * range.from)));\n const to = Math.max(from + 1, Math.min(len, Math.floor(len * range.to)));\n return [from, to];\n}\n\nfunction getRangeValue(data: Uint8Array<ArrayBuffer>, range: BandRange): number {\n const [from, to] = getIndexes(data.length, range);\n return avg(data, from, to) / 255;\n}\n\nfunction fillFrequencyData(\n analyser: AnalyserNode,\n data: Uint8Array<ArrayBuffer>,\n): Uint8Array<ArrayBuffer> {\n analyser.getByteFrequencyData(data);\n return data;\n}\n\nfunction computeBands(\n data: Uint8Array<ArrayBuffer>,\n ranges: Record<keyof Omit<Bands, 'overall'>, BandRange>,\n): Bands {\n const bass = getRangeValue(data, ranges.bass);\n const mid = getRangeValue(data, ranges.mid);\n const high = getRangeValue(data, ranges.high);\n\n return {\n bass,\n mid,\n high,\n overall: bass * 0.5 + mid * 0.3 + high * 0.2,\n };\n}\n\nfunction computeCustomBands(\n data: Uint8Array<ArrayBuffer>,\n ranges: CustomBandRanges,\n): Record<string, number> {\n return Object.fromEntries(\n Object.entries(ranges).map(([name, range]) => [name, getRangeValue(data, range)]),\n );\n}\n\nfunction cloneState(state: AudioBandsState): AudioBandsState {\n return { ...state };\n}\n\n/**\n * Vanilla JS class — no framework dependency.\n * Works in React, Vue, Svelte, or plain HTML.\n */\nexport class AudioBands {\n private options: AudioBandsOptions;\n private readonly musicConfig: Required<AudioAnalyserConfig>;\n private readonly micConfig: Required<AudioAnalyserConfig>;\n private readonly classicRanges: Record<keyof Omit<Bands, 'overall'>, BandRange>;\n private readonly customBandRanges: CustomBandRanges;\n\n private readonly state: AudioBandsState = {\n isPlaying: false,\n micActive: false,\n hasTrack: false,\n loadError: null,\n playbackError: null,\n micError: null,\n };\n\n private ctx: AudioContext | null = null;\n private musicAnalyser: AnalyserNode | null = null;\n private musicData: Uint8Array<ArrayBuffer> | null = null;\n private musicWaveformData: Uint8Array<ArrayBuffer> | null = null;\n private micAnalyser: AnalyserNode | null = null;\n private micData: Uint8Array<ArrayBuffer> | null = null;\n private micWaveformData: Uint8Array<ArrayBuffer> | null = null;\n private audioEl: HTMLAudioElement | null = null;\n private musicSource: MediaElementAudioSourceNode | null = null;\n private micSource: MediaStreamAudioSourceNode | null = null;\n private micStream: MediaStream | null = null;\n private musicEventCleanup: (() => void) | null = null;\n private pendingLoadCleanup: (() => void) | null = null;\n private pendingLoadReject: ((error: AudioBandsError) => void) | null = null;\n private trackLoop = false;\n private destroyed = false;\n\n constructor(options: AudioBandsOptions = {}) {\n this.options = options;\n this.musicConfig = normalizeAnalyserConfig(options.music, DEFAULT_MUSIC_ANALYSER);\n this.micConfig = normalizeAnalyserConfig(options.mic, DEFAULT_MIC_ANALYSER);\n this.classicRanges = normalizeClassicRanges(options.bandRanges);\n this.customBandRanges = normalizeCustomBands(options.customBands);\n }\n\n getState(): AudioBandsState {\n return cloneState(this.state);\n }\n\n getCustomBands(source: AudioSource = 'music'): Record<string, number> {\n const data = this.readFrequencyData(source);\n if (!data) return computeCustomBands(new Uint8Array(1) as Uint8Array<ArrayBuffer>, this.customBandRanges);\n return computeCustomBands(data, this.customBandRanges);\n }\n\n async load(url: string): Promise<void> {\n let ctx: AudioContext;\n try {\n ctx = this.ensureCtx();\n } catch (error) {\n throw this.handleError('load', error, 'load_error');\n }\n\n this.teardownMusic();\n\n const audio = new Audio();\n audio.crossOrigin = 'anonymous';\n audio.preload = 'auto';\n audio.src = url;\n audio.loop = this.trackLoop;\n this.bindMusicElementEvents(audio);\n this.audioEl = audio;\n this.setState({ hasTrack: false, loadError: null, playbackError: null });\n\n const source = ctx.createMediaElementSource(audio);\n source.connect(this.musicAnalyser!);\n this.musicSource = source;\n\n await new Promise<void>((resolve, reject) => {\n const finalize = () => {\n cleanup();\n this.pendingLoadCleanup = null;\n this.pendingLoadReject = null;\n };\n\n const handleReady = () => {\n finalize();\n this.setState({ hasTrack: true, loadError: null });\n resolve();\n };\n\n const handleFailure = (event?: Event) => {\n finalize();\n const mediaError =\n (event?.target as HTMLMediaElement | null)?.error ??\n audio.error ??\n event;\n reject(this.handleLoadFailure(mediaError));\n };\n\n const cleanup = () => {\n audio.removeEventListener('loadedmetadata', handleReady);\n audio.removeEventListener('canplay', handleReady);\n audio.removeEventListener('error', handleFailure);\n };\n\n this.pendingLoadCleanup = cleanup;\n this.pendingLoadReject = reject;\n\n audio.addEventListener('loadedmetadata', handleReady, { once: true });\n audio.addEventListener('canplay', handleReady, { once: true });\n audio.addEventListener('error', handleFailure, { once: true });\n audio.load();\n });\n }\n\n async play(): Promise<void> {\n const audio = this.audioEl;\n if (!audio) return;\n\n try {\n await audio.play();\n this.setState({ playbackError: null });\n } catch (error) {\n throw this.handleError('playback', error, 'playback_error');\n }\n }\n\n pause(): void {\n const audio = this.audioEl;\n if (!audio || audio.paused) return;\n\n audio.pause();\n }\n\n async togglePlayPause(): Promise<void> {\n const audio = this.audioEl;\n if (!audio) return;\n\n if (audio.paused) {\n await this.play();\n return;\n }\n\n this.pause();\n }\n\n setLoop(loop: boolean): void {\n this.trackLoop = loop;\n if (this.audioEl) this.audioEl.loop = loop;\n }\n\n seek(seconds: number): void {\n if (!Number.isFinite(seconds) || seconds < 0) {\n throw new AudioBandsError(\n 'config',\n 'invalid_config',\n 'seek time must be a finite number greater than or equal to 0',\n );\n }\n\n if (!this.audioEl) return;\n\n const duration = Number.isFinite(this.audioEl.duration) ? this.audioEl.duration : null;\n this.audioEl.currentTime = duration === null ? seconds : Math.min(seconds, duration);\n }\n\n getDuration(): number | null {\n if (!this.audioEl) return null;\n return Number.isFinite(this.audioEl.duration) ? this.audioEl.duration : null;\n }\n\n getCurrentTime(): number | null {\n if (!this.audioEl) return null;\n return Number.isFinite(this.audioEl.currentTime) ? this.audioEl.currentTime : null;\n }\n\n async enableMic(): Promise<void> {\n let ctx: AudioContext;\n try {\n ctx = this.ensureCtx();\n } catch (error) {\n throw this.handleError('mic', error);\n }\n\n if (this.micStream) return;\n\n try {\n const stream = await navigator.mediaDevices.getUserMedia({\n audio: true,\n video: false,\n });\n this.micStream = stream;\n\n const analyser = this.createAnalyser(ctx, this.micConfig);\n this.micAnalyser = analyser;\n this.micData = new Uint8Array(\n analyser.frequencyBinCount,\n ) as Uint8Array<ArrayBuffer>;\n this.micWaveformData = new Uint8Array(\n analyser.fftSize,\n ) as Uint8Array<ArrayBuffer>;\n\n const source = ctx.createMediaStreamSource(stream);\n source.connect(analyser);\n this.micSource = source;\n\n this.setState({ micActive: true, micError: null });\n this.options.onMicStart?.();\n } catch (error) {\n throw this.handleError('mic', error, 'mic_error');\n }\n }\n\n disableMic(): void {\n const hadMic = Boolean(this.micStream || this.micSource || this.micAnalyser);\n this.micStream?.getTracks().forEach((track) => track.stop());\n this.micStream = null;\n\n try {\n this.micSource?.disconnect();\n } catch {\n /* already disconnected */\n }\n\n this.micSource = null;\n this.micAnalyser = null;\n this.micData = null;\n this.micWaveformData = null;\n this.setState({ micActive: false });\n\n if (hadMic) this.options.onMicStop?.();\n }\n\n getBands(source: AudioSource = 'music'): Bands {\n const data = this.readFrequencyData(source);\n if (!data) return { ...ZERO };\n return computeBands(data, this.classicRanges);\n }\n\n getFftData(source: AudioSource = 'music'): Uint8Array<ArrayBuffer> | null {\n return this.readFrequencyData(source);\n }\n\n getWaveform(source: AudioSource = 'music'): Uint8Array<ArrayBuffer> | null {\n return this.readWaveformData(source);\n }\n\n snapshot(source: AudioSource = 'music'): AudioBandsSnapshot {\n const fft = this.readFrequencyData(source);\n const waveform = this.readWaveformData(source);\n\n return {\n bands: fft ? computeBands(fft, this.classicRanges) : { ...ZERO },\n customBands: fft\n ? computeCustomBands(fft, this.customBandRanges)\n : computeCustomBands(new Uint8Array(1) as Uint8Array<ArrayBuffer>, this.customBandRanges),\n fft,\n waveform,\n };\n }\n\n destroy(): void {\n if (this.destroyed) return;\n\n this.teardownMusic();\n this.disableMic();\n void this.ctx?.close();\n this.ctx = null;\n this.musicAnalyser = null;\n this.musicData = null;\n this.musicWaveformData = null;\n this.setState({ isPlaying: false, micActive: false, hasTrack: false });\n this.options = {};\n this.destroyed = true;\n }\n\n private readFrequencyData(source: AudioSource): Uint8Array<ArrayBuffer> | null {\n if (source === 'mic') {\n if (!this.micAnalyser || !this.micData) return null;\n return fillFrequencyData(this.micAnalyser, this.micData);\n }\n\n if (!this.musicAnalyser || !this.musicData) return null;\n return fillFrequencyData(this.musicAnalyser, this.musicData);\n }\n\n private readWaveformData(source: AudioSource): Uint8Array<ArrayBuffer> | null {\n if (source === 'mic') {\n if (!this.micAnalyser || !this.micWaveformData) return null;\n this.micAnalyser.getByteTimeDomainData(this.micWaveformData);\n return this.micWaveformData;\n }\n\n if (!this.musicAnalyser || !this.musicWaveformData) return null;\n this.musicAnalyser.getByteTimeDomainData(this.musicWaveformData);\n return this.musicWaveformData;\n }\n\n private ensureCtx(): AudioContext {\n if (this.destroyed) {\n throw new AudioBandsError(\n 'lifecycle',\n 'destroyed',\n 'This AudioBands instance was destroyed',\n );\n }\n\n if (this.ctx) return this.ctx;\n\n const Ctx =\n window.AudioContext ||\n (window as unknown as { webkitAudioContext?: typeof AudioContext })\n .webkitAudioContext;\n\n if (!Ctx) {\n throw new AudioBandsError(\n 'lifecycle',\n 'unsupported_audio_context',\n 'AudioContext is not supported in this environment',\n );\n }\n\n const ctx = new Ctx();\n const analyser = this.createAnalyser(ctx, this.musicConfig);\n analyser.connect(ctx.destination);\n\n this.ctx = ctx;\n this.musicAnalyser = analyser;\n this.musicData = new Uint8Array(\n analyser.frequencyBinCount,\n ) as Uint8Array<ArrayBuffer>;\n this.musicWaveformData = new Uint8Array(\n analyser.fftSize,\n ) as Uint8Array<ArrayBuffer>;\n\n return ctx;\n }\n\n private createAnalyser(\n ctx: AudioContext,\n config: Required<AudioAnalyserConfig>,\n ): AnalyserNode {\n const analyser = ctx.createAnalyser();\n analyser.fftSize = config.fftSize;\n analyser.smoothingTimeConstant = config.smoothingTimeConstant;\n return analyser;\n }\n\n private handleError(\n kind: 'load' | 'playback' | 'mic',\n error: unknown,\n fallbackCode: 'load_error' | 'playback_error' | 'mic_error' = kind === 'mic'\n ? 'mic_error'\n : kind === 'playback'\n ? 'playback_error'\n : 'load_error',\n ): AudioBandsError {\n const wrapped =\n error instanceof AudioBandsError\n ? error\n : new AudioBandsError(\n kind,\n fallbackCode,\n kind === 'mic'\n ? 'Failed to access microphone input'\n : kind === 'playback'\n ? 'Failed to play audio track'\n : 'Failed to load audio track',\n error,\n );\n\n if (kind === 'load') {\n this.setState({ isPlaying: false, loadError: wrapped });\n this.options.onLoadError?.(wrapped);\n } else if (kind === 'playback') {\n this.setState({ isPlaying: false, playbackError: wrapped });\n this.options.onPlaybackError?.(wrapped);\n } else {\n this.setState({ micActive: false, micError: wrapped });\n this.options.onMicError?.(wrapped);\n }\n\n this.options.onError?.(wrapped);\n return wrapped;\n }\n\n private bindMusicElementEvents(audio: HTMLAudioElement): void {\n this.musicEventCleanup?.();\n\n const handlePlay = () => {\n if (this.audioEl !== audio) return;\n this.setState({ isPlaying: true, playbackError: null });\n this.options.onPlay?.();\n };\n\n const handlePause = () => {\n if (this.audioEl !== audio) return;\n this.setState({ isPlaying: false });\n this.options.onPause?.();\n };\n\n const handleEnded = () => {\n if (this.audioEl !== audio) return;\n this.setState({ isPlaying: false });\n };\n\n audio.addEventListener('play', handlePlay);\n audio.addEventListener('pause', handlePause);\n audio.addEventListener('ended', handleEnded);\n\n this.musicEventCleanup = () => {\n audio.removeEventListener('play', handlePlay);\n audio.removeEventListener('pause', handlePause);\n audio.removeEventListener('ended', handleEnded);\n if (this.musicEventCleanup) this.musicEventCleanup = null;\n };\n }\n\n private handleLoadFailure(error: unknown): AudioBandsError {\n this.teardownMusic();\n return this.handleError('load', error, 'load_error');\n }\n\n private setState(patch: Partial<AudioBandsState>): void {\n let changed = false;\n\n for (const [key, value] of Object.entries(patch) as Array<\n [keyof AudioBandsState, AudioBandsState[keyof AudioBandsState]]\n >) {\n if (this.state[key] !== value) {\n this.state[key] = value as never;\n changed = true;\n }\n }\n\n if (changed) this.options.onStateChange?.(this.getState());\n }\n\n private teardownMusic(): void {\n this.musicEventCleanup?.();\n if (this.pendingLoadReject) {\n const reject = this.pendingLoadReject;\n this.pendingLoadReject = null;\n this.pendingLoadCleanup?.();\n this.pendingLoadCleanup = null;\n reject(\n new AudioBandsError(\n 'load',\n 'load_error',\n 'Audio track loading was interrupted before completion',\n ),\n );\n } else if (this.pendingLoadCleanup) {\n this.pendingLoadCleanup();\n this.pendingLoadCleanup = null;\n }\n this.audioEl?.pause();\n if (this.audioEl) {\n this.audioEl.src = '';\n this.audioEl.load();\n }\n this.audioEl = null;\n\n try {\n this.musicSource?.disconnect();\n } catch {\n /* already disconnected */\n }\n\n this.musicSource = null;\n this.musicWaveformData = this.musicAnalyser\n ? new Uint8Array(this.musicAnalyser.fftSize) as Uint8Array<ArrayBuffer>\n : null;\n this.setState({\n isPlaying: false,\n hasTrack: false,\n playbackError: null,\n });\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/react-entry.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { A as AudioBandsError, a as AudioBandsState, b as AudioSource, B as Bands,
|
|
2
|
-
export {
|
|
1
|
+
import { A as AudioBandsError, a as AudioBandsState, b as AudioSource, c as AudioBandsSnapshot, B as Bands, d as AudioBandsOptions } from './types-0KQJLMV2.cjs';
|
|
2
|
+
export { e as AudioAnalyserConfig, f as AudioBandsCallbacks, g as AudioBandsErrorCode, h as AudioBandsErrorKind, i as BandRange, C as ClassicBandRanges, j as CustomBandRanges } from './types-0KQJLMV2.cjs';
|
|
3
3
|
|
|
4
4
|
type UseAudioBandsReturn = {
|
|
5
5
|
isPlaying: boolean;
|
|
@@ -7,11 +7,19 @@ type UseAudioBandsReturn = {
|
|
|
7
7
|
hasTrack: boolean;
|
|
8
8
|
audioError: boolean;
|
|
9
9
|
loadError: AudioBandsError | null;
|
|
10
|
+
playbackError: AudioBandsError | null;
|
|
10
11
|
micError: AudioBandsError | null;
|
|
11
12
|
state: AudioBandsState;
|
|
12
13
|
loadTrack: (url: string) => Promise<void>;
|
|
13
|
-
|
|
14
|
+
play: () => Promise<void>;
|
|
15
|
+
pause: () => void;
|
|
16
|
+
setLoop: (loop: boolean) => void;
|
|
17
|
+
seek: (seconds: number) => void;
|
|
18
|
+
getDuration: () => number | null;
|
|
19
|
+
getCurrentTime: () => number | null;
|
|
20
|
+
togglePlayPause: () => Promise<void>;
|
|
14
21
|
toggleMic: () => Promise<void>;
|
|
22
|
+
snapshot: (source?: AudioSource) => AudioBandsSnapshot;
|
|
15
23
|
getBands: (source?: AudioSource) => Bands;
|
|
16
24
|
getCustomBands: (source?: AudioSource) => Record<string, number>;
|
|
17
25
|
getFftData: (source?: AudioSource) => Uint8Array<ArrayBuffer> | null;
|
|
@@ -23,4 +31,4 @@ type UseAudioBandsReturn = {
|
|
|
23
31
|
*/
|
|
24
32
|
declare function useAudioBands(options?: AudioBandsOptions): UseAudioBandsReturn;
|
|
25
33
|
|
|
26
|
-
export { AudioBandsError, AudioBandsOptions, AudioBandsState, AudioSource, Bands, type UseAudioBandsReturn, useAudioBands };
|
|
34
|
+
export { AudioBandsError, AudioBandsOptions, AudioBandsSnapshot, AudioBandsState, AudioSource, Bands, type UseAudioBandsReturn, useAudioBands };
|