@remotion/timeline-utils 4.0.513 → 4.0.515

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.
@@ -1,101 +1,3 @@
1
- // src/audio-waveform/parse-color.ts
2
- var colorCache = new Map;
3
- var parseColor = (color) => {
4
- const cached = colorCache.get(color);
5
- if (cached)
6
- return cached;
7
- const ctx = new OffscreenCanvas(1, 1).getContext("2d");
8
- ctx.fillStyle = color;
9
- ctx.fillRect(0, 0, 1, 1);
10
- const [r, g, b, a] = ctx.getImageData(0, 0, 1, 1).data;
11
- const result = [r, g, b, a];
12
- colorCache.set(color, result);
13
- return result;
14
- };
15
-
16
- // src/audio-waveform/draw-peaks.ts
17
- var CLIPPING_COLOR = "#FF7F50";
18
- var getVolumeAtBar = ({
19
- barIndex,
20
- numBars,
21
- volume
22
- }) => {
23
- if (typeof volume === "number") {
24
- return volume;
25
- }
26
- if (volume.length === 0) {
27
- return 1;
28
- }
29
- if (volume.length === 1 || numBars <= 1) {
30
- return volume[0];
31
- }
32
- const volumeIndex = Math.round(barIndex / (numBars - 1) * (volume.length - 1));
33
- return volume[volumeIndex] ?? 1;
34
- };
35
- var drawBars = ({
36
- canvas,
37
- color,
38
- peaks,
39
- volume,
40
- width
41
- }) => {
42
- const ctx = canvas.getContext("2d");
43
- if (!ctx) {
44
- throw new Error("Failed to get canvas context");
45
- }
46
- const { height } = canvas;
47
- const w = canvas.width;
48
- if (w === 0 || height === 0) {
49
- return;
50
- }
51
- ctx.clearRect(0, 0, w, height);
52
- const [r, g, b, a] = parseColor(color);
53
- const [cr, cg, cb, ca] = parseColor(CLIPPING_COLOR);
54
- const imageData = ctx.createImageData(w, height);
55
- const { data } = imageData;
56
- const numBars = width;
57
- for (let barIndex = 0;barIndex < numBars; barIndex++) {
58
- const x = barIndex;
59
- if (x >= w)
60
- break;
61
- const peakIndex = Math.floor(barIndex / numBars * peaks.length);
62
- const peak = peaks[peakIndex] || 0;
63
- const barVolume = getVolumeAtBar({ barIndex, numBars, volume });
64
- const scaledPeak = peak * barVolume;
65
- const halfBar = Math.max(0, Math.min(height / 2, scaledPeak * height / 2));
66
- if (halfBar === 0)
67
- continue;
68
- const mid = height / 2;
69
- const barY = Math.round(mid - halfBar);
70
- const barEnd = Math.round(mid + halfBar);
71
- const isClipping = scaledPeak > 1;
72
- const clipTopEnd = isClipping ? Math.min(barY + 2, barEnd) : barY;
73
- const clipBotStart = isClipping ? Math.max(barEnd - 2, barY) : barEnd;
74
- for (let y = barY;y < clipTopEnd; y++) {
75
- const idx = (y * w + x) * 4;
76
- data[idx] = cr;
77
- data[idx + 1] = cg;
78
- data[idx + 2] = cb;
79
- data[idx + 3] = ca;
80
- }
81
- for (let y = clipTopEnd;y < clipBotStart; y++) {
82
- const idx = (y * w + x) * 4;
83
- data[idx] = r;
84
- data[idx + 1] = g;
85
- data[idx + 2] = b;
86
- data[idx + 3] = a;
87
- }
88
- for (let y = clipBotStart;y < barEnd; y++) {
89
- const idx = (y * w + x) * 4;
90
- data[idx] = cr;
91
- data[idx + 1] = cg;
92
- data[idx + 2] = cb;
93
- data[idx + 3] = ca;
94
- }
95
- }
96
- ctx.putImageData(imageData, 0, 0);
97
- };
98
-
99
1
  // src/audio-waveform/load-waveform-peaks.ts
100
2
  import { ALL_FORMATS, AudioSampleSink, Input, UrlSource } from "mediabunny";
101
3
 
@@ -280,56 +182,18 @@ async function loadWaveformPeaks(url, signal, options) {
280
182
  }
281
183
  }
282
184
 
283
- // src/audio-waveform/slice-waveform-peaks.ts
284
- var sliceWaveformPeaks = ({
285
- durationInFrames,
286
- fps,
287
- peaks,
288
- playbackRate,
289
- startFrom
290
- }) => {
291
- if (peaks.length === 0) {
292
- return peaks;
293
- }
294
- const startTimeInSeconds = startFrom / fps;
295
- const durationInSeconds = durationInFrames / fps * playbackRate;
296
- const startPeakIndex = Math.floor(startTimeInSeconds * TARGET_SAMPLE_RATE);
297
- const endPeakIndex = Math.ceil((startTimeInSeconds + durationInSeconds) * TARGET_SAMPLE_RATE);
298
- if (!Number.isFinite(startPeakIndex) || !Number.isFinite(endPeakIndex)) {
299
- return peaks.subarray(Math.max(0, startPeakIndex), Math.min(peaks.length, endPeakIndex));
300
- }
301
- if (startPeakIndex >= 0 && endPeakIndex <= peaks.length) {
302
- return peaks.subarray(startPeakIndex, endPeakIndex);
303
- }
304
- const portion = new Float32Array(Math.max(0, endPeakIndex - startPeakIndex));
305
- const sourceStart = Math.max(0, startPeakIndex);
306
- const sourceEnd = Math.min(peaks.length, endPeakIndex);
307
- if (sourceStart < sourceEnd) {
308
- portion.set(peaks.subarray(sourceStart, sourceEnd), sourceStart - startPeakIndex);
309
- }
310
- return portion;
311
- };
312
-
313
- // src/loop-display.ts
314
- var shouldTileLoopDisplay = (loopDisplay) => {
315
- return loopDisplay !== undefined && loopDisplay.numberOfTimes > 1;
316
- };
317
- var getLoopDisplayWidth = ({
318
- visualizationWidth,
319
- loopDisplay
320
- }) => {
321
- if (!shouldTileLoopDisplay(loopDisplay)) {
322
- return visualizationWidth;
323
- }
324
- return visualizationWidth / loopDisplay.numberOfTimes;
325
- };
326
-
327
185
  // src/audio-waveform-worker.ts
