@waveform-playlist/spectrogram 9.4.1 → 9.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +16 -25
- package/dist/index.d.ts +16 -25
- package/dist/index.js +356 -266
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +354 -266
- package/dist/index.mjs.map +1 -1
- package/dist/worker/spectrogram.worker.mjs +190 -159
- package/dist/worker/spectrogram.worker.mjs.map +1 -1
- package/package.json +4 -4
package/dist/index.mjs
CHANGED
|
@@ -3776,6 +3776,12 @@ var SpectrogramSettingsModal = ({
|
|
|
3776
3776
|
};
|
|
3777
3777
|
|
|
3778
3778
|
// src/worker/createSpectrogramWorker.ts
|
|
3779
|
+
var SpectrogramAbortError = class extends Error {
|
|
3780
|
+
constructor() {
|
|
3781
|
+
super("aborted");
|
|
3782
|
+
this.name = "SpectrogramAbortError";
|
|
3783
|
+
}
|
|
3784
|
+
};
|
|
3779
3785
|
function addPending(map, id, resolve, reject) {
|
|
3780
3786
|
map.set(id, { resolve, reject });
|
|
3781
3787
|
}
|
|
@@ -3793,15 +3799,15 @@ function createSpectrogramWorker(worker) {
|
|
|
3793
3799
|
case "error":
|
|
3794
3800
|
entry.reject(new Error(msg.error));
|
|
3795
3801
|
break;
|
|
3802
|
+
case "aborted":
|
|
3803
|
+
entry.reject(new SpectrogramAbortError());
|
|
3804
|
+
break;
|
|
3796
3805
|
case "cache-key":
|
|
3797
3806
|
entry.resolve({ cacheKey: msg.cacheKey });
|
|
3798
3807
|
break;
|
|
3799
3808
|
case "done":
|
|
3800
3809
|
entry.resolve(void 0);
|
|
3801
3810
|
break;
|
|
3802
|
-
case "spectrograms":
|
|
3803
|
-
entry.resolve(msg.spectrograms);
|
|
3804
|
-
break;
|
|
3805
3811
|
}
|
|
3806
3812
|
} else if (msg.id) {
|
|
3807
3813
|
console.warn(`[spectrogram] Received response for unknown message ID: ${msg.id}`);
|
|
@@ -3815,28 +3821,7 @@ function createSpectrogramWorker(worker) {
|
|
|
3815
3821
|
pending.clear();
|
|
3816
3822
|
};
|
|
3817
3823
|
return {
|
|
3818
|
-
|
|
3819
|
-
if (terminated) return Promise.reject(new Error("Worker terminated"));
|
|
3820
|
-
const id = String(++idCounter);
|
|
3821
|
-
return new Promise((resolve, reject) => {
|
|
3822
|
-
addPending(pending, id, resolve, reject);
|
|
3823
|
-
const transferableArrays = params.channelDataArrays.map((arr) => arr.slice());
|
|
3824
|
-
const transferables = transferableArrays.map((arr) => arr.buffer);
|
|
3825
|
-
worker.postMessage(
|
|
3826
|
-
{
|
|
3827
|
-
id,
|
|
3828
|
-
channelDataArrays: transferableArrays,
|
|
3829
|
-
config: params.config,
|
|
3830
|
-
sampleRate: params.sampleRate,
|
|
3831
|
-
offsetSamples: params.offsetSamples,
|
|
3832
|
-
durationSamples: params.durationSamples,
|
|
3833
|
-
mono: params.mono
|
|
3834
|
-
},
|
|
3835
|
-
transferables
|
|
3836
|
-
);
|
|
3837
|
-
});
|
|
3838
|
-
},
|
|
3839
|
-
computeFFT(params) {
|
|
3824
|
+
computeFFT(params, generation = 0) {
|
|
3840
3825
|
if (terminated) return Promise.reject(new Error("Worker terminated"));
|
|
3841
3826
|
const id = String(++idCounter);
|
|
3842
3827
|
return new Promise((resolve, reject) => {
|
|
@@ -3848,6 +3833,7 @@ function createSpectrogramWorker(worker) {
|
|
|
3848
3833
|
{
|
|
3849
3834
|
type: "compute-fft",
|
|
3850
3835
|
id,
|
|
3836
|
+
generation,
|
|
3851
3837
|
clipId: params.clipId,
|
|
3852
3838
|
channelDataArrays: transferableArrays,
|
|
3853
3839
|
config: params.config,
|
|
@@ -3855,13 +3841,14 @@ function createSpectrogramWorker(worker) {
|
|
|
3855
3841
|
offsetSamples: params.offsetSamples,
|
|
3856
3842
|
durationSamples: params.durationSamples,
|
|
3857
3843
|
mono: params.mono,
|
|
3858
|
-
...params.sampleRange ? { sampleRange: params.sampleRange } : {}
|
|
3844
|
+
...params.sampleRange ? { sampleRange: params.sampleRange } : {},
|
|
3845
|
+
...params.channelFilter !== void 0 ? { channelFilter: params.channelFilter } : {}
|
|
3859
3846
|
},
|
|
3860
3847
|
transferables
|
|
3861
3848
|
);
|
|
3862
3849
|
});
|
|
3863
3850
|
},
|
|
3864
|
-
renderChunks(params) {
|
|
3851
|
+
renderChunks(params, generation = 0) {
|
|
3865
3852
|
if (terminated) return Promise.reject(new Error("Worker terminated"));
|
|
3866
3853
|
const id = String(++idCounter);
|
|
3867
3854
|
return new Promise((resolve, reject) => {
|
|
@@ -3869,6 +3856,7 @@ function createSpectrogramWorker(worker) {
|
|
|
3869
3856
|
worker.postMessage({
|
|
3870
3857
|
type: "render-chunks",
|
|
3871
3858
|
id,
|
|
3859
|
+
generation,
|
|
3872
3860
|
cacheKey: params.cacheKey,
|
|
3873
3861
|
canvasIds: params.canvasIds,
|
|
3874
3862
|
canvasWidths: params.canvasWidths,
|
|
@@ -3886,6 +3874,10 @@ function createSpectrogramWorker(worker) {
|
|
|
3886
3874
|
});
|
|
3887
3875
|
});
|
|
3888
3876
|
},
|
|
3877
|
+
abortGeneration(generation) {
|
|
3878
|
+
if (terminated) return;
|
|
3879
|
+
worker.postMessage({ type: "abort-generation", generation });
|
|
3880
|
+
},
|
|
3889
3881
|
registerCanvas(canvasId, canvas) {
|
|
3890
3882
|
worker.postMessage({ type: "register-canvas", canvasId, canvas }, [canvas]);
|
|
3891
3883
|
},
|
|
@@ -3905,29 +3897,6 @@ function createSpectrogramWorker(worker) {
|
|
|
3905
3897
|
worker.postMessage({ type: "unregister-audio-data", clipId });
|
|
3906
3898
|
registeredClipIds.delete(clipId);
|
|
3907
3899
|
},
|
|
3908
|
-
computeAndRender(params) {
|
|
3909
|
-
if (terminated) return Promise.reject(new Error("Worker terminated"));
|
|
3910
|
-
const id = String(++idCounter);
|
|
3911
|
-
return new Promise((resolve, reject) => {
|
|
3912
|
-
addPending(pending, id, resolve, reject);
|
|
3913
|
-
const transferableArrays = params.channelDataArrays.map((arr) => arr.slice());
|
|
3914
|
-
const transferables = transferableArrays.map((arr) => arr.buffer);
|
|
3915
|
-
worker.postMessage(
|
|
3916
|
-
{
|
|
3917
|
-
type: "compute-render",
|
|
3918
|
-
id,
|
|
3919
|
-
channelDataArrays: transferableArrays,
|
|
3920
|
-
config: params.config,
|
|
3921
|
-
sampleRate: params.sampleRate,
|
|
3922
|
-
offsetSamples: params.offsetSamples,
|
|
3923
|
-
durationSamples: params.durationSamples,
|
|
3924
|
-
mono: params.mono,
|
|
3925
|
-
render: params.render
|
|
3926
|
-
},
|
|
3927
|
-
transferables
|
|
3928
|
-
);
|
|
3929
|
-
});
|
|
3930
|
-
},
|
|
3931
3900
|
terminate() {
|
|
3932
3901
|
terminated = true;
|
|
3933
3902
|
worker.terminate();
|
|
@@ -3939,6 +3908,76 @@ function createSpectrogramWorker(worker) {
|
|
|
3939
3908
|
};
|
|
3940
3909
|
}
|
|
3941
3910
|
|
|
3911
|
+
// src/worker/createSpectrogramWorkerPool.ts
|
|
3912
|
+
function parseChannelFromCanvasId(canvasId) {
|
|
3913
|
+
const match = canvasId.match(/-ch(\d+)-/);
|
|
3914
|
+
return match ? parseInt(match[1], 10) : 0;
|
|
3915
|
+
}
|
|
3916
|
+
function defaultPoolSize() {
|
|
3917
|
+
return 2;
|
|
3918
|
+
}
|
|
3919
|
+
function createSpectrogramWorkerPool(createWorker, poolSize = defaultPoolSize()) {
|
|
3920
|
+
const workers = [];
|
|
3921
|
+
try {
|
|
3922
|
+
for (let i = 0; i < poolSize; i++) {
|
|
3923
|
+
workers.push(createSpectrogramWorker(createWorker()));
|
|
3924
|
+
}
|
|
3925
|
+
} catch (err) {
|
|
3926
|
+
for (const w of workers) {
|
|
3927
|
+
w.terminate();
|
|
3928
|
+
}
|
|
3929
|
+
throw err;
|
|
3930
|
+
}
|
|
3931
|
+
function getWorkerForChannel(channelIndex) {
|
|
3932
|
+
return workers[channelIndex % workers.length];
|
|
3933
|
+
}
|
|
3934
|
+
return {
|
|
3935
|
+
computeFFT(params, generation = 0) {
|
|
3936
|
+
if (params.mono) {
|
|
3937
|
+
return workers[0].computeFFT(params, generation);
|
|
3938
|
+
}
|
|
3939
|
+
const channelCount = params.channelDataArrays.length;
|
|
3940
|
+
const activeWorkers = workers.slice(0, channelCount);
|
|
3941
|
+
const promises = activeWorkers.map(
|
|
3942
|
+
(w, i) => w.computeFFT({ ...params, channelFilter: i }, generation)
|
|
3943
|
+
);
|
|
3944
|
+
return Promise.all(promises).then((results) => results[0]);
|
|
3945
|
+
},
|
|
3946
|
+
renderChunks(params, generation = 0) {
|
|
3947
|
+
const worker = getWorkerForChannel(params.channelIndex);
|
|
3948
|
+
return worker.renderChunks({ ...params, channelIndex: 0 }, generation);
|
|
3949
|
+
},
|
|
3950
|
+
abortGeneration(generation) {
|
|
3951
|
+
for (const w of workers) {
|
|
3952
|
+
w.abortGeneration(generation);
|
|
3953
|
+
}
|
|
3954
|
+
},
|
|
3955
|
+
registerCanvas(canvasId, canvas) {
|
|
3956
|
+
const ch = parseChannelFromCanvasId(canvasId);
|
|
3957
|
+
getWorkerForChannel(ch).registerCanvas(canvasId, canvas);
|
|
3958
|
+
},
|
|
3959
|
+
unregisterCanvas(canvasId) {
|
|
3960
|
+
const ch = parseChannelFromCanvasId(canvasId);
|
|
3961
|
+
getWorkerForChannel(ch).unregisterCanvas(canvasId);
|
|
3962
|
+
},
|
|
3963
|
+
registerAudioData(clipId, channelDataArrays, sampleRate) {
|
|
3964
|
+
for (const w of workers) {
|
|
3965
|
+
w.registerAudioData(clipId, channelDataArrays, sampleRate);
|
|
3966
|
+
}
|
|
3967
|
+
},
|
|
3968
|
+
unregisterAudioData(clipId) {
|
|
3969
|
+
for (const w of workers) {
|
|
3970
|
+
w.unregisterAudioData(clipId);
|
|
3971
|
+
}
|
|
3972
|
+
},
|
|
3973
|
+
terminate() {
|
|
3974
|
+
for (const w of workers) {
|
|
3975
|
+
w.terminate();
|
|
3976
|
+
}
|
|
3977
|
+
}
|
|
3978
|
+
};
|
|
3979
|
+
}
|
|
3980
|
+
|
|
3942
3981
|
// src/SpectrogramProvider.tsx
|
|
3943
3982
|
import { useState as useState2, useEffect as useEffect2, useRef as useRef2, useCallback, useMemo } from "react";
|
|
3944
3983
|
import {
|
|
@@ -3960,13 +3999,11 @@ function extractChunkNumber(canvasId) {
|
|
|
3960
3999
|
var SpectrogramProvider = ({
|
|
3961
4000
|
config: spectrogramConfig,
|
|
3962
4001
|
colorMap: spectrogramColorMap,
|
|
4002
|
+
workerPoolSize,
|
|
3963
4003
|
children
|
|
3964
4004
|
}) => {
|
|
3965
|
-
const { tracks, waveHeight, samplesPerPixel, isReady, mono
|
|
4005
|
+
const { tracks, waveHeight, samplesPerPixel, isReady, mono } = usePlaylistData();
|
|
3966
4006
|
const { scrollContainerRef } = usePlaylistControls();
|
|
3967
|
-
const [spectrogramDataMap, setSpectrogramDataMap] = useState2(
|
|
3968
|
-
/* @__PURE__ */ new Map()
|
|
3969
|
-
);
|
|
3970
4007
|
const [trackSpectrogramOverrides, setTrackSpectrogramOverrides] = useState2(/* @__PURE__ */ new Map());
|
|
3971
4008
|
const spectrogramCanvasRegistryRef = useRef2(/* @__PURE__ */ new Map());
|
|
3972
4009
|
const [spectrogramCanvasVersion, setSpectrogramCanvasVersion] = useState2(0);
|
|
@@ -3976,7 +4013,7 @@ var SpectrogramProvider = ({
|
|
|
3976
4013
|
const spectrogramGenerationRef = useRef2(0);
|
|
3977
4014
|
const prevCanvasVersionRef = useRef2(0);
|
|
3978
4015
|
const [spectrogramWorkerReady, setSpectrogramWorkerReady] = useState2(false);
|
|
3979
|
-
const
|
|
4016
|
+
const renderedClipIdsRef = useRef2(/* @__PURE__ */ new Set());
|
|
3980
4017
|
const backgroundRenderAbortRef = useRef2(null);
|
|
3981
4018
|
const registeredAudioClipIdsRef = useRef2(/* @__PURE__ */ new Set());
|
|
3982
4019
|
useEffect2(() => {
|
|
@@ -3990,15 +4027,19 @@ var SpectrogramProvider = ({
|
|
|
3990
4027
|
let workerApi = spectrogramWorkerRef.current;
|
|
3991
4028
|
if (!workerApi) {
|
|
3992
4029
|
try {
|
|
3993
|
-
|
|
3994
|
-
new
|
|
3995
|
-
|
|
4030
|
+
workerApi = createSpectrogramWorkerPool(
|
|
4031
|
+
() => new Worker(
|
|
4032
|
+
new URL("@waveform-playlist/spectrogram/worker/spectrogram.worker", import.meta.url),
|
|
4033
|
+
{ type: "module" }
|
|
4034
|
+
),
|
|
4035
|
+
workerPoolSize
|
|
3996
4036
|
);
|
|
3997
|
-
workerApi = createSpectrogramWorker(rawWorker);
|
|
3998
4037
|
spectrogramWorkerRef.current = workerApi;
|
|
3999
4038
|
setSpectrogramWorkerReady(true);
|
|
4000
|
-
} catch {
|
|
4001
|
-
console.warn(
|
|
4039
|
+
} catch (err) {
|
|
4040
|
+
console.warn(
|
|
4041
|
+
`[waveform-playlist] Spectrogram Web Worker unavailable for pre-transfer: ${err instanceof Error ? err.message : String(err)}`
|
|
4042
|
+
);
|
|
4002
4043
|
return;
|
|
4003
4044
|
}
|
|
4004
4045
|
}
|
|
@@ -4070,42 +4111,28 @@ var SpectrogramProvider = ({
|
|
|
4070
4111
|
prevSpectrogramConfigRef.current = currentKeys;
|
|
4071
4112
|
prevSpectrogramFFTKeyRef.current = currentFFTKeys;
|
|
4072
4113
|
}
|
|
4073
|
-
if (configChanged) {
|
|
4074
|
-
setSpectrogramDataMap((prevMap) => {
|
|
4075
|
-
const activeClipIds = /* @__PURE__ */ new Set();
|
|
4076
|
-
for (const track of tracks) {
|
|
4077
|
-
const mode = trackSpectrogramOverrides.get(track.id)?.renderMode ?? track.renderMode ?? "waveform";
|
|
4078
|
-
if (mode === "spectrogram" || mode === "both") {
|
|
4079
|
-
for (const clip of track.clips) {
|
|
4080
|
-
activeClipIds.add(clip.id);
|
|
4081
|
-
}
|
|
4082
|
-
}
|
|
4083
|
-
}
|
|
4084
|
-
const newMap = new Map(prevMap);
|
|
4085
|
-
for (const clipId of newMap.keys()) {
|
|
4086
|
-
if (!activeClipIds.has(clipId)) {
|
|
4087
|
-
newMap.delete(clipId);
|
|
4088
|
-
}
|
|
4089
|
-
}
|
|
4090
|
-
return newMap;
|
|
4091
|
-
});
|
|
4092
|
-
}
|
|
4093
4114
|
if (backgroundRenderAbortRef.current) {
|
|
4094
4115
|
backgroundRenderAbortRef.current.aborted = true;
|
|
4095
4116
|
}
|
|
4096
4117
|
const generation = ++spectrogramGenerationRef.current;
|
|
4118
|
+
if (spectrogramWorkerRef.current) {
|
|
4119
|
+
spectrogramWorkerRef.current.abortGeneration(generation);
|
|
4120
|
+
}
|
|
4097
4121
|
let workerApi = spectrogramWorkerRef.current;
|
|
4098
4122
|
if (!workerApi) {
|
|
4099
4123
|
try {
|
|
4100
|
-
|
|
4101
|
-
new
|
|
4102
|
-
|
|
4124
|
+
workerApi = createSpectrogramWorkerPool(
|
|
4125
|
+
() => new Worker(
|
|
4126
|
+
new URL("@waveform-playlist/spectrogram/worker/spectrogram.worker", import.meta.url),
|
|
4127
|
+
{ type: "module" }
|
|
4128
|
+
),
|
|
4129
|
+
workerPoolSize
|
|
4103
4130
|
);
|
|
4104
|
-
workerApi = createSpectrogramWorker(rawWorker);
|
|
4105
4131
|
spectrogramWorkerRef.current = workerApi;
|
|
4106
4132
|
setSpectrogramWorkerReady(true);
|
|
4107
|
-
} catch {
|
|
4108
|
-
console.
|
|
4133
|
+
} catch (err) {
|
|
4134
|
+
console.error(`[waveform-playlist] Spectrogram Web Worker required but unavailable: ${err instanceof Error ? err.message : String(err)}`);
|
|
4135
|
+
return;
|
|
4109
4136
|
}
|
|
4110
4137
|
}
|
|
4111
4138
|
const clipsNeedingFFT = [];
|
|
@@ -4122,11 +4149,19 @@ var SpectrogramProvider = ({
|
|
|
4122
4149
|
for (const clip of track.clips) {
|
|
4123
4150
|
if (!clip.audioBuffer) continue;
|
|
4124
4151
|
const monoFlag = mono || clip.audioBuffer.numberOfChannels === 1;
|
|
4125
|
-
if (!trackFFTChanged && !hasRegisteredCanvases &&
|
|
4152
|
+
if (!trackFFTChanged && !hasRegisteredCanvases && renderedClipIdsRef.current.has(clip.id)) {
|
|
4153
|
+
const channelDataArrays2 = [];
|
|
4154
|
+
for (let ch = 0; ch < clip.audioBuffer.numberOfChannels; ch++) {
|
|
4155
|
+
channelDataArrays2.push(clip.audioBuffer.getChannelData(ch));
|
|
4156
|
+
}
|
|
4126
4157
|
clipsNeedingDisplayOnly.push({
|
|
4127
4158
|
clipId: clip.id,
|
|
4128
4159
|
trackIndex: i,
|
|
4160
|
+
channelDataArrays: channelDataArrays2,
|
|
4129
4161
|
config: cfg,
|
|
4162
|
+
sampleRate: clip.audioBuffer.sampleRate,
|
|
4163
|
+
offsetSamples: clip.offsetSamples,
|
|
4164
|
+
durationSamples: clip.durationSamples,
|
|
4130
4165
|
clipStartSample: clip.startSample,
|
|
4131
4166
|
monoFlag,
|
|
4132
4167
|
colorMap: cm,
|
|
@@ -4153,68 +4188,38 @@ var SpectrogramProvider = ({
|
|
|
4153
4188
|
}
|
|
4154
4189
|
});
|
|
4155
4190
|
if (clipsNeedingFFT.length === 0 && clipsNeedingDisplayOnly.length === 0) return;
|
|
4156
|
-
if (!workerApi) {
|
|
4157
|
-
try {
|
|
4158
|
-
setSpectrogramDataMap((prevMap) => {
|
|
4159
|
-
const newMap = new Map(prevMap);
|
|
4160
|
-
for (const item of clipsNeedingFFT) {
|
|
4161
|
-
const clip = tracks.flatMap((t) => t.clips).find((c) => c.id === item.clipId);
|
|
4162
|
-
if (!clip?.audioBuffer) continue;
|
|
4163
|
-
const channelSpectrograms = [];
|
|
4164
|
-
if (item.monoFlag) {
|
|
4165
|
-
channelSpectrograms.push(
|
|
4166
|
-
computeSpectrogramMono(
|
|
4167
|
-
clip.audioBuffer,
|
|
4168
|
-
item.config,
|
|
4169
|
-
item.offsetSamples,
|
|
4170
|
-
item.durationSamples
|
|
4171
|
-
)
|
|
4172
|
-
);
|
|
4173
|
-
} else {
|
|
4174
|
-
for (let ch = 0; ch < clip.audioBuffer.numberOfChannels; ch++) {
|
|
4175
|
-
channelSpectrograms.push(
|
|
4176
|
-
computeSpectrogram(
|
|
4177
|
-
clip.audioBuffer,
|
|
4178
|
-
item.config,
|
|
4179
|
-
item.offsetSamples,
|
|
4180
|
-
item.durationSamples,
|
|
4181
|
-
ch
|
|
4182
|
-
)
|
|
4183
|
-
);
|
|
4184
|
-
}
|
|
4185
|
-
}
|
|
4186
|
-
newMap.set(item.clipId, channelSpectrograms);
|
|
4187
|
-
}
|
|
4188
|
-
return newMap;
|
|
4189
|
-
});
|
|
4190
|
-
} catch (err) {
|
|
4191
|
-
console.error("[waveform-playlist] Synchronous spectrogram computation failed:", err);
|
|
4192
|
-
}
|
|
4193
|
-
return;
|
|
4194
|
-
}
|
|
4195
4191
|
const getVisibleChunkRange = (channelInfo, clipPixelOffset = 0) => {
|
|
4196
4192
|
const container = scrollContainerRef.current;
|
|
4197
4193
|
if (!container) {
|
|
4198
|
-
return {
|
|
4194
|
+
return {
|
|
4195
|
+
viewportIndices: channelInfo.canvasWidths.map((_, i) => i),
|
|
4196
|
+
bufferIndices: [],
|
|
4197
|
+
remainingIndices: []
|
|
4198
|
+
};
|
|
4199
4199
|
}
|
|
4200
4200
|
const scrollLeft = container.scrollLeft;
|
|
4201
4201
|
const viewportWidth = container.clientWidth;
|
|
4202
|
-
const
|
|
4203
|
-
const
|
|
4202
|
+
const buffer = viewportWidth * 1.5;
|
|
4203
|
+
const bufferStart = Math.max(0, scrollLeft - buffer);
|
|
4204
|
+
const bufferEnd = scrollLeft + viewportWidth + buffer;
|
|
4205
|
+
const viewportIndices = [];
|
|
4206
|
+
const bufferIndices = [];
|
|
4204
4207
|
const remainingIndices = [];
|
|
4205
4208
|
for (let i = 0; i < channelInfo.canvasWidths.length; i++) {
|
|
4206
4209
|
const chunkNumber = extractChunkNumber(channelInfo.canvasIds[i]);
|
|
4207
|
-
const chunkLeft = chunkNumber * MAX_CANVAS_WIDTH +
|
|
4210
|
+
const chunkLeft = chunkNumber * MAX_CANVAS_WIDTH + clipPixelOffset;
|
|
4208
4211
|
const chunkRight = chunkLeft + channelInfo.canvasWidths[i];
|
|
4209
4212
|
if (chunkRight > scrollLeft && chunkLeft < scrollLeft + viewportWidth) {
|
|
4210
|
-
|
|
4213
|
+
viewportIndices.push(i);
|
|
4214
|
+
} else if (chunkRight > bufferStart && chunkLeft < bufferEnd) {
|
|
4215
|
+
bufferIndices.push(i);
|
|
4211
4216
|
} else {
|
|
4212
4217
|
remainingIndices.push(i);
|
|
4213
4218
|
}
|
|
4214
4219
|
}
|
|
4215
|
-
return {
|
|
4220
|
+
return { viewportIndices, bufferIndices, remainingIndices };
|
|
4216
4221
|
};
|
|
4217
|
-
const renderChunkSubset = async (api, cacheKey, channelInfo, indices, item, channelIndex) => {
|
|
4222
|
+
const renderChunkSubset = async (api, cacheKey, channelInfo, indices, item, channelIndex, gen) => {
|
|
4218
4223
|
if (indices.length === 0) return;
|
|
4219
4224
|
const canvasIds = indices.map((i) => channelInfo.canvasIds[i]);
|
|
4220
4225
|
const canvasWidths = indices.map((i) => channelInfo.canvasWidths[i]);
|
|
@@ -4224,41 +4229,117 @@ var SpectrogramProvider = ({
|
|
|
4224
4229
|
globalPixelOffsets.push(chunkNumber * MAX_CANVAS_WIDTH);
|
|
4225
4230
|
}
|
|
4226
4231
|
const colorLUT = getColorMap(item.colorMap);
|
|
4227
|
-
await api.renderChunks(
|
|
4228
|
-
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4232
|
+
await api.renderChunks(
|
|
4233
|
+
{
|
|
4234
|
+
cacheKey,
|
|
4235
|
+
canvasIds,
|
|
4236
|
+
canvasWidths,
|
|
4237
|
+
globalPixelOffsets,
|
|
4238
|
+
canvasHeight: waveHeight,
|
|
4239
|
+
devicePixelRatio: typeof window !== "undefined" ? window.devicePixelRatio : 1,
|
|
4240
|
+
samplesPerPixel,
|
|
4241
|
+
colorLUT,
|
|
4242
|
+
frequencyScale: item.config.frequencyScale ?? "mel",
|
|
4243
|
+
minFrequency: item.config.minFrequency ?? 0,
|
|
4244
|
+
maxFrequency: item.config.maxFrequency ?? 0,
|
|
4245
|
+
gainDb: item.config.gainDb ?? 20,
|
|
4246
|
+
rangeDb: item.config.rangeDb ?? 80,
|
|
4247
|
+
channelIndex
|
|
4248
|
+
},
|
|
4249
|
+
gen
|
|
4250
|
+
);
|
|
4251
|
+
};
|
|
4252
|
+
const computeFFTForChunks = async (api, channelInfo, indices, item, gen) => {
|
|
4253
|
+
const chunkNumbers = indices.map((i) => extractChunkNumber(channelInfo.canvasIds[i]));
|
|
4254
|
+
const minChunk = Math.min(...chunkNumbers);
|
|
4255
|
+
const maxChunk = Math.max(...chunkNumbers);
|
|
4256
|
+
const maxChunkIdx = indices[chunkNumbers.indexOf(maxChunk)];
|
|
4257
|
+
const lastChunkWidth = channelInfo.canvasWidths[maxChunkIdx];
|
|
4258
|
+
const startPx = minChunk * MAX_CANVAS_WIDTH;
|
|
4259
|
+
const endPx = maxChunk * MAX_CANVAS_WIDTH + lastChunkWidth;
|
|
4260
|
+
const windowSize = item.config.fftSize ?? 2048;
|
|
4261
|
+
const rangeStartSample = item.offsetSamples + Math.floor(startPx * samplesPerPixel);
|
|
4262
|
+
const rangeEndSample = Math.min(
|
|
4263
|
+
item.offsetSamples + item.durationSamples,
|
|
4264
|
+
item.offsetSamples + Math.ceil(endPx * samplesPerPixel)
|
|
4265
|
+
);
|
|
4266
|
+
const paddedStart = Math.max(item.offsetSamples, rangeStartSample - windowSize);
|
|
4267
|
+
const paddedEnd = Math.min(
|
|
4268
|
+
item.offsetSamples + item.durationSamples,
|
|
4269
|
+
rangeEndSample + windowSize
|
|
4270
|
+
);
|
|
4271
|
+
const { cacheKey } = await api.computeFFT(
|
|
4272
|
+
{
|
|
4273
|
+
clipId: item.clipId,
|
|
4274
|
+
channelDataArrays: item.channelDataArrays,
|
|
4275
|
+
config: item.config,
|
|
4276
|
+
sampleRate: item.sampleRate,
|
|
4277
|
+
offsetSamples: item.offsetSamples,
|
|
4278
|
+
durationSamples: item.durationSamples,
|
|
4279
|
+
mono: item.monoFlag,
|
|
4280
|
+
sampleRange: { start: paddedStart, end: paddedEnd }
|
|
4281
|
+
},
|
|
4282
|
+
gen
|
|
4283
|
+
);
|
|
4284
|
+
return cacheKey;
|
|
4285
|
+
};
|
|
4286
|
+
const groupContiguousIndices = (channelInfo, indices) => {
|
|
4287
|
+
if (indices.length === 0) return [];
|
|
4288
|
+
const groups = [];
|
|
4289
|
+
let currentGroup = [indices[0]];
|
|
4290
|
+
let prevChunk = extractChunkNumber(channelInfo.canvasIds[indices[0]]);
|
|
4291
|
+
for (let i = 1; i < indices.length; i++) {
|
|
4292
|
+
const chunk = extractChunkNumber(channelInfo.canvasIds[indices[i]]);
|
|
4293
|
+
if (chunk === prevChunk + 1) {
|
|
4294
|
+
currentGroup.push(indices[i]);
|
|
4295
|
+
} else {
|
|
4296
|
+
groups.push(currentGroup);
|
|
4297
|
+
currentGroup = [indices[i]];
|
|
4298
|
+
}
|
|
4299
|
+
prevChunk = chunk;
|
|
4300
|
+
}
|
|
4301
|
+
groups.push(currentGroup);
|
|
4302
|
+
return groups;
|
|
4243
4303
|
};
|
|
4244
4304
|
const computeAsync = async () => {
|
|
4245
4305
|
const abortToken = { aborted: false };
|
|
4246
4306
|
backgroundRenderAbortRef.current = abortToken;
|
|
4247
|
-
const renderBackgroundBatches = async (channelRanges,
|
|
4248
|
-
const
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
}
|
|
4307
|
+
const renderBackgroundBatches = async (channelRanges, item) => {
|
|
4308
|
+
const allGroups = [];
|
|
4309
|
+
if (channelRanges.length > 0) {
|
|
4310
|
+
const { channelInfo, remainingIndices } = channelRanges[0];
|
|
4311
|
+
const groups = groupContiguousIndices(channelInfo, remainingIndices);
|
|
4312
|
+
for (const group of groups) {
|
|
4313
|
+
allGroups.push({
|
|
4314
|
+
group,
|
|
4315
|
+
channelRangeEntries: channelRanges.map(({ ch, channelInfo: ci }) => ({
|
|
4316
|
+
ch,
|
|
4317
|
+
channelInfo: ci
|
|
4318
|
+
}))
|
|
4259
4319
|
});
|
|
4320
|
+
}
|
|
4321
|
+
}
|
|
4322
|
+
for (const { group, channelRangeEntries } of allGroups) {
|
|
4323
|
+
if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return true;
|
|
4324
|
+
await new Promise((resolve) => {
|
|
4325
|
+
if (typeof requestIdleCallback === "function") {
|
|
4326
|
+
requestIdleCallback(() => resolve());
|
|
4327
|
+
} else {
|
|
4328
|
+
setTimeout(resolve, 0);
|
|
4329
|
+
}
|
|
4330
|
+
});
|
|
4331
|
+
if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return true;
|
|
4332
|
+
const { channelInfo: firstChannelInfo } = channelRangeEntries[0];
|
|
4333
|
+
const cacheKey = await computeFFTForChunks(
|
|
4334
|
+
workerApi,
|
|
4335
|
+
firstChannelInfo,
|
|
4336
|
+
group,
|
|
4337
|
+
item,
|
|
4338
|
+
generation
|
|
4339
|
+
);
|
|
4340
|
+
for (const { ch, channelInfo: ci } of channelRangeEntries) {
|
|
4260
4341
|
if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return true;
|
|
4261
|
-
await renderChunkSubset(workerApi, cacheKey,
|
|
4342
|
+
await renderChunkSubset(workerApi, cacheKey, ci, group, item, ch, generation);
|
|
4262
4343
|
}
|
|
4263
4344
|
}
|
|
4264
4345
|
return false;
|
|
@@ -4270,117 +4351,76 @@ var SpectrogramProvider = ({
|
|
|
4270
4351
|
if (clipCanvasInfo && clipCanvasInfo.size > 0) {
|
|
4271
4352
|
const numChannels = item.monoFlag ? 1 : item.channelDataArrays.length;
|
|
4272
4353
|
const clipPixelOffset = Math.floor(item.clipStartSample / samplesPerPixel);
|
|
4273
|
-
const
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4277
|
-
const
|
|
4278
|
-
|
|
4279
|
-
const controlWidth = controls.show ? controls.width : 0;
|
|
4280
|
-
const vpStartPx = Math.max(0, scrollLeft - controlWidth);
|
|
4281
|
-
const vpEndPx = vpStartPx + viewportWidth;
|
|
4282
|
-
const clipStartPx = clipPixelOffset;
|
|
4283
|
-
const clipEndPx = clipStartPx + Math.ceil(item.durationSamples / samplesPerPixel);
|
|
4284
|
-
const overlapStartPx = Math.max(vpStartPx, clipStartPx);
|
|
4285
|
-
const overlapEndPx = Math.min(vpEndPx, clipEndPx);
|
|
4286
|
-
if (overlapEndPx > overlapStartPx) {
|
|
4287
|
-
const localStartPx = overlapStartPx - clipStartPx;
|
|
4288
|
-
const localEndPx = overlapEndPx - clipStartPx;
|
|
4289
|
-
const visStartSample = item.offsetSamples + Math.floor(localStartPx * samplesPerPixel);
|
|
4290
|
-
const visEndSample = Math.min(
|
|
4291
|
-
item.offsetSamples + item.durationSamples,
|
|
4292
|
-
item.offsetSamples + Math.ceil(localEndPx * samplesPerPixel)
|
|
4293
|
-
);
|
|
4294
|
-
const paddedStart = Math.max(item.offsetSamples, visStartSample - windowSize);
|
|
4295
|
-
const paddedEnd = Math.min(
|
|
4296
|
-
item.offsetSamples + item.durationSamples,
|
|
4297
|
-
visEndSample + windowSize
|
|
4298
|
-
);
|
|
4299
|
-
if (paddedEnd - paddedStart < item.durationSamples * 0.8) {
|
|
4300
|
-
visibleRange = { start: paddedStart, end: paddedEnd };
|
|
4301
|
-
}
|
|
4302
|
-
}
|
|
4354
|
+
const channelRanges = [];
|
|
4355
|
+
for (let ch = 0; ch < numChannels; ch++) {
|
|
4356
|
+
const channelInfo = clipCanvasInfo.get(ch);
|
|
4357
|
+
if (!channelInfo) continue;
|
|
4358
|
+
const range = getVisibleChunkRange(channelInfo, clipPixelOffset);
|
|
4359
|
+
channelRanges.push({ ch, channelInfo, ...range });
|
|
4303
4360
|
}
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
durationSamples: item.durationSamples,
|
|
4313
|
-
mono: item.monoFlag,
|
|
4314
|
-
sampleRange: visibleRange
|
|
4315
|
-
});
|
|
4361
|
+
if (channelRanges.length > 0 && channelRanges[0].viewportIndices.length > 0) {
|
|
4362
|
+
const cacheKey = await computeFFTForChunks(
|
|
4363
|
+
workerApi,
|
|
4364
|
+
channelRanges[0].channelInfo,
|
|
4365
|
+
channelRanges[0].viewportIndices,
|
|
4366
|
+
item,
|
|
4367
|
+
generation
|
|
4368
|
+
);
|
|
4316
4369
|
if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;
|
|
4317
|
-
for (
|
|
4318
|
-
const channelInfo = clipCanvasInfo.get(ch);
|
|
4319
|
-
if (!channelInfo) continue;
|
|
4320
|
-
const { visibleIndices } = getVisibleChunkRange(channelInfo, clipPixelOffset);
|
|
4370
|
+
for (const { ch, channelInfo, viewportIndices } of channelRanges) {
|
|
4321
4371
|
await renderChunkSubset(
|
|
4322
4372
|
workerApi,
|
|
4323
|
-
|
|
4373
|
+
cacheKey,
|
|
4324
4374
|
channelInfo,
|
|
4325
|
-
|
|
4375
|
+
viewportIndices,
|
|
4326
4376
|
item,
|
|
4327
|
-
ch
|
|
4377
|
+
ch,
|
|
4378
|
+
generation
|
|
4328
4379
|
);
|
|
4329
4380
|
}
|
|
4330
|
-
if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;
|
|
4331
4381
|
}
|
|
4332
|
-
const { cacheKey } = await workerApi.computeFFT({
|
|
4333
|
-
clipId: item.clipId,
|
|
4334
|
-
channelDataArrays: item.channelDataArrays,
|
|
4335
|
-
config: item.config,
|
|
4336
|
-
sampleRate: item.sampleRate,
|
|
4337
|
-
offsetSamples: item.offsetSamples,
|
|
4338
|
-
durationSamples: item.durationSamples,
|
|
4339
|
-
mono: item.monoFlag
|
|
4340
|
-
});
|
|
4341
4382
|
if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
if (!channelInfo) continue;
|
|
4347
|
-
const range = getVisibleChunkRange(channelInfo, clipPixelOffset);
|
|
4348
|
-
channelRanges.push({ ch, channelInfo, ...range });
|
|
4349
|
-
await renderChunkSubset(
|
|
4350
|
-
workerApi,
|
|
4351
|
-
cacheKey,
|
|
4352
|
-
channelInfo,
|
|
4353
|
-
range.visibleIndices,
|
|
4354
|
-
item,
|
|
4355
|
-
ch
|
|
4383
|
+
if (channelRanges.length > 0 && channelRanges[0].bufferIndices.length > 0) {
|
|
4384
|
+
const bufferGroups = groupContiguousIndices(
|
|
4385
|
+
channelRanges[0].channelInfo,
|
|
4386
|
+
channelRanges[0].bufferIndices
|
|
4356
4387
|
);
|
|
4388
|
+
for (const group of bufferGroups) {
|
|
4389
|
+
if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;
|
|
4390
|
+
const cacheKey = await computeFFTForChunks(
|
|
4391
|
+
workerApi,
|
|
4392
|
+
channelRanges[0].channelInfo,
|
|
4393
|
+
group,
|
|
4394
|
+
item,
|
|
4395
|
+
generation
|
|
4396
|
+
);
|
|
4397
|
+
if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;
|
|
4398
|
+
for (const { ch, channelInfo } of channelRanges) {
|
|
4399
|
+
await renderChunkSubset(
|
|
4400
|
+
workerApi,
|
|
4401
|
+
cacheKey,
|
|
4402
|
+
channelInfo,
|
|
4403
|
+
group,
|
|
4404
|
+
item,
|
|
4405
|
+
ch,
|
|
4406
|
+
generation
|
|
4407
|
+
);
|
|
4408
|
+
}
|
|
4409
|
+
}
|
|
4357
4410
|
}
|
|
4411
|
+
renderedClipIdsRef.current.add(item.clipId);
|
|
4358
4412
|
if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;
|
|
4359
|
-
if (await renderBackgroundBatches(channelRanges,
|
|
4360
|
-
} else {
|
|
4361
|
-
const spectrograms = await workerApi.compute({
|
|
4362
|
-
channelDataArrays: item.channelDataArrays,
|
|
4363
|
-
config: item.config,
|
|
4364
|
-
sampleRate: item.sampleRate,
|
|
4365
|
-
offsetSamples: item.offsetSamples,
|
|
4366
|
-
durationSamples: item.durationSamples,
|
|
4367
|
-
mono: item.monoFlag
|
|
4368
|
-
});
|
|
4369
|
-
if (spectrogramGenerationRef.current !== generation) return;
|
|
4370
|
-
setSpectrogramDataMap((prevMap) => {
|
|
4371
|
-
const newMap = new Map(prevMap);
|
|
4372
|
-
newMap.set(item.clipId, spectrograms);
|
|
4373
|
-
return newMap;
|
|
4374
|
-
});
|
|
4413
|
+
if (await renderBackgroundBatches(channelRanges, item)) return;
|
|
4375
4414
|
}
|
|
4376
4415
|
} catch (err) {
|
|
4377
|
-
|
|
4416
|
+
if (err instanceof SpectrogramAbortError) return;
|
|
4417
|
+
console.warn(
|
|
4418
|
+
`[waveform-playlist] Spectrogram worker error for clip ${item.clipId}: ${err instanceof Error ? err.message : String(err)}`
|
|
4419
|
+
);
|
|
4378
4420
|
}
|
|
4379
4421
|
}
|
|
4380
4422
|
for (const item of clipsNeedingDisplayOnly) {
|
|
4381
4423
|
if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;
|
|
4382
|
-
const cacheKey = clipCacheKeysRef.current.get(item.clipId);
|
|
4383
|
-
if (!cacheKey) continue;
|
|
4384
4424
|
const clipCanvasInfo = spectrogramCanvasRegistryRef.current.get(item.clipId);
|
|
4385
4425
|
if (!clipCanvasInfo || clipCanvasInfo.size === 0) continue;
|
|
4386
4426
|
try {
|
|
@@ -4389,22 +4429,71 @@ var SpectrogramProvider = ({
|
|
|
4389
4429
|
for (let ch = 0; ch < item.numChannels; ch++) {
|
|
4390
4430
|
const channelInfo = clipCanvasInfo.get(ch);
|
|
4391
4431
|
if (!channelInfo) continue;
|
|
4392
|
-
const
|
|
4393
|
-
|
|
4394
|
-
|
|
4432
|
+
const range = getVisibleChunkRange(channelInfo, clipPixelOffset);
|
|
4433
|
+
channelRanges.push({ ch, channelInfo, ...range });
|
|
4434
|
+
}
|
|
4435
|
+
if (channelRanges.length > 0 && channelRanges[0].viewportIndices.length > 0) {
|
|
4436
|
+
const cacheKey = await computeFFTForChunks(
|
|
4437
|
+
workerApi,
|
|
4438
|
+
channelRanges[0].channelInfo,
|
|
4439
|
+
channelRanges[0].viewportIndices,
|
|
4440
|
+
item,
|
|
4441
|
+
generation
|
|
4442
|
+
);
|
|
4443
|
+
if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;
|
|
4444
|
+
for (const { ch, channelInfo, viewportIndices } of channelRanges) {
|
|
4445
|
+
await renderChunkSubset(
|
|
4446
|
+
workerApi,
|
|
4447
|
+
cacheKey,
|
|
4448
|
+
channelInfo,
|
|
4449
|
+
viewportIndices,
|
|
4450
|
+
item,
|
|
4451
|
+
ch,
|
|
4452
|
+
generation
|
|
4453
|
+
);
|
|
4454
|
+
}
|
|
4455
|
+
}
|
|
4456
|
+
if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;
|
|
4457
|
+
if (channelRanges.length > 0 && channelRanges[0].bufferIndices.length > 0) {
|
|
4458
|
+
const bufferGroups = groupContiguousIndices(
|
|
4459
|
+
channelRanges[0].channelInfo,
|
|
4460
|
+
channelRanges[0].bufferIndices
|
|
4395
4461
|
);
|
|
4396
|
-
|
|
4397
|
-
|
|
4462
|
+
for (const group of bufferGroups) {
|
|
4463
|
+
if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;
|
|
4464
|
+
const cacheKey = await computeFFTForChunks(
|
|
4465
|
+
workerApi,
|
|
4466
|
+
channelRanges[0].channelInfo,
|
|
4467
|
+
group,
|
|
4468
|
+
item,
|
|
4469
|
+
generation
|
|
4470
|
+
);
|
|
4471
|
+
if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;
|
|
4472
|
+
for (const { ch, channelInfo } of channelRanges) {
|
|
4473
|
+
await renderChunkSubset(
|
|
4474
|
+
workerApi,
|
|
4475
|
+
cacheKey,
|
|
4476
|
+
channelInfo,
|
|
4477
|
+
group,
|
|
4478
|
+
item,
|
|
4479
|
+
ch,
|
|
4480
|
+
generation
|
|
4481
|
+
);
|
|
4482
|
+
}
|
|
4483
|
+
}
|
|
4398
4484
|
}
|
|
4399
4485
|
if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;
|
|
4400
|
-
if (await renderBackgroundBatches(channelRanges,
|
|
4486
|
+
if (await renderBackgroundBatches(channelRanges, item)) return;
|
|
4401
4487
|
} catch (err) {
|
|
4402
|
-
|
|
4488
|
+
if (err instanceof SpectrogramAbortError) return;
|
|
4489
|
+
console.warn(
|
|
4490
|
+
`[waveform-playlist] Spectrogram display re-render error for clip ${item.clipId}: ${err instanceof Error ? err.message : String(err)}`
|
|
4491
|
+
);
|
|
4403
4492
|
}
|
|
4404
4493
|
}
|
|
4405
4494
|
};
|
|
4406
4495
|
computeAsync().catch((err) => {
|
|
4407
|
-
console.error(
|
|
4496
|
+
console.error(`[waveform-playlist] Spectrogram computation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
4408
4497
|
});
|
|
4409
4498
|
}, [
|
|
4410
4499
|
tracks,
|
|
@@ -4415,7 +4504,6 @@ var SpectrogramProvider = ({
|
|
|
4415
4504
|
waveHeight,
|
|
4416
4505
|
samplesPerPixel,
|
|
4417
4506
|
spectrogramCanvasVersion,
|
|
4418
|
-
controls,
|
|
4419
4507
|
scrollContainerRef
|
|
4420
4508
|
]);
|
|
4421
4509
|
const setTrackRenderMode = useCallback((trackId, mode) => {
|
|
@@ -4475,7 +4563,6 @@ var SpectrogramProvider = ({
|
|
|
4475
4563
|
);
|
|
4476
4564
|
const value = useMemo(
|
|
4477
4565
|
() => ({
|
|
4478
|
-
spectrogramDataMap,
|
|
4479
4566
|
trackSpectrogramOverrides,
|
|
4480
4567
|
spectrogramWorkerApi: spectrogramWorkerReady ? spectrogramWorkerRef.current : null,
|
|
4481
4568
|
spectrogramConfig,
|
|
@@ -4490,7 +4577,6 @@ var SpectrogramProvider = ({
|
|
|
4490
4577
|
getFrequencyScale
|
|
4491
4578
|
}),
|
|
4492
4579
|
[
|
|
4493
|
-
spectrogramDataMap,
|
|
4494
4580
|
trackSpectrogramOverrides,
|
|
4495
4581
|
spectrogramWorkerReady,
|
|
4496
4582
|
spectrogramConfig,
|
|
@@ -4505,12 +4591,14 @@ var SpectrogramProvider = ({
|
|
|
4505
4591
|
return /* @__PURE__ */ jsx3(SpectrogramIntegrationProvider, { value, children });
|
|
4506
4592
|
};
|
|
4507
4593
|
export {
|
|
4594
|
+
SpectrogramAbortError,
|
|
4508
4595
|
SpectrogramMenuItems,
|
|
4509
4596
|
SpectrogramProvider,
|
|
4510
4597
|
SpectrogramSettingsModal,
|
|
4511
4598
|
computeSpectrogram,
|
|
4512
4599
|
computeSpectrogramMono,
|
|
4513
4600
|
createSpectrogramWorker,
|
|
4601
|
+
createSpectrogramWorkerPool,
|
|
4514
4602
|
getColorMap,
|
|
4515
4603
|
getFrequencyScale
|
|
4516
4604
|
};
|