@waveform-playlist/spectrogram 9.5.0 → 9.5.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/dist/index.d.mts +16 -25
- package/dist/index.d.ts +16 -25
- package/dist/index.js +360 -266
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +358 -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,30 @@ 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(
|
|
4135
|
+
`[waveform-playlist] Spectrogram Web Worker required but unavailable: ${err instanceof Error ? err.message : String(err)}`
|
|
4136
|
+
);
|
|
4137
|
+
return;
|
|
4109
4138
|
}
|
|
4110
4139
|
}
|
|
4111
4140
|
const clipsNeedingFFT = [];
|
|
@@ -4122,11 +4151,19 @@ var SpectrogramProvider = ({
|
|
|
4122
4151
|
for (const clip of track.clips) {
|
|
4123
4152
|
if (!clip.audioBuffer) continue;
|
|
4124
4153
|
const monoFlag = mono || clip.audioBuffer.numberOfChannels === 1;
|
|
4125
|
-
if (!trackFFTChanged && !hasRegisteredCanvases &&
|
|
4154
|
+
if (!trackFFTChanged && !hasRegisteredCanvases && renderedClipIdsRef.current.has(clip.id)) {
|
|
4155
|
+
const channelDataArrays2 = [];
|
|
4156
|
+
for (let ch = 0; ch < clip.audioBuffer.numberOfChannels; ch++) {
|
|
4157
|
+
channelDataArrays2.push(clip.audioBuffer.getChannelData(ch));
|
|
4158
|
+
}
|
|
4126
4159
|
clipsNeedingDisplayOnly.push({
|
|
4127
4160
|
clipId: clip.id,
|
|
4128
4161
|
trackIndex: i,
|
|
4162
|
+
channelDataArrays: channelDataArrays2,
|
|
4129
4163
|
config: cfg,
|
|
4164
|
+
sampleRate: clip.audioBuffer.sampleRate,
|
|
4165
|
+
offsetSamples: clip.offsetSamples,
|
|
4166
|
+
durationSamples: clip.durationSamples,
|
|
4130
4167
|
clipStartSample: clip.startSample,
|
|
4131
4168
|
monoFlag,
|
|
4132
4169
|
colorMap: cm,
|
|
@@ -4153,68 +4190,38 @@ var SpectrogramProvider = ({
|
|
|
4153
4190
|
}
|
|
4154
4191
|
});
|
|
4155
4192
|
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
4193
|
const getVisibleChunkRange = (channelInfo, clipPixelOffset = 0) => {
|
|
4196
4194
|
const container = scrollContainerRef.current;
|
|
4197
4195
|
if (!container) {
|
|
4198
|
-
return {
|
|
4196
|
+
return {
|
|
4197
|
+
viewportIndices: channelInfo.canvasWidths.map((_, i) => i),
|
|
4198
|
+
bufferIndices: [],
|
|
4199
|
+
remainingIndices: []
|
|
4200
|
+
};
|
|
4199
4201
|
}
|
|
4200
4202
|
const scrollLeft = container.scrollLeft;
|
|
4201
4203
|
const viewportWidth = container.clientWidth;
|
|
4202
|
-
const
|
|
4203
|
-
const
|
|
4204
|
+
const buffer = viewportWidth * 1.5;
|
|
4205
|
+
const bufferStart = Math.max(0, scrollLeft - buffer);
|
|
4206
|
+
const bufferEnd = scrollLeft + viewportWidth + buffer;
|
|
4207
|
+
const viewportIndices = [];
|
|
4208
|
+
const bufferIndices = [];
|
|
4204
4209
|
const remainingIndices = [];
|
|
4205
4210
|
for (let i = 0; i < channelInfo.canvasWidths.length; i++) {
|
|
4206
4211
|
const chunkNumber = extractChunkNumber(channelInfo.canvasIds[i]);
|
|
4207
|
-
const chunkLeft = chunkNumber * MAX_CANVAS_WIDTH +
|
|
4212
|
+
const chunkLeft = chunkNumber * MAX_CANVAS_WIDTH + clipPixelOffset;
|
|
4208
4213
|
const chunkRight = chunkLeft + channelInfo.canvasWidths[i];
|
|
4209
4214
|
if (chunkRight > scrollLeft && chunkLeft < scrollLeft + viewportWidth) {
|
|
4210
|
-
|
|
4215
|
+
viewportIndices.push(i);
|
|
4216
|
+
} else if (chunkRight > bufferStart && chunkLeft < bufferEnd) {
|
|
4217
|
+
bufferIndices.push(i);
|
|
4211
4218
|
} else {
|
|
4212
4219
|
remainingIndices.push(i);
|
|
4213
4220
|
}
|
|
4214
4221
|
}
|
|
4215
|
-
return {
|
|
4222
|
+
return { viewportIndices, bufferIndices, remainingIndices };
|
|
4216
4223
|
};
|
|
4217
|
-
const renderChunkSubset = async (api, cacheKey, channelInfo, indices, item, channelIndex) => {
|
|
4224
|
+
const renderChunkSubset = async (api, cacheKey, channelInfo, indices, item, channelIndex, gen) => {
|
|
4218
4225
|
if (indices.length === 0) return;
|
|
4219
4226
|
const canvasIds = indices.map((i) => channelInfo.canvasIds[i]);
|
|
4220
4227
|
const canvasWidths = indices.map((i) => channelInfo.canvasWidths[i]);
|
|
@@ -4224,41 +4231,117 @@ var SpectrogramProvider = ({
|
|
|
4224
4231
|
globalPixelOffsets.push(chunkNumber * MAX_CANVAS_WIDTH);
|
|
4225
4232
|
}
|
|
4226
4233
|
const colorLUT = getColorMap(item.colorMap);
|
|
4227
|
-
await api.renderChunks(
|
|
4228
|
-
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4234
|
+
await api.renderChunks(
|
|
4235
|
+
{
|
|
4236
|
+
cacheKey,
|
|
4237
|
+
canvasIds,
|
|
4238
|
+
canvasWidths,
|
|
4239
|
+
globalPixelOffsets,
|
|
4240
|
+
canvasHeight: waveHeight,
|
|
4241
|
+
devicePixelRatio: typeof window !== "undefined" ? window.devicePixelRatio : 1,
|
|
4242
|
+
samplesPerPixel,
|
|
4243
|
+
colorLUT,
|
|
4244
|
+
frequencyScale: item.config.frequencyScale ?? "mel",
|
|
4245
|
+
minFrequency: item.config.minFrequency ?? 0,
|
|
4246
|
+
maxFrequency: item.config.maxFrequency ?? 0,
|
|
4247
|
+
gainDb: item.config.gainDb ?? 20,
|
|
4248
|
+
rangeDb: item.config.rangeDb ?? 80,
|
|
4249
|
+
channelIndex
|
|
4250
|
+
},
|
|
4251
|
+
gen
|
|
4252
|
+
);
|
|
4253
|
+
};
|
|
4254
|
+
const computeFFTForChunks = async (api, channelInfo, indices, item, gen) => {
|
|
4255
|
+
const chunkNumbers = indices.map((i) => extractChunkNumber(channelInfo.canvasIds[i]));
|
|
4256
|
+
const minChunk = Math.min(...chunkNumbers);
|
|
4257
|
+
const maxChunk = Math.max(...chunkNumbers);
|
|
4258
|
+
const maxChunkIdx = indices[chunkNumbers.indexOf(maxChunk)];
|
|
4259
|
+
const lastChunkWidth = channelInfo.canvasWidths[maxChunkIdx];
|
|
4260
|
+
const startPx = minChunk * MAX_CANVAS_WIDTH;
|
|
4261
|
+
const endPx = maxChunk * MAX_CANVAS_WIDTH + lastChunkWidth;
|
|
4262
|
+
const windowSize = item.config.fftSize ?? 2048;
|
|
4263
|
+
const rangeStartSample = item.offsetSamples + Math.floor(startPx * samplesPerPixel);
|
|
4264
|
+
const rangeEndSample = Math.min(
|
|
4265
|
+
item.offsetSamples + item.durationSamples,
|
|
4266
|
+
item.offsetSamples + Math.ceil(endPx * samplesPerPixel)
|
|
4267
|
+
);
|
|
4268
|
+
const paddedStart = Math.max(item.offsetSamples, rangeStartSample - windowSize);
|
|
4269
|
+
const paddedEnd = Math.min(
|
|
4270
|
+
item.offsetSamples + item.durationSamples,
|
|
4271
|
+
rangeEndSample + windowSize
|
|
4272
|
+
);
|
|
4273
|
+
const { cacheKey } = await api.computeFFT(
|
|
4274
|
+
{
|
|
4275
|
+
clipId: item.clipId,
|
|
4276
|
+
channelDataArrays: item.channelDataArrays,
|
|
4277
|
+
config: item.config,
|
|
4278
|
+
sampleRate: item.sampleRate,
|
|
4279
|
+
offsetSamples: item.offsetSamples,
|
|
4280
|
+
durationSamples: item.durationSamples,
|
|
4281
|
+
mono: item.monoFlag,
|
|
4282
|
+
sampleRange: { start: paddedStart, end: paddedEnd }
|
|
4283
|
+
},
|
|
4284
|
+
gen
|
|
4285
|
+
);
|
|
4286
|
+
return cacheKey;
|
|
4287
|
+
};
|
|
4288
|
+
const groupContiguousIndices = (channelInfo, indices) => {
|
|
4289
|
+
if (indices.length === 0) return [];
|
|
4290
|
+
const groups = [];
|
|
4291
|
+
let currentGroup = [indices[0]];
|
|
4292
|
+
let prevChunk = extractChunkNumber(channelInfo.canvasIds[indices[0]]);
|
|
4293
|
+
for (let i = 1; i < indices.length; i++) {
|
|
4294
|
+
const chunk = extractChunkNumber(channelInfo.canvasIds[indices[i]]);
|
|
4295
|
+
if (chunk === prevChunk + 1) {
|
|
4296
|
+
currentGroup.push(indices[i]);
|
|
4297
|
+
} else {
|
|
4298
|
+
groups.push(currentGroup);
|
|
4299
|
+
currentGroup = [indices[i]];
|
|
4300
|
+
}
|
|
4301
|
+
prevChunk = chunk;
|
|
4302
|
+
}
|
|
4303
|
+
groups.push(currentGroup);
|
|
4304
|
+
return groups;
|
|
4243
4305
|
};
|
|
4244
4306
|
const computeAsync = async () => {
|
|
4245
4307
|
const abortToken = { aborted: false };
|
|
4246
4308
|
backgroundRenderAbortRef.current = abortToken;
|
|
4247
|
-
const renderBackgroundBatches = async (channelRanges,
|
|
4248
|
-
const
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
}
|
|
4309
|
+
const renderBackgroundBatches = async (channelRanges, item) => {
|
|
4310
|
+
const allGroups = [];
|
|
4311
|
+
if (channelRanges.length > 0) {
|
|
4312
|
+
const { channelInfo, remainingIndices } = channelRanges[0];
|
|
4313
|
+
const groups = groupContiguousIndices(channelInfo, remainingIndices);
|
|
4314
|
+
for (const group of groups) {
|
|
4315
|
+
allGroups.push({
|
|
4316
|
+
group,
|
|
4317
|
+
channelRangeEntries: channelRanges.map(({ ch, channelInfo: ci }) => ({
|
|
4318
|
+
ch,
|
|
4319
|
+
channelInfo: ci
|
|
4320
|
+
}))
|
|
4259
4321
|
});
|
|
4322
|
+
}
|
|
4323
|
+
}
|
|
4324
|
+
for (const { group, channelRangeEntries } of allGroups) {
|
|
4325
|
+
if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return true;
|
|
4326
|
+
await new Promise((resolve) => {
|
|
4327
|
+
if (typeof requestIdleCallback === "function") {
|
|
4328
|
+
requestIdleCallback(() => resolve());
|
|
4329
|
+
} else {
|
|
4330
|
+
setTimeout(resolve, 0);
|
|
4331
|
+
}
|
|
4332
|
+
});
|
|
4333
|
+
if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return true;
|
|
4334
|
+
const { channelInfo: firstChannelInfo } = channelRangeEntries[0];
|
|
4335
|
+
const cacheKey = await computeFFTForChunks(
|
|
4336
|
+
workerApi,
|
|
4337
|
+
firstChannelInfo,
|
|
4338
|
+
group,
|
|
4339
|
+
item,
|
|
4340
|
+
generation
|
|
4341
|
+
);
|
|
4342
|
+
for (const { ch, channelInfo: ci } of channelRangeEntries) {
|
|
4260
4343
|
if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return true;
|
|
4261
|
-
await renderChunkSubset(workerApi, cacheKey,
|
|
4344
|
+
await renderChunkSubset(workerApi, cacheKey, ci, group, item, ch, generation);
|
|
4262
4345
|
}
|
|
4263
4346
|
}
|
|
4264
4347
|
return false;
|
|
@@ -4270,117 +4353,76 @@ var SpectrogramProvider = ({
|
|
|
4270
4353
|
if (clipCanvasInfo && clipCanvasInfo.size > 0) {
|
|
4271
4354
|
const numChannels = item.monoFlag ? 1 : item.channelDataArrays.length;
|
|
4272
4355
|
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
|
-
}
|
|
4356
|
+
const channelRanges = [];
|
|
4357
|
+
for (let ch = 0; ch < numChannels; ch++) {
|
|
4358
|
+
const channelInfo = clipCanvasInfo.get(ch);
|
|
4359
|
+
if (!channelInfo) continue;
|
|
4360
|
+
const range = getVisibleChunkRange(channelInfo, clipPixelOffset);
|
|
4361
|
+
channelRanges.push({ ch, channelInfo, ...range });
|
|
4303
4362
|
}
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
durationSamples: item.durationSamples,
|
|
4313
|
-
mono: item.monoFlag,
|
|
4314
|
-
sampleRange: visibleRange
|
|
4315
|
-
});
|
|
4363
|
+
if (channelRanges.length > 0 && channelRanges[0].viewportIndices.length > 0) {
|
|
4364
|
+
const cacheKey = await computeFFTForChunks(
|
|
4365
|
+
workerApi,
|
|
4366
|
+
channelRanges[0].channelInfo,
|
|
4367
|
+
channelRanges[0].viewportIndices,
|
|
4368
|
+
item,
|
|
4369
|
+
generation
|
|
4370
|
+
);
|
|
4316
4371
|
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);
|
|
4372
|
+
for (const { ch, channelInfo, viewportIndices } of channelRanges) {
|
|
4321
4373
|
await renderChunkSubset(
|
|
4322
4374
|
workerApi,
|
|
4323
|
-
|
|
4375
|
+
cacheKey,
|
|
4324
4376
|
channelInfo,
|
|
4325
|
-
|
|
4377
|
+
viewportIndices,
|
|
4326
4378
|
item,
|
|
4327
|
-
ch
|
|
4379
|
+
ch,
|
|
4380
|
+
generation
|
|
4328
4381
|
);
|
|
4329
4382
|
}
|
|
4330
|
-
if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;
|
|
4331
4383
|
}
|
|
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
4384
|
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
|
|
4385
|
+
if (channelRanges.length > 0 && channelRanges[0].bufferIndices.length > 0) {
|
|
4386
|
+
const bufferGroups = groupContiguousIndices(
|
|
4387
|
+
channelRanges[0].channelInfo,
|
|
4388
|
+
channelRanges[0].bufferIndices
|
|
4356
4389
|
);
|
|
4390
|
+
for (const group of bufferGroups) {
|
|
4391
|
+
if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;
|
|
4392
|
+
const cacheKey = await computeFFTForChunks(
|
|
4393
|
+
workerApi,
|
|
4394
|
+
channelRanges[0].channelInfo,
|
|
4395
|
+
group,
|
|
4396
|
+
item,
|
|
4397
|
+
generation
|
|
4398
|
+
);
|
|
4399
|
+
if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;
|
|
4400
|
+
for (const { ch, channelInfo } of channelRanges) {
|
|
4401
|
+
await renderChunkSubset(
|
|
4402
|
+
workerApi,
|
|
4403
|
+
cacheKey,
|
|
4404
|
+
channelInfo,
|
|
4405
|
+
group,
|
|
4406
|
+
item,
|
|
4407
|
+
ch,
|
|
4408
|
+
generation
|
|
4409
|
+
);
|
|
4410
|
+
}
|
|
4411
|
+
}
|
|
4357
4412
|
}
|
|
4413
|
+
renderedClipIdsRef.current.add(item.clipId);
|
|
4358
4414
|
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
|
-
});
|
|
4415
|
+
if (await renderBackgroundBatches(channelRanges, item)) return;
|
|
4375
4416
|
}
|
|
4376
4417
|
} catch (err) {
|
|
4377
|
-
|
|
4418
|
+
if (err instanceof SpectrogramAbortError) return;
|
|
4419
|
+
console.warn(
|
|
4420
|
+
`[waveform-playlist] Spectrogram worker error for clip ${item.clipId}: ${err instanceof Error ? err.message : String(err)}`
|
|
4421
|
+
);
|
|
4378
4422
|
}
|
|
4379
4423
|
}
|
|
4380
4424
|
for (const item of clipsNeedingDisplayOnly) {
|
|
4381
4425
|
if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;
|
|
4382
|
-
const cacheKey = clipCacheKeysRef.current.get(item.clipId);
|
|
4383
|
-
if (!cacheKey) continue;
|
|
4384
4426
|
const clipCanvasInfo = spectrogramCanvasRegistryRef.current.get(item.clipId);
|
|
4385
4427
|
if (!clipCanvasInfo || clipCanvasInfo.size === 0) continue;
|
|
4386
4428
|
try {
|
|
@@ -4389,22 +4431,73 @@ var SpectrogramProvider = ({
|
|
|
4389
4431
|
for (let ch = 0; ch < item.numChannels; ch++) {
|
|
4390
4432
|
const channelInfo = clipCanvasInfo.get(ch);
|
|
4391
4433
|
if (!channelInfo) continue;
|
|
4392
|
-
const
|
|
4393
|
-
|
|
4394
|
-
|
|
4434
|
+
const range = getVisibleChunkRange(channelInfo, clipPixelOffset);
|
|
4435
|
+
channelRanges.push({ ch, channelInfo, ...range });
|
|
4436
|
+
}
|
|
4437
|
+
if (channelRanges.length > 0 && channelRanges[0].viewportIndices.length > 0) {
|
|
4438
|
+
const cacheKey = await computeFFTForChunks(
|
|
4439
|
+
workerApi,
|
|
4440
|
+
channelRanges[0].channelInfo,
|
|
4441
|
+
channelRanges[0].viewportIndices,
|
|
4442
|
+
item,
|
|
4443
|
+
generation
|
|
4444
|
+
);
|
|
4445
|
+
if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;
|
|
4446
|
+
for (const { ch, channelInfo, viewportIndices } of channelRanges) {
|
|
4447
|
+
await renderChunkSubset(
|
|
4448
|
+
workerApi,
|
|
4449
|
+
cacheKey,
|
|
4450
|
+
channelInfo,
|
|
4451
|
+
viewportIndices,
|
|
4452
|
+
item,
|
|
4453
|
+
ch,
|
|
4454
|
+
generation
|
|
4455
|
+
);
|
|
4456
|
+
}
|
|
4457
|
+
}
|
|
4458
|
+
if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;
|
|
4459
|
+
if (channelRanges.length > 0 && channelRanges[0].bufferIndices.length > 0) {
|
|
4460
|
+
const bufferGroups = groupContiguousIndices(
|
|
4461
|
+
channelRanges[0].channelInfo,
|
|
4462
|
+
channelRanges[0].bufferIndices
|
|
4395
4463
|
);
|
|
4396
|
-
|
|
4397
|
-
|
|
4464
|
+
for (const group of bufferGroups) {
|
|
4465
|
+
if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;
|
|
4466
|
+
const cacheKey = await computeFFTForChunks(
|
|
4467
|
+
workerApi,
|
|
4468
|
+
channelRanges[0].channelInfo,
|
|
4469
|
+
group,
|
|
4470
|
+
item,
|
|
4471
|
+
generation
|
|
4472
|
+
);
|
|
4473
|
+
if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;
|
|
4474
|
+
for (const { ch, channelInfo } of channelRanges) {
|
|
4475
|
+
await renderChunkSubset(
|
|
4476
|
+
workerApi,
|
|
4477
|
+
cacheKey,
|
|
4478
|
+
channelInfo,
|
|
4479
|
+
group,
|
|
4480
|
+
item,
|
|
4481
|
+
ch,
|
|
4482
|
+
generation
|
|
4483
|
+
);
|
|
4484
|
+
}
|
|
4485
|
+
}
|
|
4398
4486
|
}
|
|
4399
4487
|
if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;
|
|
4400
|
-
if (await renderBackgroundBatches(channelRanges,
|
|
4488
|
+
if (await renderBackgroundBatches(channelRanges, item)) return;
|
|
4401
4489
|
} catch (err) {
|
|
4402
|
-
|
|
4490
|
+
if (err instanceof SpectrogramAbortError) return;
|
|
4491
|
+
console.warn(
|
|
4492
|
+
`[waveform-playlist] Spectrogram display re-render error for clip ${item.clipId}: ${err instanceof Error ? err.message : String(err)}`
|
|
4493
|
+
);
|
|
4403
4494
|
}
|
|
4404
4495
|
}
|
|
4405
4496
|
};
|
|
4406
4497
|
computeAsync().catch((err) => {
|
|
4407
|
-
console.error(
|
|
4498
|
+
console.error(
|
|
4499
|
+
`[waveform-playlist] Spectrogram computation failed: ${err instanceof Error ? err.message : String(err)}`
|
|
4500
|
+
);
|
|
4408
4501
|
});
|
|
4409
4502
|
}, [
|
|
4410
4503
|
tracks,
|
|
@@ -4415,7 +4508,6 @@ var SpectrogramProvider = ({
|
|
|
4415
4508
|
waveHeight,
|
|
4416
4509
|
samplesPerPixel,
|
|
4417
4510
|
spectrogramCanvasVersion,
|
|
4418
|
-
controls,
|
|
4419
4511
|
scrollContainerRef
|
|
4420
4512
|
]);
|
|
4421
4513
|
const setTrackRenderMode = useCallback((trackId, mode) => {
|
|
@@ -4475,7 +4567,6 @@ var SpectrogramProvider = ({
|
|
|
4475
4567
|
);
|
|
4476
4568
|
const value = useMemo(
|
|
4477
4569
|
() => ({
|
|
4478
|
-
spectrogramDataMap,
|
|
4479
4570
|
trackSpectrogramOverrides,
|
|
4480
4571
|
spectrogramWorkerApi: spectrogramWorkerReady ? spectrogramWorkerRef.current : null,
|
|
4481
4572
|
spectrogramConfig,
|
|
@@ -4490,7 +4581,6 @@ var SpectrogramProvider = ({
|
|
|
4490
4581
|
getFrequencyScale
|
|
4491
4582
|
}),
|
|
4492
4583
|
[
|
|
4493
|
-
spectrogramDataMap,
|
|
4494
4584
|
trackSpectrogramOverrides,
|
|
4495
4585
|
spectrogramWorkerReady,
|
|
4496
4586
|
spectrogramConfig,
|
|
@@ -4505,12 +4595,14 @@ var SpectrogramProvider = ({
|
|
|
4505
4595
|
return /* @__PURE__ */ jsx3(SpectrogramIntegrationProvider, { value, children });
|
|
4506
4596
|
};
|
|
4507
4597
|
export {
|
|
4598
|
+
SpectrogramAbortError,
|
|
4508
4599
|
SpectrogramMenuItems,
|
|
4509
4600
|
SpectrogramProvider,
|
|
4510
4601
|
SpectrogramSettingsModal,
|
|
4511
4602
|
computeSpectrogram,
|
|
4512
4603
|
computeSpectrogramMono,
|
|
4513
4604
|
createSpectrogramWorker,
|
|
4605
|
+
createSpectrogramWorkerPool,
|
|
4514
4606
|
getColorMap,
|
|
4515
4607
|
getFrequencyScale
|
|
4516
4608
|
};
|