328
- var canvas = null;
329
- var currentController = null;
330
- var latestRequestId = 0;
186
+ var postPeaks = (requestId, peaks, final) => {
187
+ const payload = {
188
+ type: "peaks",
189
+ requestId,
190
+ peaks,
191
+ final
192
+ };
193
+ self.postMessage(payload);
194
+ };
331
195
  var postError = (requestId, error) => {
332
- const message = error instanceof Error ? error.message : "Failed to render waveform";
196
+ const message = error instanceof Error ? error.message : "Failed to load waveform";
333
197
  const payload = {
334
198
  type: "error",
335
199
  requestId,
@@ -337,96 +201,18 @@ var postError = (requestId, error) => {
337
201
  };
338
202
  self.postMessage(payload);
339
203
  };
340
- var drawPartialWaveform = (message, peaks) => {
341
- if (!canvas) {
342
- return;
343
- }
344
- const portionPeaks = sliceWaveformPeaks({
345
- durationInFrames: shouldTileLoopDisplay(message.loopDisplay) ? message.loopDisplay.durationInFrames : message.durationInFrames,
346
- fps: message.fps,
347
- peaks,
348
- playbackRate: message.playbackRate,
349
- startFrom: message.startFrom
350
- });
351
- if (!shouldTileLoopDisplay(message.loopDisplay)) {
352
- drawBars({
353
- canvas,
354
- peaks: portionPeaks,
355
- color: "rgba(255, 255, 255, 0.6)",
356
- volume: message.volume,
357
- width: message.width
358
- });
359
- return;
360
- }
361
- const loopWidth = getLoopDisplayWidth({
362
- visualizationWidth: message.width,
363
- loopDisplay: message.loopDisplay
364
- });
365
- const targetCanvas = new OffscreenCanvas(Math.max(1, Math.ceil(loopWidth)), message.height);
366
- drawBars({
367
- canvas: targetCanvas,
368
- peaks: portionPeaks,
369
- color: "rgba(255, 255, 255, 0.6)",
370
- volume: message.volume,
371
- width: targetCanvas.width
372
- });
373
- const ctx = canvas.getContext("2d");
374
- if (!ctx) {
375
- throw new Error("Failed to get canvas context");
376
- }
377
- const pattern = ctx.createPattern(targetCanvas, "repeat-x");
378
- if (!pattern) {
379
- return;
380
- }
381
- pattern.setTransform(new DOMMatrix().scaleSelf(loopWidth / targetCanvas.width, 1));
382
- ctx.clearRect(0, 0, message.width, message.height);
383
- ctx.fillStyle = pattern;
384
- ctx.fillRect(0, 0, message.width, message.height);
385
- };
386
- var renderWaveform = async (message) => {
387
- if (!canvas) {
388
- postError(message.requestId, new Error("Waveform canvas not initialized"));
389
- return;
390
- }
204
+ self.addEventListener("message", (event) => {
205
+ const message = event.data;
391
206
  const controller = new AbortController;
392
- currentController?.abort();
393
- currentController = controller;
394
- latestRequestId = message.requestId;
395
- try {
396
- canvas.width = message.width;
397
- canvas.height = message.height;
398
- const peaks = await loadWaveformPeaks(message.src, controller.signal, {
399
- onProgress: ({ peaks: nextPeaks }) => {
400
- if (controller.signal.aborted || latestRequestId !== message.requestId) {
401
- return;
402
- }
403
- drawPartialWaveform(message, nextPeaks);
207
+ loadWaveformPeaks(message.src, controller.signal, {
208
+ onProgress: ({ peaks, final }) => {
209
+ if (!final) {
210
+ postPeaks(message.requestId, peaks, false);
404
211
  }
405
- });
406
- if (controller.signal.aborted || latestRequestId !== message.requestId) {
407
- return;
408
- }
409
- drawPartialWaveform(message, peaks);
410
- } catch (error) {
411
- if (controller.signal.aborted || latestRequestId !== message.requestId) {
412
- return;
413
212
  }
414
- postError(message.requestId, error);
415
- }
416
- };
417
- self.addEventListener("message", (event) => {
418
- const message = event.data;
419
- if (message.type === "init") {
420
- canvas = message.canvas;
421
- return;
422
- }
423
- if (message.type === "dispose") {
424
- currentController?.abort();
425
- currentController = null;
426
- canvas = null;
427
- return;
428
- }
429
- renderWaveform(message).catch((error) => {
213
+ }).then((peaks) => {
214
+ postPeaks(message.requestId, peaks, true);
215
+ }).catch((error) => {
430
216
  postError(message.requestId, error);
431
217
  });
432
218
  });