@waveform-playlist/spectrogram 7.1.0 → 7.1.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.js CHANGED
@@ -3950,10 +3950,19 @@ function createSpectrogramWorker(worker) {
3950
3950
 
3951
3951
  // src/SpectrogramProvider.tsx
3952
3952
  var import_react2 = require("react");
3953
+ var import_core = require("@waveform-playlist/core");
3953
3954
  var import_browser = require("@waveform-playlist/browser");
3954
3955
  var import_browser2 = require("@waveform-playlist/browser");
3955
3956
  var import_jsx_runtime3 = require("react/jsx-runtime");
3956
3957
  var import_meta = {};
3958
+ function extractChunkNumber(canvasId) {
3959
+ const match = canvasId.match(/chunk(\d+)$/);
3960
+ if (!match) {
3961
+ console.warn(`[spectrogram] Unexpected canvas ID format: ${canvasId}`);
3962
+ return 0;
3963
+ }
3964
+ return parseInt(match[1], 10);
3965
+ }
3957
3966
  var SpectrogramProvider = ({
3958
3967
  config: spectrogramConfig,
3959
3968
  colorMap: spectrogramColorMap,
@@ -4190,26 +4199,25 @@ var SpectrogramProvider = ({
4190
4199
  }
4191
4200
  return;
4192
4201
  }
4193
- const getVisibleChunkRange = (canvasWidths, clipPixelOffset = 0) => {
4202
+ const getVisibleChunkRange = (channelInfo, clipPixelOffset = 0) => {
4194
4203
  const container = scrollContainerRef.current;
4195
4204
  if (!container) {
4196
- return { visibleIndices: canvasWidths.map((_, i) => i), remainingIndices: [] };
4205
+ return { visibleIndices: channelInfo.canvasWidths.map((_, i) => i), remainingIndices: [] };
4197
4206
  }
4198
4207
  const scrollLeft = container.scrollLeft;
4199
4208
  const viewportWidth = container.clientWidth;
4200
4209
  const controlWidth = controls.show ? controls.width : 0;
4201
4210
  const visibleIndices = [];
4202
4211
  const remainingIndices = [];
4203
- let offset = 0;
4204
- for (let i = 0; i < canvasWidths.length; i++) {
4205
- const chunkLeft = offset + controlWidth + clipPixelOffset;
4206
- const chunkRight = chunkLeft + canvasWidths[i];
4212
+ for (let i = 0; i < channelInfo.canvasWidths.length; i++) {
4213
+ const chunkNumber = extractChunkNumber(channelInfo.canvasIds[i]);
4214
+ const chunkLeft = chunkNumber * import_core.MAX_CANVAS_WIDTH + controlWidth + clipPixelOffset;
4215
+ const chunkRight = chunkLeft + channelInfo.canvasWidths[i];
4207
4216
  if (chunkRight > scrollLeft && chunkLeft < scrollLeft + viewportWidth) {
4208
4217
  visibleIndices.push(i);
4209
4218
  } else {
4210
4219
  remainingIndices.push(i);
4211
4220
  }
4212
- offset += canvasWidths[i];
4213
4221
  }
4214
4222
  return { visibleIndices, remainingIndices };
4215
4223
  };
@@ -4219,11 +4227,8 @@ var SpectrogramProvider = ({
4219
4227
  const canvasWidths = indices.map((i) => channelInfo.canvasWidths[i]);
4220
4228
  const globalPixelOffsets = [];
4221
4229
  for (const idx of indices) {
4222
- let offset = 0;
4223
- for (let j = 0; j < idx; j++) {
4224
- offset += channelInfo.canvasWidths[j];
4225
- }
4226
- globalPixelOffsets.push(offset);
4230
+ const chunkNumber = extractChunkNumber(channelInfo.canvasIds[idx]);
4231
+ globalPixelOffsets.push(chunkNumber * import_core.MAX_CANVAS_WIDTH);
4227
4232
  }
4228
4233
  const colorLUT = getColorMap(item.colorMap);
4229
4234
  await api.renderChunks({
@@ -4246,6 +4251,25 @@ var SpectrogramProvider = ({
4246
4251
  const computeAsync = async () => {
4247
4252
  const abortToken = { aborted: false };
4248
4253
  backgroundRenderAbortRef.current = abortToken;
4254
+ const renderBackgroundBatches = async (channelRanges, cacheKey, item) => {
4255
+ const BATCH_SIZE = 4;
4256
+ for (const { ch, channelInfo, remainingIndices } of channelRanges) {
4257
+ for (let batchStart = 0; batchStart < remainingIndices.length; batchStart += BATCH_SIZE) {
4258
+ if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return true;
4259
+ const batch = remainingIndices.slice(batchStart, batchStart + BATCH_SIZE);
4260
+ await new Promise((resolve) => {
4261
+ if (typeof requestIdleCallback === "function") {
4262
+ requestIdleCallback(() => resolve());
4263
+ } else {
4264
+ setTimeout(resolve, 0);
4265
+ }
4266
+ });
4267
+ if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return true;
4268
+ await renderChunkSubset(workerApi, cacheKey, channelInfo, batch, item, ch);
4269
+ }
4270
+ }
4271
+ return false;
4272
+ };
4249
4273
  for (const item of clipsNeedingFFT) {
4250
4274
  if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;
4251
4275
  try {
@@ -4297,7 +4321,7 @@ var SpectrogramProvider = ({
4297
4321
  for (let ch = 0; ch < numChannels; ch++) {
4298
4322
  const channelInfo = clipCanvasInfo.get(ch);
4299
4323
  if (!channelInfo) continue;
4300
- const { visibleIndices } = getVisibleChunkRange(channelInfo.canvasWidths, clipPixelOffset);
4324
+ const { visibleIndices } = getVisibleChunkRange(channelInfo, clipPixelOffset);
4301
4325
  await renderChunkSubset(workerApi, visibleCacheKey, channelInfo, visibleIndices, item, ch);
4302
4326
  }
4303
4327
  if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;
@@ -4313,27 +4337,16 @@ var SpectrogramProvider = ({
4313
4337
  });
4314
4338
  if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;
4315
4339
  clipCacheKeysRef.current.set(item.clipId, cacheKey);
4340
+ const channelRanges = [];
4316
4341
  for (let ch = 0; ch < numChannels; ch++) {
4317
4342
  const channelInfo = clipCanvasInfo.get(ch);
4318
4343
  if (!channelInfo) continue;
4319
- const { visibleIndices, remainingIndices } = getVisibleChunkRange(channelInfo.canvasWidths, clipPixelOffset);
4320
- await renderChunkSubset(workerApi, cacheKey, channelInfo, visibleIndices, item, ch);
4321
- if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;
4322
- const BATCH_SIZE = 4;
4323
- for (let batchStart = 0; batchStart < remainingIndices.length; batchStart += BATCH_SIZE) {
4324
- if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;
4325
- const batch = remainingIndices.slice(batchStart, batchStart + BATCH_SIZE);
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;
4334
- await renderChunkSubset(workerApi, cacheKey, channelInfo, batch, item, ch);
4335
- }
4344
+ const range = getVisibleChunkRange(channelInfo, clipPixelOffset);
4345
+ channelRanges.push({ ch, channelInfo, ...range });
4346
+ await renderChunkSubset(workerApi, cacheKey, channelInfo, range.visibleIndices, item, ch);
4336
4347
  }
4348
+ if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;
4349
+ if (await renderBackgroundBatches(channelRanges, cacheKey, item)) return;
4337
4350
  } else {
4338
4351
  const spectrograms = await workerApi.compute({
4339
4352
  channelDataArrays: item.channelDataArrays,
@@ -4362,27 +4375,16 @@ var SpectrogramProvider = ({
4362
4375
  if (!clipCanvasInfo || clipCanvasInfo.size === 0) continue;
4363
4376
  try {
4364
4377
  const clipPixelOffset = Math.floor(item.clipStartSample / samplesPerPixel);
4378
+ const channelRanges = [];
4365
4379
  for (let ch = 0; ch < item.numChannels; ch++) {
4366
4380
  const channelInfo = clipCanvasInfo.get(ch);
4367
4381
  if (!channelInfo) continue;
4368
- const { visibleIndices, remainingIndices } = getVisibleChunkRange(channelInfo.canvasWidths, clipPixelOffset);
4382
+ const { visibleIndices, remainingIndices } = getVisibleChunkRange(channelInfo, clipPixelOffset);
4383
+ channelRanges.push({ ch, channelInfo, remainingIndices });
4369
4384
  await renderChunkSubset(workerApi, cacheKey, channelInfo, visibleIndices, item, ch);
4370
- if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;
4371
- const BATCH_SIZE = 4;
4372
- for (let batchStart = 0; batchStart < remainingIndices.length; batchStart += BATCH_SIZE) {
4373
- if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;
4374
- const batch = remainingIndices.slice(batchStart, batchStart + BATCH_SIZE);
4375
- await new Promise((resolve) => {
4376
- if (typeof requestIdleCallback === "function") {
4377
- requestIdleCallback(() => resolve());
4378
- } else {
4379
- setTimeout(resolve, 0);
4380
- }
4381
- });
4382
- if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;
4383
- await renderChunkSubset(workerApi, cacheKey, channelInfo, batch, item, ch);
4384
- }
4385
4385
  }
4386
+ if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;
4387
+ if (await renderBackgroundBatches(channelRanges, cacheKey, item)) return;
4386
4388
  } catch (err) {
4387
4389
  console.warn("Spectrogram display re-render error for clip", item.clipId, err);
4388
4390
  }