@waveform-playlist/spectrogram 7.1.2 → 7.1.3
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/dist/index.js +161 -85
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +167 -87
- package/dist/index.mjs.map +1 -1
- package/dist/worker/spectrogram.worker.mjs +68 -8
- package/dist/worker/spectrogram.worker.mjs.map +1 -1
- package/package.json +4 -4
package/dist/index.mjs
CHANGED
|
@@ -3563,7 +3563,14 @@ var ModalButton = styled2.button`
|
|
|
3563
3563
|
}
|
|
3564
3564
|
`;
|
|
3565
3565
|
var FFT_SIZES = [256, 512, 1024, 2048, 4096, 8192];
|
|
3566
|
-
var WINDOW_FUNCTIONS = [
|
|
3566
|
+
var WINDOW_FUNCTIONS = [
|
|
3567
|
+
"hann",
|
|
3568
|
+
"hamming",
|
|
3569
|
+
"blackman",
|
|
3570
|
+
"blackman-harris",
|
|
3571
|
+
"bartlett",
|
|
3572
|
+
"rectangular"
|
|
3573
|
+
];
|
|
3567
3574
|
var FREQ_SCALES = ["linear", "logarithmic", "mel", "bark", "erb"];
|
|
3568
3575
|
var COLOR_MAPS = ["viridis", "magma", "inferno", "grayscale", "igray", "roseus"];
|
|
3569
3576
|
var SpectrogramSettingsModal = ({
|
|
@@ -3585,7 +3592,9 @@ var SpectrogramSettingsModal = ({
|
|
|
3585
3592
|
const [gainDb, setGainDb] = useState(config.gainDb ?? 20);
|
|
3586
3593
|
const [rangeDb, setRangeDb] = useState(config.rangeDb ?? 80);
|
|
3587
3594
|
const [zeroPadding, setZeroPadding] = useState(config.zeroPaddingFactor ?? 2);
|
|
3588
|
-
const [hopSize, setHopSize] = useState(
|
|
3595
|
+
const [hopSize, setHopSize] = useState(
|
|
3596
|
+
config.hopSize ?? Math.floor((config.fftSize ?? 2048) / 4)
|
|
3597
|
+
);
|
|
3589
3598
|
const [showLabels, setShowLabels] = useState(config.labels ?? false);
|
|
3590
3599
|
useEffect(() => {
|
|
3591
3600
|
setFftSize(config.fftSize ?? 2048);
|
|
@@ -3639,11 +3648,18 @@ var SpectrogramSettingsModal = ({
|
|
|
3639
3648
|
/* @__PURE__ */ jsxs2(FormGrid, { children: [
|
|
3640
3649
|
/* @__PURE__ */ jsxs2(Field, { children: [
|
|
3641
3650
|
/* @__PURE__ */ jsx2(Label, { children: "FFT Size" }),
|
|
3642
|
-
/* @__PURE__ */ jsx2(
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3651
|
+
/* @__PURE__ */ jsx2(
|
|
3652
|
+
Select,
|
|
3653
|
+
{
|
|
3654
|
+
value: fftSize,
|
|
3655
|
+
onChange: (e) => {
|
|
3656
|
+
const v = Number(e.target.value);
|
|
3657
|
+
setFftSize(v);
|
|
3658
|
+
setHopSize(Math.floor(v / 4));
|
|
3659
|
+
},
|
|
3660
|
+
children: FFT_SIZES.map((s) => /* @__PURE__ */ jsx2("option", { value: s, children: s }, s))
|
|
3661
|
+
}
|
|
3662
|
+
)
|
|
3647
3663
|
] }),
|
|
3648
3664
|
/* @__PURE__ */ jsxs2(Field, { children: [
|
|
3649
3665
|
/* @__PURE__ */ jsx2(Label, { children: "Hop Size" }),
|
|
@@ -3664,11 +3680,25 @@ var SpectrogramSettingsModal = ({
|
|
|
3664
3680
|
] }),
|
|
3665
3681
|
/* @__PURE__ */ jsxs2(Field, { children: [
|
|
3666
3682
|
/* @__PURE__ */ jsx2(Label, { children: "Frequency Scale" }),
|
|
3667
|
-
/* @__PURE__ */ jsx2(
|
|
3683
|
+
/* @__PURE__ */ jsx2(
|
|
3684
|
+
Select,
|
|
3685
|
+
{
|
|
3686
|
+
value: freqScale,
|
|
3687
|
+
onChange: (e) => setFreqScale(e.target.value),
|
|
3688
|
+
children: FREQ_SCALES.map((s) => /* @__PURE__ */ jsx2("option", { value: s, children: s }, s))
|
|
3689
|
+
}
|
|
3690
|
+
)
|
|
3668
3691
|
] }),
|
|
3669
3692
|
/* @__PURE__ */ jsxs2(Field, { children: [
|
|
3670
3693
|
/* @__PURE__ */ jsx2(Label, { children: "Color Map" }),
|
|
3671
|
-
/* @__PURE__ */ jsx2(
|
|
3694
|
+
/* @__PURE__ */ jsx2(
|
|
3695
|
+
Select,
|
|
3696
|
+
{
|
|
3697
|
+
value: localColorMap,
|
|
3698
|
+
onChange: (e) => setLocalColorMap(e.target.value),
|
|
3699
|
+
children: COLOR_MAPS.map((c) => /* @__PURE__ */ jsx2("option", { value: c, children: c }, c))
|
|
3700
|
+
}
|
|
3701
|
+
)
|
|
3672
3702
|
] }),
|
|
3673
3703
|
/* @__PURE__ */ jsxs2(Field, { children: [
|
|
3674
3704
|
/* @__PURE__ */ jsx2(Label, { children: "Min Frequency (Hz)" }),
|
|
@@ -3727,7 +3757,14 @@ var SpectrogramSettingsModal = ({
|
|
|
3727
3757
|
)
|
|
3728
3758
|
] }),
|
|
3729
3759
|
/* @__PURE__ */ jsx2(Field, { $span: true, children: /* @__PURE__ */ jsxs2(CheckboxLabel, { children: [
|
|
3730
|
-
/* @__PURE__ */ jsx2(
|
|
3760
|
+
/* @__PURE__ */ jsx2(
|
|
3761
|
+
"input",
|
|
3762
|
+
{
|
|
3763
|
+
type: "checkbox",
|
|
3764
|
+
checked: showLabels,
|
|
3765
|
+
onChange: (e) => setShowLabels(e.target.checked)
|
|
3766
|
+
}
|
|
3767
|
+
),
|
|
3731
3768
|
"Show Frequency Labels"
|
|
3732
3769
|
] }) })
|
|
3733
3770
|
] }),
|
|
@@ -3850,10 +3887,7 @@ function createSpectrogramWorker(worker) {
|
|
|
3850
3887
|
});
|
|
3851
3888
|
},
|
|
3852
3889
|
registerCanvas(canvasId, canvas) {
|
|
3853
|
-
worker.postMessage(
|
|
3854
|
-
{ type: "register-canvas", canvasId, canvas },
|
|
3855
|
-
[canvas]
|
|
3856
|
-
);
|
|
3890
|
+
worker.postMessage({ type: "register-canvas", canvasId, canvas }, [canvas]);
|
|
3857
3891
|
},
|
|
3858
3892
|
unregisterCanvas(canvasId) {
|
|
3859
3893
|
worker.postMessage({ type: "unregister-canvas", canvasId });
|
|
@@ -3907,8 +3941,12 @@ function createSpectrogramWorker(worker) {
|
|
|
3907
3941
|
|
|
3908
3942
|
// src/SpectrogramProvider.tsx
|
|
3909
3943
|
import { useState as useState2, useEffect as useEffect2, useRef as useRef2, useCallback, useMemo } from "react";
|
|
3910
|
-
import {
|
|
3911
|
-
|
|
3944
|
+
import {
|
|
3945
|
+
MAX_CANVAS_WIDTH
|
|
3946
|
+
} from "@waveform-playlist/core";
|
|
3947
|
+
import {
|
|
3948
|
+
SpectrogramIntegrationProvider
|
|
3949
|
+
} from "@waveform-playlist/browser";
|
|
3912
3950
|
import { usePlaylistData, usePlaylistControls } from "@waveform-playlist/browser";
|
|
3913
3951
|
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
3914
3952
|
function extractChunkNumber(canvasId) {
|
|
@@ -3924,16 +3962,11 @@ var SpectrogramProvider = ({
|
|
|
3924
3962
|
colorMap: spectrogramColorMap,
|
|
3925
3963
|
children
|
|
3926
3964
|
}) => {
|
|
3927
|
-
const {
|
|
3928
|
-
tracks,
|
|
3929
|
-
waveHeight,
|
|
3930
|
-
samplesPerPixel,
|
|
3931
|
-
isReady,
|
|
3932
|
-
mono,
|
|
3933
|
-
controls
|
|
3934
|
-
} = usePlaylistData();
|
|
3965
|
+
const { tracks, waveHeight, samplesPerPixel, isReady, mono, controls } = usePlaylistData();
|
|
3935
3966
|
const { scrollContainerRef } = usePlaylistControls();
|
|
3936
|
-
const [spectrogramDataMap, setSpectrogramDataMap] = useState2(
|
|
3967
|
+
const [spectrogramDataMap, setSpectrogramDataMap] = useState2(
|
|
3968
|
+
/* @__PURE__ */ new Map()
|
|
3969
|
+
);
|
|
3937
3970
|
const [trackSpectrogramOverrides, setTrackSpectrogramOverrides] = useState2(/* @__PURE__ */ new Map());
|
|
3938
3971
|
const spectrogramCanvasRegistryRef = useRef2(/* @__PURE__ */ new Map());
|
|
3939
3972
|
const [spectrogramCanvasVersion, setSpectrogramCanvasVersion] = useState2(0);
|
|
@@ -4082,9 +4115,7 @@ var SpectrogramProvider = ({
|
|
|
4082
4115
|
if (mode === "waveform") return;
|
|
4083
4116
|
const trackConfigChanged = configChanged && currentKeys.get(track.id) !== prevKeys.get(track.id);
|
|
4084
4117
|
const trackFFTChanged = fftKeyChanged && currentFFTKeys.get(track.id) !== prevFFTKeys.get(track.id);
|
|
4085
|
-
const hasRegisteredCanvases = canvasVersionChanged && track.clips.some(
|
|
4086
|
-
(clip) => spectrogramCanvasRegistryRef.current.has(clip.id)
|
|
4087
|
-
);
|
|
4118
|
+
const hasRegisteredCanvases = canvasVersionChanged && track.clips.some((clip) => spectrogramCanvasRegistryRef.current.has(clip.id));
|
|
4088
4119
|
if (!trackConfigChanged && !hasRegisteredCanvases) return;
|
|
4089
4120
|
const cfg = trackSpectrogramOverrides.get(track.id)?.config ?? track.spectrogramConfig ?? spectrogramConfig ?? {};
|
|
4090
4121
|
const cm = trackSpectrogramOverrides.get(track.id)?.colorMap ?? track.spectrogramColorMap ?? spectrogramColorMap ?? "viridis";
|
|
@@ -4142,7 +4173,13 @@ var SpectrogramProvider = ({
|
|
|
4142
4173
|
} else {
|
|
4143
4174
|
for (let ch = 0; ch < clip.audioBuffer.numberOfChannels; ch++) {
|
|
4144
4175
|
channelSpectrograms.push(
|
|
4145
|
-
computeSpectrogram(
|
|
4176
|
+
computeSpectrogram(
|
|
4177
|
+
clip.audioBuffer,
|
|
4178
|
+
item.config,
|
|
4179
|
+
item.offsetSamples,
|
|
4180
|
+
item.durationSamples,
|
|
4181
|
+
ch
|
|
4182
|
+
)
|
|
4146
4183
|
);
|
|
4147
4184
|
}
|
|
4148
4185
|
}
|
|
@@ -4255,7 +4292,10 @@ var SpectrogramProvider = ({
|
|
|
4255
4292
|
item.offsetSamples + Math.ceil(localEndPx * samplesPerPixel)
|
|
4256
4293
|
);
|
|
4257
4294
|
const paddedStart = Math.max(item.offsetSamples, visStartSample - windowSize);
|
|
4258
|
-
const paddedEnd = Math.min(
|
|
4295
|
+
const paddedEnd = Math.min(
|
|
4296
|
+
item.offsetSamples + item.durationSamples,
|
|
4297
|
+
visEndSample + windowSize
|
|
4298
|
+
);
|
|
4259
4299
|
if (paddedEnd - paddedStart < item.durationSamples * 0.8) {
|
|
4260
4300
|
visibleRange = { start: paddedStart, end: paddedEnd };
|
|
4261
4301
|
}
|
|
@@ -4278,7 +4318,14 @@ var SpectrogramProvider = ({
|
|
|
4278
4318
|
const channelInfo = clipCanvasInfo.get(ch);
|
|
4279
4319
|
if (!channelInfo) continue;
|
|
4280
4320
|
const { visibleIndices } = getVisibleChunkRange(channelInfo, clipPixelOffset);
|
|
4281
|
-
await renderChunkSubset(
|
|
4321
|
+
await renderChunkSubset(
|
|
4322
|
+
workerApi,
|
|
4323
|
+
visibleCacheKey,
|
|
4324
|
+
channelInfo,
|
|
4325
|
+
visibleIndices,
|
|
4326
|
+
item,
|
|
4327
|
+
ch
|
|
4328
|
+
);
|
|
4282
4329
|
}
|
|
4283
4330
|
if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;
|
|
4284
4331
|
}
|
|
@@ -4299,7 +4346,14 @@ var SpectrogramProvider = ({
|
|
|
4299
4346
|
if (!channelInfo) continue;
|
|
4300
4347
|
const range = getVisibleChunkRange(channelInfo, clipPixelOffset);
|
|
4301
4348
|
channelRanges.push({ ch, channelInfo, ...range });
|
|
4302
|
-
await renderChunkSubset(
|
|
4349
|
+
await renderChunkSubset(
|
|
4350
|
+
workerApi,
|
|
4351
|
+
cacheKey,
|
|
4352
|
+
channelInfo,
|
|
4353
|
+
range.visibleIndices,
|
|
4354
|
+
item,
|
|
4355
|
+
ch
|
|
4356
|
+
);
|
|
4303
4357
|
}
|
|
4304
4358
|
if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;
|
|
4305
4359
|
if (await renderBackgroundBatches(channelRanges, cacheKey, item)) return;
|
|
@@ -4335,7 +4389,10 @@ var SpectrogramProvider = ({
|
|
|
4335
4389
|
for (let ch = 0; ch < item.numChannels; ch++) {
|
|
4336
4390
|
const channelInfo = clipCanvasInfo.get(ch);
|
|
4337
4391
|
if (!channelInfo) continue;
|
|
4338
|
-
const { visibleIndices, remainingIndices } = getVisibleChunkRange(
|
|
4392
|
+
const { visibleIndices, remainingIndices } = getVisibleChunkRange(
|
|
4393
|
+
channelInfo,
|
|
4394
|
+
clipPixelOffset
|
|
4395
|
+
);
|
|
4339
4396
|
channelRanges.push({ ch, channelInfo, remainingIndices });
|
|
4340
4397
|
await renderChunkSubset(workerApi, cacheKey, channelInfo, visibleIndices, item, ch);
|
|
4341
4398
|
}
|
|
@@ -4349,7 +4406,18 @@ var SpectrogramProvider = ({
|
|
|
4349
4406
|
computeAsync().catch((err) => {
|
|
4350
4407
|
console.error("[waveform-playlist] Spectrogram computation failed:", err);
|
|
4351
4408
|
});
|
|
4352
|
-
}, [
|
|
4409
|
+
}, [
|
|
4410
|
+
tracks,
|
|
4411
|
+
mono,
|
|
4412
|
+
spectrogramConfig,
|
|
4413
|
+
spectrogramColorMap,
|
|
4414
|
+
trackSpectrogramOverrides,
|
|
4415
|
+
waveHeight,
|
|
4416
|
+
samplesPerPixel,
|
|
4417
|
+
spectrogramCanvasVersion,
|
|
4418
|
+
controls,
|
|
4419
|
+
scrollContainerRef
|
|
4420
|
+
]);
|
|
4353
4421
|
const setTrackRenderMode = useCallback((trackId, mode) => {
|
|
4354
4422
|
setTrackSpectrogramOverrides((prev) => {
|
|
4355
4423
|
const next = new Map(prev);
|
|
@@ -4358,26 +4426,32 @@ var SpectrogramProvider = ({
|
|
|
4358
4426
|
return next;
|
|
4359
4427
|
});
|
|
4360
4428
|
}, []);
|
|
4361
|
-
const setTrackSpectrogramConfig = useCallback(
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
|
|
4429
|
+
const setTrackSpectrogramConfig = useCallback(
|
|
4430
|
+
(trackId, config, colorMap) => {
|
|
4431
|
+
setTrackSpectrogramOverrides((prev) => {
|
|
4432
|
+
const next = new Map(prev);
|
|
4433
|
+
const existing = next.get(trackId);
|
|
4434
|
+
next.set(trackId, {
|
|
4435
|
+
renderMode: existing?.renderMode ?? "waveform",
|
|
4436
|
+
config,
|
|
4437
|
+
...colorMap !== void 0 ? { colorMap } : { colorMap: existing?.colorMap }
|
|
4438
|
+
});
|
|
4439
|
+
return next;
|
|
4369
4440
|
});
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
const registerSpectrogramCanvases = useCallback(
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
registry.
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
|
|
4441
|
+
},
|
|
4442
|
+
[]
|
|
4443
|
+
);
|
|
4444
|
+
const registerSpectrogramCanvases = useCallback(
|
|
4445
|
+
(clipId, channelIndex, canvasIds, canvasWidths) => {
|
|
4446
|
+
const registry = spectrogramCanvasRegistryRef.current;
|
|
4447
|
+
if (!registry.has(clipId)) {
|
|
4448
|
+
registry.set(clipId, /* @__PURE__ */ new Map());
|
|
4449
|
+
}
|
|
4450
|
+
registry.get(clipId).set(channelIndex, { canvasIds, canvasWidths });
|
|
4451
|
+
setSpectrogramCanvasVersion((v) => v + 1);
|
|
4452
|
+
},
|
|
4453
|
+
[]
|
|
4454
|
+
);
|
|
4381
4455
|
const unregisterSpectrogramCanvases = useCallback((clipId, channelIndex) => {
|
|
4382
4456
|
const registry = spectrogramCanvasRegistryRef.current;
|
|
4383
4457
|
const clipChannels = registry.get(clipId);
|
|
@@ -4388,40 +4462,46 @@ var SpectrogramProvider = ({
|
|
|
4388
4462
|
}
|
|
4389
4463
|
}
|
|
4390
4464
|
}, []);
|
|
4391
|
-
const renderMenuItems = useCallback(
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
|
|
4397
|
-
|
|
4398
|
-
|
|
4399
|
-
|
|
4400
|
-
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4465
|
+
const renderMenuItems = useCallback(
|
|
4466
|
+
(props) => {
|
|
4467
|
+
return SpectrogramMenuItems({
|
|
4468
|
+
renderMode: props.renderMode,
|
|
4469
|
+
onRenderModeChange: props.onRenderModeChange,
|
|
4470
|
+
onOpenSettings: props.onOpenSettings,
|
|
4471
|
+
onClose: props.onClose
|
|
4472
|
+
});
|
|
4473
|
+
},
|
|
4474
|
+
[]
|
|
4475
|
+
);
|
|
4476
|
+
const value = useMemo(
|
|
4477
|
+
() => ({
|
|
4478
|
+
spectrogramDataMap,
|
|
4479
|
+
trackSpectrogramOverrides,
|
|
4480
|
+
spectrogramWorkerApi: spectrogramWorkerReady ? spectrogramWorkerRef.current : null,
|
|
4481
|
+
spectrogramConfig,
|
|
4482
|
+
spectrogramColorMap,
|
|
4483
|
+
setTrackRenderMode,
|
|
4484
|
+
setTrackSpectrogramConfig,
|
|
4485
|
+
registerSpectrogramCanvases,
|
|
4486
|
+
unregisterSpectrogramCanvases,
|
|
4487
|
+
renderMenuItems,
|
|
4488
|
+
SettingsModal: SpectrogramSettingsModal,
|
|
4489
|
+
getColorMap,
|
|
4490
|
+
getFrequencyScale
|
|
4491
|
+
}),
|
|
4492
|
+
[
|
|
4493
|
+
spectrogramDataMap,
|
|
4494
|
+
trackSpectrogramOverrides,
|
|
4495
|
+
spectrogramWorkerReady,
|
|
4496
|
+
spectrogramConfig,
|
|
4497
|
+
spectrogramColorMap,
|
|
4498
|
+
setTrackRenderMode,
|
|
4499
|
+
setTrackSpectrogramConfig,
|
|
4500
|
+
registerSpectrogramCanvases,
|
|
4501
|
+
unregisterSpectrogramCanvases,
|
|
4502
|
+
renderMenuItems
|
|
4503
|
+
]
|
|
4504
|
+
);
|
|
4425
4505
|
return /* @__PURE__ */ jsx3(SpectrogramIntegrationProvider, { value, children });
|
|
4426
4506
|
};
|
|
4427
4507
|
export {
|