@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.
- package/dist/audio-waveform/audio-waveform-worker-types.d.ts +9 -20
- package/dist/audio-waveform/get-visible-waveform-volume.d.ts +8 -0
- package/dist/audio-waveform/get-visible-waveform-volume.js +36 -0
- package/dist/audio-waveform/slice-visible-waveform-peaks.d.ts +11 -0
- package/dist/audio-waveform/slice-visible-waveform-peaks.js +46 -0
- package/dist/audio-waveform/subscribe-to-waveform-peaks.d.ts +5 -0
- package/dist/audio-waveform/subscribe-to-waveform-peaks.js +148 -0
- package/dist/audio-waveform-worker.js +24 -99
- package/dist/esm/audio-waveform-worker.mjs +19 -233
- package/dist/esm/index.mjs +345 -81
- package/dist/extract-frames.js +24 -14
- package/dist/image-thumbnail/draw-repeating-image-thumbnail.d.ts +2 -1
- package/dist/image-thumbnail/draw-repeating-image-thumbnail.js +2 -1
- package/dist/index.d.ts +9 -7
- package/dist/index.js +13 -8
- package/dist/loop-display.d.ts +11 -0
- package/dist/loop-display.js +36 -1
- package/package.json +5 -4
|
@@ -1,29 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export type AudioWaveformWorkerInitMessage = {
|
|
4
|
-
readonly type: 'init';
|
|
5
|
-
readonly canvas: OffscreenCanvas;
|
|
6
|
-
};
|
|
7
|
-
export type AudioWaveformWorkerRenderMessage = {
|
|
8
|
-
readonly type: 'render';
|
|
1
|
+
export type AudioWaveformWorkerLoadMessage = {
|
|
2
|
+
readonly type: 'load';
|
|
9
3
|
readonly requestId: number;
|
|
10
4
|
readonly src: string;
|
|
11
|
-
readonly width: number;
|
|
12
|
-
readonly height: number;
|
|
13
|
-
readonly volume: WaveformVolume;
|
|
14
|
-
readonly startFrom: number;
|
|
15
|
-
readonly durationInFrames: number;
|
|
16
|
-
readonly fps: number;
|
|
17
|
-
readonly playbackRate: number;
|
|
18
|
-
readonly loopDisplay: TimelineLoopDisplay | undefined;
|
|
19
5
|
};
|
|
20
|
-
export type
|
|
21
|
-
|
|
6
|
+
export type AudioWaveformWorkerIncomingMessage = AudioWaveformWorkerLoadMessage;
|
|
7
|
+
export type AudioWaveformWorkerPeaksMessage = {
|
|
8
|
+
readonly type: 'peaks';
|
|
9
|
+
readonly requestId: number;
|
|
10
|
+
readonly peaks: Float32Array;
|
|
11
|
+
readonly final: boolean;
|
|
22
12
|
};
|
|
23
|
-
export type AudioWaveformWorkerIncomingMessage = AudioWaveformWorkerInitMessage | AudioWaveformWorkerRenderMessage | AudioWaveformWorkerDisposeMessage;
|
|
24
13
|
export type AudioWaveformWorkerErrorMessage = {
|
|
25
14
|
readonly type: 'error';
|
|
26
15
|
readonly requestId: number;
|
|
27
16
|
readonly message: string;
|
|
28
17
|
};
|
|
29
|
-
export type AudioWaveformWorkerOutgoingMessage = AudioWaveformWorkerErrorMessage;
|
|
18
|
+
export type AudioWaveformWorkerOutgoingMessage = AudioWaveformWorkerPeaksMessage | AudioWaveformWorkerErrorMessage;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type TimelineLoopDisplay } from '../loop-display';
|
|
2
|
+
import type { WaveformVolume } from './draw-peaks';
|
|
3
|
+
export declare const getVisibleWaveformVolume: ({ displayDurationInFrames, displayOffsetInFrames, loopDisplay, volume, }: {
|
|
4
|
+
readonly displayDurationInFrames: number;
|
|
5
|
+
readonly displayOffsetInFrames: number;
|
|
6
|
+
readonly loopDisplay: TimelineLoopDisplay | undefined;
|
|
7
|
+
readonly volume: WaveformVolume;
|
|
8
|
+
}) => WaveformVolume;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getVisibleWaveformVolume = void 0;
|
|
4
|
+
const loop_display_1 = require("../loop-display");
|
|
5
|
+
const getVisibleWaveformVolume = ({ displayDurationInFrames, displayOffsetInFrames, loopDisplay, volume, }) => {
|
|
6
|
+
if (!Array.isArray(volume)) {
|
|
7
|
+
return volume;
|
|
8
|
+
}
|
|
9
|
+
if (!Number.isFinite(displayDurationInFrames) ||
|
|
10
|
+
displayDurationInFrames <= 0) {
|
|
11
|
+
return [];
|
|
12
|
+
}
|
|
13
|
+
if (!(0, loop_display_1.shouldTileLoopDisplay)(loopDisplay) ||
|
|
14
|
+
loopDisplay.durationInFrames <= 0) {
|
|
15
|
+
const start = Math.max(0, Math.floor(displayOffsetInFrames));
|
|
16
|
+
const end = Math.min(volume.length, Math.ceil(displayOffsetInFrames + displayDurationInFrames));
|
|
17
|
+
return volume.slice(start, end);
|
|
18
|
+
}
|
|
19
|
+
const segments = (0, loop_display_1.getLoopDisplaySegments)({
|
|
20
|
+
displayDurationInFrames,
|
|
21
|
+
displayOffsetInFrames,
|
|
22
|
+
loopDurationInFrames: loopDisplay.durationInFrames,
|
|
23
|
+
});
|
|
24
|
+
const result = [];
|
|
25
|
+
for (const segment of segments) {
|
|
26
|
+
const start = Math.max(0, Math.floor(segment.loopOffsetInFrames));
|
|
27
|
+
const end = Math.min(volume.length, Math.ceil(segment.loopOffsetInFrames + segment.durationInFrames));
|
|
28
|
+
// Do not `push(...slice)`: Chrome throws RangeError: Invalid array length
|
|
29
|
+
// once a loop segment is longer than ~65k frames.
|
|
30
|
+
for (let index = start; index < end; index++) {
|
|
31
|
+
result.push(volume[index]);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return result;
|
|
35
|
+
};
|
|
36
|
+
exports.getVisibleWaveformVolume = getVisibleWaveformVolume;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { TimelineLoopDisplay } from '../loop-display';
|
|
2
|
+
export declare const sliceVisibleWaveformPeaks: ({ displayDurationInFrames, displayOffsetInFrames, durationInFrames, fps, loopDisplay, peaks, playbackRate, startFrom, }: {
|
|
3
|
+
readonly displayDurationInFrames: number;
|
|
4
|
+
readonly displayOffsetInFrames: number;
|
|
5
|
+
readonly durationInFrames: number;
|
|
6
|
+
readonly fps: number;
|
|
7
|
+
readonly loopDisplay: TimelineLoopDisplay | undefined;
|
|
8
|
+
readonly peaks: Float32Array<ArrayBufferLike>;
|
|
9
|
+
readonly playbackRate: number;
|
|
10
|
+
readonly startFrom: number;
|
|
11
|
+
}) => Float32Array<ArrayBufferLike>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sliceVisibleWaveformPeaks = void 0;
|
|
4
|
+
const loop_display_1 = require("../loop-display");
|
|
5
|
+
const slice_waveform_peaks_1 = require("./slice-waveform-peaks");
|
|
6
|
+
const sliceVisibleWaveformPeaks = ({ displayDurationInFrames, displayOffsetInFrames, durationInFrames, fps, loopDisplay, peaks, playbackRate, startFrom, }) => {
|
|
7
|
+
if (!(0, loop_display_1.shouldTileLoopDisplay)(loopDisplay) ||
|
|
8
|
+
loopDisplay.durationInFrames <= 0) {
|
|
9
|
+
return (0, slice_waveform_peaks_1.sliceWaveformPeaks)({
|
|
10
|
+
durationInFrames: Math.min(displayDurationInFrames, Math.max(0, durationInFrames - displayOffsetInFrames)),
|
|
11
|
+
fps,
|
|
12
|
+
peaks,
|
|
13
|
+
playbackRate,
|
|
14
|
+
startFrom: startFrom + displayOffsetInFrames * playbackRate,
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
const segments = (0, loop_display_1.getLoopDisplaySegments)({
|
|
18
|
+
displayDurationInFrames,
|
|
19
|
+
displayOffsetInFrames,
|
|
20
|
+
loopDurationInFrames: loopDisplay.durationInFrames,
|
|
21
|
+
});
|
|
22
|
+
const parts = [];
|
|
23
|
+
let totalLength = 0;
|
|
24
|
+
for (const segment of segments) {
|
|
25
|
+
const part = (0, slice_waveform_peaks_1.sliceWaveformPeaks)({
|
|
26
|
+
durationInFrames: segment.durationInFrames,
|
|
27
|
+
fps,
|
|
28
|
+
peaks,
|
|
29
|
+
playbackRate,
|
|
30
|
+
startFrom: startFrom + segment.loopOffsetInFrames * playbackRate,
|
|
31
|
+
});
|
|
32
|
+
parts.push(part);
|
|
33
|
+
totalLength += part.length;
|
|
34
|
+
}
|
|
35
|
+
if (parts.length === 1) {
|
|
36
|
+
return parts[0];
|
|
37
|
+
}
|
|
38
|
+
const result = new Float32Array(totalLength);
|
|
39
|
+
let writeOffset = 0;
|
|
40
|
+
for (const part of parts) {
|
|
41
|
+
result.set(part, writeOffset);
|
|
42
|
+
writeOffset += part.length;
|
|
43
|
+
}
|
|
44
|
+
return result;
|
|
45
|
+
};
|
|
46
|
+
exports.sliceVisibleWaveformPeaks = sliceVisibleWaveformPeaks;
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.subscribeToWaveformPeaks = void 0;
|
|
4
|
+
const load_waveform_peaks_1 = require("./load-waveform-peaks");
|
|
5
|
+
const make_audio_waveform_worker_1 = require("./make-audio-waveform-worker");
|
|
6
|
+
// All AudioWaveform instances share one decode worker and one peaks cache,
|
|
7
|
+
// so remounts (timeline virtualization, zoom window cropping) and multiple
|
|
8
|
+
// clips with the same src never re-fetch or re-decode the audio.
|
|
9
|
+
const peaksCache = new Map();
|
|
10
|
+
const inFlightBySrc = new Map();
|
|
11
|
+
const inFlightByRequestId = new Map();
|
|
12
|
+
let worker = null;
|
|
13
|
+
let workerFailed = false;
|
|
14
|
+
let nextRequestId = 0;
|
|
15
|
+
const emitPeaks = (load, peaks, final) => {
|
|
16
|
+
if (final) {
|
|
17
|
+
peaksCache.set(load.src, peaks);
|
|
18
|
+
inFlightBySrc.delete(load.src);
|
|
19
|
+
if (load.requestId !== null) {
|
|
20
|
+
inFlightByRequestId.delete(load.requestId);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
load.latestPeaks = peaks;
|
|
25
|
+
}
|
|
26
|
+
for (const listener of load.listeners) {
|
|
27
|
+
listener.onPeaks(peaks, final);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
const emitError = (load, error) => {
|
|
31
|
+
inFlightBySrc.delete(load.src);
|
|
32
|
+
if (load.requestId !== null) {
|
|
33
|
+
inFlightByRequestId.delete(load.requestId);
|
|
34
|
+
}
|
|
35
|
+
for (const listener of load.listeners) {
|
|
36
|
+
listener.onError(error);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
const startMainThreadLoad = (load) => {
|
|
40
|
+
load.requestId = null;
|
|
41
|
+
// Never aborted: even if all subscribers unsubscribe, finishing the
|
|
42
|
+
// decode fills the cache for the next mount.
|
|
43
|
+
const controller = new AbortController();
|
|
44
|
+
(0, load_waveform_peaks_1.loadWaveformPeaks)(load.src, controller.signal, {
|
|
45
|
+
onProgress: ({ peaks, final }) => {
|
|
46
|
+
if (final) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
// The processor mutates the same array in place; snapshot it so
|
|
50
|
+
// React state updates see a new reference.
|
|
51
|
+
emitPeaks(load, peaks.slice(), false);
|
|
52
|
+
},
|
|
53
|
+
})
|
|
54
|
+
.then((peaks) => {
|
|
55
|
+
emitPeaks(load, peaks, true);
|
|
56
|
+
})
|
|
57
|
+
.catch((error) => {
|
|
58
|
+
emitError(load, error instanceof Error
|
|
59
|
+
? error
|
|
60
|
+
: new Error('Failed to load waveform peaks'));
|
|
61
|
+
});
|
|
62
|
+
};
|
|
63
|
+
const handleWorkerFailure = () => {
|
|
64
|
+
workerFailed = true;
|
|
65
|
+
worker === null || worker === void 0 ? void 0 : worker.terminate();
|
|
66
|
+
worker = null;
|
|
67
|
+
const pending = [...inFlightByRequestId.values()];
|
|
68
|
+
inFlightByRequestId.clear();
|
|
69
|
+
for (const load of pending) {
|
|
70
|
+
startMainThreadLoad(load);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
const getOrCreateWorker = () => {
|
|
74
|
+
if (workerFailed || typeof Worker === 'undefined') {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
if (worker) {
|
|
78
|
+
return worker;
|
|
79
|
+
}
|
|
80
|
+
try {
|
|
81
|
+
worker = (0, make_audio_waveform_worker_1.makeAudioWaveformWorker)();
|
|
82
|
+
}
|
|
83
|
+
catch (_a) {
|
|
84
|
+
workerFailed = true;
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
worker.addEventListener('message', (event) => {
|
|
88
|
+
const message = event.data;
|
|
89
|
+
const load = inFlightByRequestId.get(message.requestId);
|
|
90
|
+
if (!load) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (message.type === 'error') {
|
|
94
|
+
emitError(load, new Error(message.message));
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
emitPeaks(load, message.peaks, message.final);
|
|
98
|
+
});
|
|
99
|
+
worker.addEventListener('error', (event) => {
|
|
100
|
+
event.preventDefault();
|
|
101
|
+
handleWorkerFailure();
|
|
102
|
+
});
|
|
103
|
+
return worker;
|
|
104
|
+
};
|
|
105
|
+
const subscribeToWaveformPeaks = ({ src, onPeaks, onError, }) => {
|
|
106
|
+
const cached = peaksCache.get(src);
|
|
107
|
+
if (cached) {
|
|
108
|
+
onPeaks(cached, true);
|
|
109
|
+
return () => undefined;
|
|
110
|
+
}
|
|
111
|
+
const listener = { onPeaks, onError };
|
|
112
|
+
const existing = inFlightBySrc.get(src);
|
|
113
|
+
if (existing) {
|
|
114
|
+
existing.listeners.add(listener);
|
|
115
|
+
if (existing.latestPeaks) {
|
|
116
|
+
onPeaks(existing.latestPeaks, false);
|
|
117
|
+
}
|
|
118
|
+
return () => {
|
|
119
|
+
existing.listeners.delete(listener);
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
const load = {
|
|
123
|
+
src,
|
|
124
|
+
listeners: new Set([listener]),
|
|
125
|
+
latestPeaks: null,
|
|
126
|
+
requestId: null,
|
|
127
|
+
};
|
|
128
|
+
inFlightBySrc.set(src, load);
|
|
129
|
+
const workerInstance = getOrCreateWorker();
|
|
130
|
+
if (workerInstance) {
|
|
131
|
+
const requestId = nextRequestId++;
|
|
132
|
+
load.requestId = requestId;
|
|
133
|
+
inFlightByRequestId.set(requestId, load);
|
|
134
|
+
const message = {
|
|
135
|
+
type: 'load',
|
|
136
|
+
requestId,
|
|
137
|
+
src,
|
|
138
|
+
};
|
|
139
|
+
workerInstance.postMessage(message);
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
startMainThreadLoad(load);
|
|
143
|
+
}
|
|
144
|
+
return () => {
|
|
145
|
+
load.listeners.delete(listener);
|
|
146
|
+
};
|
|
147
|
+
};
|
|
148
|
+
exports.subscribeToWaveformPeaks = subscribeToWaveformPeaks;
|
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/// <reference lib="webworker" />
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
const draw_peaks_1 = require("./audio-waveform/draw-peaks");
|
|
5
4
|
const load_waveform_peaks_1 = require("./audio-waveform/load-waveform-peaks");
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
const postPeaks = (requestId, peaks, final) => {
|
|
6
|
+
// Structured cloning copies the array, so the decoder can keep
|
|
7
|
+
// mutating its buffer while the main thread reads the snapshot.
|
|
8
|
+
const payload = {
|
|
9
|
+
type: 'peaks',
|
|
10
|
+
requestId,
|
|
11
|
+
peaks,
|
|
12
|
+
final,
|
|
13
|
+
};
|
|
14
|
+
self.postMessage(payload);
|
|
15
|
+
};
|
|
11
16
|
const postError = (requestId, error) => {
|
|
12
|
-
const message = error instanceof Error ? error.message : 'Failed to
|
|
17
|
+
const message = error instanceof Error ? error.message : 'Failed to load waveform';
|
|
13
18
|
const payload = {
|
|
14
19
|
type: 'error',
|
|
15
20
|
requestId,
|
|
@@ -17,100 +22,20 @@ const postError = (requestId, error) => {
|
|
|
17
22
|
};
|
|
18
23
|
self.postMessage(payload);
|
|
19
24
|
};
|
|
20
|
-
const drawPartialWaveform = (message, peaks) => {
|
|
21
|
-
if (!canvas) {
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
const portionPeaks = (0, slice_waveform_peaks_1.sliceWaveformPeaks)({
|
|
25
|
-
durationInFrames: (0, loop_display_1.shouldTileLoopDisplay)(message.loopDisplay)
|
|
26
|
-
? message.loopDisplay.durationInFrames
|
|
27
|
-
: message.durationInFrames,
|
|
28
|
-
fps: message.fps,
|
|
29
|
-
peaks,
|
|
30
|
-
playbackRate: message.playbackRate,
|
|
31
|
-
startFrom: message.startFrom,
|
|
32
|
-
});
|
|
33
|
-
if (!(0, loop_display_1.shouldTileLoopDisplay)(message.loopDisplay)) {
|
|
34
|
-
(0, draw_peaks_1.drawBars)({
|
|
35
|
-
canvas,
|
|
36
|
-
peaks: portionPeaks,
|
|
37
|
-
color: 'rgba(255, 255, 255, 0.6)',
|
|
38
|
-
volume: message.volume,
|
|
39
|
-
width: message.width,
|
|
40
|
-
});
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
const loopWidth = (0, loop_display_1.getLoopDisplayWidth)({
|
|
44
|
-
visualizationWidth: message.width,
|
|
45
|
-
loopDisplay: message.loopDisplay,
|
|
46
|
-
});
|
|
47
|
-
const targetCanvas = new OffscreenCanvas(Math.max(1, Math.ceil(loopWidth)), message.height);
|
|
48
|
-
(0, draw_peaks_1.drawBars)({
|
|
49
|
-
canvas: targetCanvas,
|
|
50
|
-
peaks: portionPeaks,
|
|
51
|
-
color: 'rgba(255, 255, 255, 0.6)',
|
|
52
|
-
volume: message.volume,
|
|
53
|
-
width: targetCanvas.width,
|
|
54
|
-
});
|
|
55
|
-
const ctx = canvas.getContext('2d');
|
|
56
|
-
if (!ctx) {
|
|
57
|
-
throw new Error('Failed to get canvas context');
|
|
58
|
-
}
|
|
59
|
-
const pattern = ctx.createPattern(targetCanvas, 'repeat-x');
|
|
60
|
-
if (!pattern) {
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
pattern.setTransform(new DOMMatrix().scaleSelf(loopWidth / targetCanvas.width, 1));
|
|
64
|
-
ctx.clearRect(0, 0, message.width, message.height);
|
|
65
|
-
ctx.fillStyle = pattern;
|
|
66
|
-
ctx.fillRect(0, 0, message.width, message.height);
|
|
67
|
-
};
|
|
68
|
-
const renderWaveform = async (message) => {
|
|
69
|
-
if (!canvas) {
|
|
70
|
-
postError(message.requestId, new Error('Waveform canvas not initialized'));
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
const controller = new AbortController();
|
|
74
|
-
currentController === null || currentController === void 0 ? void 0 : currentController.abort();
|
|
75
|
-
currentController = controller;
|
|
76
|
-
latestRequestId = message.requestId;
|
|
77
|
-
try {
|
|
78
|
-
canvas.width = message.width;
|
|
79
|
-
canvas.height = message.height;
|
|
80
|
-
const peaks = await (0, load_waveform_peaks_1.loadWaveformPeaks)(message.src, controller.signal, {
|
|
81
|
-
onProgress: ({ peaks: nextPeaks }) => {
|
|
82
|
-
if (controller.signal.aborted ||
|
|
83
|
-
latestRequestId !== message.requestId) {
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
drawPartialWaveform(message, nextPeaks);
|
|
87
|
-
},
|
|
88
|
-
});
|
|
89
|
-
if (controller.signal.aborted || latestRequestId !== message.requestId) {
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
drawPartialWaveform(message, peaks);
|
|
93
|
-
}
|
|
94
|
-
catch (error) {
|
|
95
|
-
if (controller.signal.aborted || latestRequestId !== message.requestId) {
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
postError(message.requestId, error);
|
|
99
|
-
}
|
|
100
|
-
};
|
|
101
25
|
self.addEventListener('message', (event) => {
|
|
102
26
|
const message = event.data;
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
27
|
+
const controller = new AbortController();
|
|
28
|
+
(0, load_waveform_peaks_1.loadWaveformPeaks)(message.src, controller.signal, {
|
|
29
|
+
onProgress: ({ peaks, final }) => {
|
|
30
|
+
if (!final) {
|
|
31
|
+
postPeaks(message.requestId, peaks, false);
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
})
|
|
35
|
+
.then((peaks) => {
|
|
36
|
+
postPeaks(message.requestId, peaks, true);
|
|
37
|
+
})
|
|
38
|
+
.catch((error) => {
|
|
114
39
|
postError(message.requestId, error);
|
|
115
40
|
});
|
|
116
41
|
});
|