preview speed control
This commit is contained in:
@@ -11,7 +11,12 @@ import { app } from '../store.svelte';
|
||||
|
||||
export type AudioEngine = {
|
||||
init: (video: HTMLVideoElement) => Promise<void>;
|
||||
reschedule: (currentTime: number, markers: Marker[], isPlaying: boolean) => void;
|
||||
reschedule: (
|
||||
currentTime: number,
|
||||
markers: Marker[],
|
||||
isPlaying: boolean,
|
||||
playbackRate: number,
|
||||
) => void;
|
||||
playKey: (code: string, keyLabel: string, phase: SoundPhase) => void;
|
||||
preloadActiveSwitch: () => Promise<void>;
|
||||
destroy: () => void;
|
||||
@@ -146,7 +151,7 @@ export function createAudioEngine(): AudioEngine {
|
||||
await preloadSwitch(app.activeSwitch);
|
||||
},
|
||||
|
||||
reschedule(time: number, markers: Marker[], playing: boolean) {
|
||||
reschedule(time: number, markers: Marker[], playing: boolean, playbackRate: number) {
|
||||
if (!ctx || !playing) {
|
||||
clearScheduled();
|
||||
return;
|
||||
@@ -155,6 +160,7 @@ export function createAudioEngine(): AudioEngine {
|
||||
clearScheduled();
|
||||
const audioCtx = ctx;
|
||||
const startAt = audioCtx.currentTime + 0.02;
|
||||
const rate = playbackRate > 0 ? playbackRate : 1;
|
||||
const switchType = app.activeSwitch;
|
||||
|
||||
void (async () => {
|
||||
@@ -172,14 +178,14 @@ export function createAudioEngine(): AudioEngine {
|
||||
const releaseTime = markerReleaseTime(marker);
|
||||
|
||||
if (marker.time >= time - 0.05) {
|
||||
const pressDelay = marker.time - time;
|
||||
const pressDelay = (marker.time - time) / rate;
|
||||
const pressBuffer = await loadBuffer(switchType, 'press', pressKey);
|
||||
const pressSource = playBuffer(pressBuffer, startAt + Math.max(0, pressDelay));
|
||||
if (pressSource) scheduledSources.push(pressSource);
|
||||
}
|
||||
|
||||
if (releaseTime >= time - 0.05) {
|
||||
const releaseDelay = releaseTime - time;
|
||||
const releaseDelay = (releaseTime - time) / rate;
|
||||
const releaseBuffer = await loadBuffer(switchType, 'release', releaseKey);
|
||||
const releaseSource = playBuffer(releaseBuffer, startAt + Math.max(0, releaseDelay));
|
||||
if (releaseSource) scheduledSources.push(releaseSource);
|
||||
|
||||
@@ -14,6 +14,7 @@ export const app = $state({
|
||||
videoUrl: null as string | null,
|
||||
videoName: null as string | null,
|
||||
timelineWidth: 800,
|
||||
previewSpeed: 1,
|
||||
});
|
||||
|
||||
let markerCounter = 0;
|
||||
@@ -52,6 +53,10 @@ export function setFps(value: number) {
|
||||
app.fps = value;
|
||||
}
|
||||
|
||||
export function setPreviewSpeed(value: number) {
|
||||
app.previewSpeed = Math.max(0.25, Math.min(2, value));
|
||||
}
|
||||
|
||||
export function setPixelsPerSecond(value: number) {
|
||||
app.pixelsPerSecond = value;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ export type VideoController = {
|
||||
togglePlayPause: () => void;
|
||||
stepFrame: (delta: number) => void;
|
||||
seek: (time: number) => void;
|
||||
setPlaybackRate: (rate: number) => void;
|
||||
};
|
||||
|
||||
export function attachVideoPlayer(video: HTMLVideoElement): VideoController {
|
||||
@@ -71,6 +72,9 @@ export function attachVideoPlayer(video: HTMLVideoElement): VideoController {
|
||||
|
||||
if (video.readyState >= 1) onLoadedMetadata();
|
||||
|
||||
video.preservesPitch = true;
|
||||
video.playbackRate = app.previewSpeed;
|
||||
|
||||
return {
|
||||
element: video,
|
||||
destroy() {
|
||||
@@ -99,5 +103,8 @@ export function attachVideoPlayer(video: HTMLVideoElement): VideoController {
|
||||
video.currentTime = clamped;
|
||||
setCurrentTime(clamped);
|
||||
},
|
||||
setPlaybackRate(rate: number) {
|
||||
video.playbackRate = rate;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user