@waveform-playlist/browser 11.1.0 → 11.3.0
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 +19 -2
- package/dist/index.d.ts +19 -2
- package/dist/index.js +109 -95
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +111 -96
- package/dist/index.mjs.map +1 -1
- package/package.json +10 -10
package/dist/index.mjs
CHANGED
|
@@ -65,6 +65,7 @@ import {
|
|
|
65
65
|
} from "react";
|
|
66
66
|
import { ThemeProvider } from "styled-components";
|
|
67
67
|
import {
|
|
68
|
+
configureGlobalContext,
|
|
68
69
|
createToneAdapter,
|
|
69
70
|
getGlobalAudioContext as getGlobalAudioContext4
|
|
70
71
|
} from "@waveform-playlist/playout";
|
|
@@ -78,11 +79,13 @@ import { getContext as getContext2 } from "tone";
|
|
|
78
79
|
import WaveformData from "waveform-data";
|
|
79
80
|
function loadWaveformData(src) {
|
|
80
81
|
return __async(this, null, function* () {
|
|
82
|
+
var _a, _b;
|
|
81
83
|
const response = yield fetch(src);
|
|
82
84
|
if (!response.ok) {
|
|
83
85
|
throw new Error(`Failed to fetch waveform data: ${response.statusText}`);
|
|
84
86
|
}
|
|
85
|
-
const
|
|
87
|
+
const { pathname } = new URL(src, (_b = (_a = globalThis.location) == null ? void 0 : _a.href) != null ? _b : "http://localhost");
|
|
88
|
+
const isBinary = pathname.toLowerCase().endsWith(".dat");
|
|
86
89
|
if (isBinary) {
|
|
87
90
|
const arrayBuffer = yield response.arrayBuffer();
|
|
88
91
|
return WaveformData.create(arrayBuffer);
|
|
@@ -3700,6 +3703,7 @@ var WaveformPlaylistProvider = ({
|
|
|
3700
3703
|
soundFontCache,
|
|
3701
3704
|
deferEngineRebuild = false,
|
|
3702
3705
|
indefinitePlayback = false,
|
|
3706
|
+
sampleRate: sampleRateProp,
|
|
3703
3707
|
children
|
|
3704
3708
|
}) => {
|
|
3705
3709
|
var _a, _b, _c, _d;
|
|
@@ -3755,6 +3759,7 @@ var WaveformPlaylistProvider = ({
|
|
|
3755
3759
|
const playbackEndTimeRef = useRef15(null);
|
|
3756
3760
|
const scrollContainerRef = useRef15(null);
|
|
3757
3761
|
const isAutomaticScrollRef = useRef15(false);
|
|
3762
|
+
const frameCallbacksRef = useRef15(/* @__PURE__ */ new Map());
|
|
3758
3763
|
const continuousPlayRef = useRef15((_d = annotationList == null ? void 0 : annotationList.isContinuousPlay) != null ? _d : false);
|
|
3759
3764
|
const activeAnnotationIdRef = useRef15(null);
|
|
3760
3765
|
const engineTracksRef = useRef15(null);
|
|
@@ -3763,9 +3768,21 @@ var WaveformPlaylistProvider = ({
|
|
|
3763
3768
|
const isDraggingRef = useRef15(false);
|
|
3764
3769
|
const prevTracksRef = useRef15([]);
|
|
3765
3770
|
const samplesPerPixelRef = useRef15(initialSamplesPerPixel);
|
|
3766
|
-
const
|
|
3767
|
-
typeof AudioContext
|
|
3768
|
-
|
|
3771
|
+
const [initialSampleRate] = useState15(() => {
|
|
3772
|
+
if (typeof AudioContext === "undefined") return sampleRateProp != null ? sampleRateProp : 48e3;
|
|
3773
|
+
try {
|
|
3774
|
+
if (sampleRateProp !== void 0) {
|
|
3775
|
+
return configureGlobalContext({ sampleRate: sampleRateProp });
|
|
3776
|
+
}
|
|
3777
|
+
return getGlobalAudioContext4().sampleRate;
|
|
3778
|
+
} catch (err) {
|
|
3779
|
+
console.warn(
|
|
3780
|
+
"[waveform-playlist] Failed to configure AudioContext: " + String(err) + " \u2014 falling back to " + (sampleRateProp != null ? sampleRateProp : 48e3) + " Hz"
|
|
3781
|
+
);
|
|
3782
|
+
return sampleRateProp != null ? sampleRateProp : 48e3;
|
|
3783
|
+
}
|
|
3784
|
+
});
|
|
3785
|
+
const sampleRateRef = useRef15(initialSampleRate);
|
|
3769
3786
|
const { timeFormat, setTimeFormat, formatTime: formatTime2 } = useTimeFormat();
|
|
3770
3787
|
const zoom = useZoomControls({ engineRef, initialSamplesPerPixel });
|
|
3771
3788
|
const { samplesPerPixel, onEngineState: onZoomEngineState } = zoom;
|
|
@@ -4115,15 +4132,28 @@ var WaveformPlaylistProvider = ({
|
|
|
4115
4132
|
let peaks;
|
|
4116
4133
|
if (clip.waveformData) {
|
|
4117
4134
|
try {
|
|
4135
|
+
const wdRate = clip.waveformData.sample_rate;
|
|
4136
|
+
const clipRate = clip.sampleRate;
|
|
4137
|
+
let peakOffset = clip.offsetSamples;
|
|
4138
|
+
let peakDuration = clip.durationSamples;
|
|
4139
|
+
let peakSpp = samplesPerPixel;
|
|
4140
|
+
if (wdRate !== clipRate && clipRate > 0 && wdRate > 0) {
|
|
4141
|
+
const ratio = wdRate / clipRate;
|
|
4142
|
+
peakOffset = Math.round(clip.offsetSamples * ratio);
|
|
4143
|
+
peakDuration = Math.round(clip.durationSamples * ratio);
|
|
4144
|
+
peakSpp = Math.max(1, Math.round(samplesPerPixel * ratio));
|
|
4145
|
+
}
|
|
4118
4146
|
peaks = extractPeaksFromWaveformDataFull(
|
|
4119
4147
|
clip.waveformData,
|
|
4120
|
-
|
|
4148
|
+
peakSpp,
|
|
4121
4149
|
mono,
|
|
4122
|
-
|
|
4123
|
-
|
|
4150
|
+
peakOffset,
|
|
4151
|
+
peakDuration
|
|
4124
4152
|
);
|
|
4125
4153
|
} catch (err) {
|
|
4126
|
-
console.warn(
|
|
4154
|
+
console.warn(
|
|
4155
|
+
"[waveform-playlist] Failed to extract peaks from waveformData: " + String(err)
|
|
4156
|
+
);
|
|
4127
4157
|
}
|
|
4128
4158
|
}
|
|
4129
4159
|
if (!peaks) {
|
|
@@ -4138,7 +4168,9 @@ var WaveformPlaylistProvider = ({
|
|
|
4138
4168
|
clip.durationSamples
|
|
4139
4169
|
);
|
|
4140
4170
|
} catch (err) {
|
|
4141
|
-
console.warn(
|
|
4171
|
+
console.warn(
|
|
4172
|
+
"[waveform-playlist] Failed to extract peaks from cache: " + String(err)
|
|
4173
|
+
);
|
|
4142
4174
|
}
|
|
4143
4175
|
}
|
|
4144
4176
|
}
|
|
@@ -4188,10 +4220,30 @@ var WaveformPlaylistProvider = ({
|
|
|
4188
4220
|
const elapsed = getContext2().currentTime - ((_a2 = playbackStartTimeRef.current) != null ? _a2 : 0);
|
|
4189
4221
|
return ((_b2 = audioStartPositionRef.current) != null ? _b2 : 0) + elapsed;
|
|
4190
4222
|
}, []);
|
|
4223
|
+
const registerFrameCallback = useCallback19((id, cb) => {
|
|
4224
|
+
frameCallbacksRef.current.set(id, cb);
|
|
4225
|
+
}, []);
|
|
4226
|
+
const unregisterFrameCallback = useCallback19((id) => {
|
|
4227
|
+
frameCallbacksRef.current.delete(id);
|
|
4228
|
+
}, []);
|
|
4191
4229
|
const startAnimationLoop = useCallback19(() => {
|
|
4230
|
+
const audioCtx = getGlobalAudioContext4();
|
|
4192
4231
|
const updateTime = () => {
|
|
4193
4232
|
const time = getPlaybackTime();
|
|
4194
4233
|
currentTimeRef.current = time;
|
|
4234
|
+
const latency = "outputLatency" in audioCtx ? audioCtx.outputLatency : 0;
|
|
4235
|
+
const visualTime = Math.max(0, time - latency);
|
|
4236
|
+
const sr = sampleRateRef.current;
|
|
4237
|
+
const spp = samplesPerPixelRef.current;
|
|
4238
|
+
const frameData = {
|
|
4239
|
+
time,
|
|
4240
|
+
visualTime,
|
|
4241
|
+
sampleRate: sr,
|
|
4242
|
+
samplesPerPixel: spp
|
|
4243
|
+
};
|
|
4244
|
+
for (const cb of frameCallbacksRef.current.values()) {
|
|
4245
|
+
cb(frameData);
|
|
4246
|
+
}
|
|
4195
4247
|
const currentAnnotations = annotationsRef.current;
|
|
4196
4248
|
if (currentAnnotations.length > 0) {
|
|
4197
4249
|
const currentAnnotation = currentAnnotations.find(
|
|
@@ -4226,10 +4278,9 @@ var WaveformPlaylistProvider = ({
|
|
|
4226
4278
|
}
|
|
4227
4279
|
if (isAutomaticScrollRef.current && scrollContainerRef.current && duration > 0) {
|
|
4228
4280
|
const container = scrollContainerRef.current;
|
|
4229
|
-
const
|
|
4230
|
-
const pixelPosition = time * sr / samplesPerPixelRef.current;
|
|
4281
|
+
const pixelPosition = visualTime * sr / spp;
|
|
4231
4282
|
const containerWidth = container.clientWidth;
|
|
4232
|
-
const targetScrollLeft = Math.max(0, pixelPosition - containerWidth / 2);
|
|
4283
|
+
const targetScrollLeft = Math.round(Math.max(0, pixelPosition - containerWidth / 2));
|
|
4233
4284
|
container.scrollLeft = targetScrollLeft;
|
|
4234
4285
|
}
|
|
4235
4286
|
if (playbackEndTimeRef.current !== null && time >= playbackEndTimeRef.current) {
|
|
@@ -4465,7 +4516,9 @@ var WaveformPlaylistProvider = ({
|
|
|
4465
4516
|
currentTimeRef,
|
|
4466
4517
|
playbackStartTimeRef,
|
|
4467
4518
|
audioStartPositionRef,
|
|
4468
|
-
getPlaybackTime
|
|
4519
|
+
getPlaybackTime,
|
|
4520
|
+
registerFrameCallback,
|
|
4521
|
+
unregisterFrameCallback
|
|
4469
4522
|
}),
|
|
4470
4523
|
[
|
|
4471
4524
|
isPlaying,
|
|
@@ -4473,7 +4526,9 @@ var WaveformPlaylistProvider = ({
|
|
|
4473
4526
|
currentTimeRef,
|
|
4474
4527
|
playbackStartTimeRef,
|
|
4475
4528
|
audioStartPositionRef,
|
|
4476
|
-
getPlaybackTime
|
|
4529
|
+
getPlaybackTime,
|
|
4530
|
+
registerFrameCallback,
|
|
4531
|
+
unregisterFrameCallback
|
|
4477
4532
|
]
|
|
4478
4533
|
);
|
|
4479
4534
|
const stateValue = useMemo4(
|
|
@@ -5268,32 +5323,19 @@ var PositionDisplay = styled.span`
|
|
|
5268
5323
|
var AudioPosition = ({ className }) => {
|
|
5269
5324
|
var _a;
|
|
5270
5325
|
const timeRef = useRef17(null);
|
|
5271
|
-
const
|
|
5272
|
-
const { isPlaying, currentTimeRef, getPlaybackTime } = usePlaybackAnimation();
|
|
5326
|
+
const { isPlaying, currentTimeRef, registerFrameCallback, unregisterFrameCallback } = usePlaybackAnimation();
|
|
5273
5327
|
const { timeFormat: format } = usePlaylistData();
|
|
5274
5328
|
useEffect12(() => {
|
|
5275
|
-
const
|
|
5276
|
-
var _a2;
|
|
5277
|
-
if (timeRef.current) {
|
|
5278
|
-
const time = isPlaying ? getPlaybackTime() : (_a2 = currentTimeRef.current) != null ? _a2 : 0;
|
|
5279
|
-
timeRef.current.textContent = formatTime(time, format);
|
|
5280
|
-
}
|
|
5281
|
-
if (isPlaying) {
|
|
5282
|
-
animationFrameRef.current = requestAnimationFrame(updateTime);
|
|
5283
|
-
}
|
|
5284
|
-
};
|
|
5329
|
+
const id = "audio-position";
|
|
5285
5330
|
if (isPlaying) {
|
|
5286
|
-
|
|
5287
|
-
|
|
5288
|
-
|
|
5331
|
+
registerFrameCallback(id, ({ time }) => {
|
|
5332
|
+
if (timeRef.current) {
|
|
5333
|
+
timeRef.current.textContent = formatTime(time, format);
|
|
5334
|
+
}
|
|
5335
|
+
});
|
|
5289
5336
|
}
|
|
5290
|
-
return () =>
|
|
5291
|
-
|
|
5292
|
-
cancelAnimationFrame(animationFrameRef.current);
|
|
5293
|
-
animationFrameRef.current = null;
|
|
5294
|
-
}
|
|
5295
|
-
};
|
|
5296
|
-
}, [isPlaying, format, currentTimeRef, getPlaybackTime]);
|
|
5337
|
+
return () => unregisterFrameCallback(id);
|
|
5338
|
+
}, [isPlaying, format, registerFrameCallback, unregisterFrameCallback]);
|
|
5297
5339
|
useEffect12(() => {
|
|
5298
5340
|
var _a2;
|
|
5299
5341
|
if (!isPlaying && timeRef.current) {
|
|
@@ -5476,33 +5518,20 @@ var PlayheadLine = styled2.div.attrs((props) => ({
|
|
|
5476
5518
|
`;
|
|
5477
5519
|
var AnimatedPlayhead = ({ color = "#ff0000" }) => {
|
|
5478
5520
|
const playheadRef = useRef18(null);
|
|
5479
|
-
const
|
|
5480
|
-
const { isPlaying, currentTimeRef, getPlaybackTime } = usePlaybackAnimation();
|
|
5521
|
+
const { isPlaying, currentTimeRef, registerFrameCallback, unregisterFrameCallback } = usePlaybackAnimation();
|
|
5481
5522
|
const { samplesPerPixel, sampleRate, progressBarWidth } = usePlaylistData();
|
|
5482
5523
|
useEffect13(() => {
|
|
5483
|
-
const
|
|
5484
|
-
var _a;
|
|
5485
|
-
if (playheadRef.current) {
|
|
5486
|
-
const time = isPlaying ? getPlaybackTime() : (_a = currentTimeRef.current) != null ? _a : 0;
|
|
5487
|
-
const position = time * sampleRate / samplesPerPixel;
|
|
5488
|
-
playheadRef.current.style.transform = `translate3d(${position}px, 0, 0)`;
|
|
5489
|
-
}
|
|
5490
|
-
if (isPlaying) {
|
|
5491
|
-
animationFrameRef.current = requestAnimationFrame(updatePosition);
|
|
5492
|
-
}
|
|
5493
|
-
};
|
|
5524
|
+
const id = "playhead";
|
|
5494
5525
|
if (isPlaying) {
|
|
5495
|
-
|
|
5496
|
-
|
|
5497
|
-
|
|
5526
|
+
registerFrameCallback(id, ({ visualTime, sampleRate: sr, samplesPerPixel: spp }) => {
|
|
5527
|
+
if (playheadRef.current) {
|
|
5528
|
+
const px = visualTime * sr / spp;
|
|
5529
|
+
playheadRef.current.style.transform = `translate3d(${px}px, 0, 0)`;
|
|
5530
|
+
}
|
|
5531
|
+
});
|
|
5498
5532
|
}
|
|
5499
|
-
return () =>
|
|
5500
|
-
|
|
5501
|
-
cancelAnimationFrame(animationFrameRef.current);
|
|
5502
|
-
animationFrameRef.current = null;
|
|
5503
|
-
}
|
|
5504
|
-
};
|
|
5505
|
-
}, [isPlaying, sampleRate, samplesPerPixel, currentTimeRef, getPlaybackTime]);
|
|
5533
|
+
return () => unregisterFrameCallback(id);
|
|
5534
|
+
}, [isPlaying, registerFrameCallback, unregisterFrameCallback]);
|
|
5506
5535
|
useEffect13(() => {
|
|
5507
5536
|
var _a;
|
|
5508
5537
|
if (!isPlaying && playheadRef.current) {
|
|
@@ -5515,7 +5544,7 @@ var AnimatedPlayhead = ({ color = "#ff0000" }) => {
|
|
|
5515
5544
|
};
|
|
5516
5545
|
|
|
5517
5546
|
// src/components/ChannelWithProgress.tsx
|
|
5518
|
-
import { useRef as useRef19, useEffect as useEffect14 } from "react";
|
|
5547
|
+
import { useId, useRef as useRef19, useEffect as useEffect14 } from "react";
|
|
5519
5548
|
import styled3 from "styled-components";
|
|
5520
5549
|
import {
|
|
5521
5550
|
clipPixelWidth as computeClipPixelWidth
|
|
@@ -5581,10 +5610,10 @@ var ChannelWithProgress = (_a) => {
|
|
|
5581
5610
|
"clipOffsetSeconds"
|
|
5582
5611
|
]);
|
|
5583
5612
|
const progressRef = useRef19(null);
|
|
5584
|
-
const
|
|
5613
|
+
const callbackId = useId();
|
|
5585
5614
|
const theme = useTheme();
|
|
5586
5615
|
const { waveHeight } = usePlaylistInfo();
|
|
5587
|
-
const { isPlaying, currentTimeRef,
|
|
5616
|
+
const { isPlaying, currentTimeRef, registerFrameCallback, unregisterFrameCallback } = usePlaybackAnimation();
|
|
5588
5617
|
const { samplesPerPixel, sampleRate } = usePlaylistData();
|
|
5589
5618
|
const progressColor = (theme == null ? void 0 : theme.waveProgressColor) || "rgba(0, 0, 0, 0.1)";
|
|
5590
5619
|
const clipPixelWidth = computeClipPixelWidth(
|
|
@@ -5593,46 +5622,32 @@ var ChannelWithProgress = (_a) => {
|
|
|
5593
5622
|
samplesPerPixel
|
|
5594
5623
|
);
|
|
5595
5624
|
useEffect14(() => {
|
|
5596
|
-
const updateProgress = () => {
|
|
5597
|
-
var _a2;
|
|
5598
|
-
if (progressRef.current) {
|
|
5599
|
-
const currentTime = isPlaying ? getPlaybackTime() : (_a2 = currentTimeRef.current) != null ? _a2 : 0;
|
|
5600
|
-
const currentSample = currentTime * sampleRate;
|
|
5601
|
-
const clipEndSample = clipStartSample + clipDurationSamples;
|
|
5602
|
-
let ratio = 0;
|
|
5603
|
-
if (currentSample <= clipStartSample) {
|
|
5604
|
-
ratio = 0;
|
|
5605
|
-
} else if (currentSample >= clipEndSample) {
|
|
5606
|
-
ratio = 1;
|
|
5607
|
-
} else {
|
|
5608
|
-
const playedSamples = currentSample - clipStartSample;
|
|
5609
|
-
ratio = playedSamples / clipDurationSamples;
|
|
5610
|
-
}
|
|
5611
|
-
progressRef.current.style.transform = `scaleX(${ratio})`;
|
|
5612
|
-
}
|
|
5613
|
-
if (isPlaying) {
|
|
5614
|
-
animationFrameRef.current = requestAnimationFrame(updateProgress);
|
|
5615
|
-
}
|
|
5616
|
-
};
|
|
5617
5625
|
if (isPlaying) {
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
|
|
5626
|
+
registerFrameCallback(callbackId, ({ visualTime, sampleRate: sr }) => {
|
|
5627
|
+
if (progressRef.current) {
|
|
5628
|
+
const currentSample = visualTime * sr;
|
|
5629
|
+
const clipEndSample = clipStartSample + clipDurationSamples;
|
|
5630
|
+
let ratio = 0;
|
|
5631
|
+
if (currentSample <= clipStartSample) {
|
|
5632
|
+
ratio = 0;
|
|
5633
|
+
} else if (currentSample >= clipEndSample) {
|
|
5634
|
+
ratio = 1;
|
|
5635
|
+
} else {
|
|
5636
|
+
const playedSamples = currentSample - clipStartSample;
|
|
5637
|
+
ratio = playedSamples / clipDurationSamples;
|
|
5638
|
+
}
|
|
5639
|
+
progressRef.current.style.transform = `scaleX(${ratio})`;
|
|
5640
|
+
}
|
|
5641
|
+
});
|
|
5621
5642
|
}
|
|
5622
|
-
return () =>
|
|
5623
|
-
if (animationFrameRef.current) {
|
|
5624
|
-
cancelAnimationFrame(animationFrameRef.current);
|
|
5625
|
-
animationFrameRef.current = null;
|
|
5626
|
-
}
|
|
5627
|
-
};
|
|
5643
|
+
return () => unregisterFrameCallback(callbackId);
|
|
5628
5644
|
}, [
|
|
5629
5645
|
isPlaying,
|
|
5630
|
-
sampleRate,
|
|
5631
5646
|
clipStartSample,
|
|
5632
5647
|
clipDurationSamples,
|
|
5633
|
-
|
|
5634
|
-
|
|
5635
|
-
|
|
5648
|
+
callbackId,
|
|
5649
|
+
registerFrameCallback,
|
|
5650
|
+
unregisterFrameCallback
|
|
5636
5651
|
]);
|
|
5637
5652
|
useEffect14(() => {
|
|
5638
5653
|
var _a2;
|