UNPKG

lingo3d

Version:

Lingo3D is a React/Vue 3d game development framework that ships with a complete visual editor

98 lines 4.21 kB
import { jsx as _jsx } from "preact/jsx-runtime"; import { Cancellable } from "@lincode/promiselikes"; import { memo } from "preact/compat"; import { useLayoutEffect, useMemo, useRef, useState } from "preact/hooks"; import { FRAME_HEIGHT, STANDARD_FRAME, FRAME_WIDTH } from "../../globals"; import { getTimelinePaused } from "../../states/useTimelinePaused"; import diffProps from "../utils/diffProps"; import useSyncState from "../hooks/useSyncState"; import { getTimeline } from "../../states/useTimeline"; import { getTimelineMute } from "../../states/useTimelineMute"; import getReactive from "../../utils/getReactive"; import { timelineFramePtr } from "../../pointers/timelineFramePtr"; import { timelineWaveSurferFrameSystem } from "../../systems/timelineWaveSurferFrameSystem"; import { timelineWaveSurferPlaybackSystem } from "../../systems/timelineWaveSurferPlaybackSystem"; const AudioRow = ({ instance, frames }) => { const src = useSyncState(instance.srcState.get); const durationReactive = useMemo(() => getReactive(instance, "duration"), []); const duration = useSyncState(durationReactive.get); const frameKeys = useMemo(() => Object.keys(frames), [frames]); const [startFrame, endFrame] = useMemo(() => { const startFrame = Number(frameKeys[0] ?? 0); return [ startFrame, frameKeys.length < 2 ? startFrame + Math.ceil(duration * STANDARD_FRAME) : Number(frameKeys.at(-1)) ]; }, [frameKeys, duration]); const width = endFrame * FRAME_WIDTH; const ref = useRef(null); const [waveSurfer, setWaveSurfer] = useState(); const paused = useSyncState(getTimelinePaused); const timeline = useSyncState(getTimeline); useLayoutEffect(() => { if (!duration || frameKeys.length >= 2 || !timeline) return; timeline.mergeData({ [instance.uuid]: { frames: { 0: 0, [endFrame]: 0 } } }); }, [duration, frameKeys, timeline, endFrame]); useLayoutEffect(() => { if (!waveSurfer || !timeline) return; if (!paused) { timelineWaveSurferPlaybackSystem.add(waveSurfer, { startFrame }); let pausedCount = 1; timeline.$animationStates.pausedCount += pausedCount; const audioContext = waveSurfer.backend.getAudioContext(); const timeout = setTimeout(() => { timeline.$animationStates.pausedCount -= pausedCount; pausedCount = 0; }, (audioContext.baseLatency + audioContext.outputLatency) * 1000); return () => { timelineWaveSurferPlaybackSystem.delete(waveSurfer); clearTimeout(timeout); waveSurfer.pause(); timeline.$animationStates.pausedCount -= pausedCount; }; } timelineWaveSurferFrameSystem.add(waveSurfer, { frame: timelineFramePtr[0], startFrame }); return () => { timelineWaveSurferFrameSystem.delete(waveSurfer); }; }, [waveSurfer, paused, timeline]); useLayoutEffect(() => { const div = ref.current; if (!div || !src || !width) return; const handle = new Cancellable(); import("wavesurfer.js").then(({ default: WaveSurfer }) => { if (handle.done) return; const waveSurfer = WaveSurfer.create({ container: div, waveColor: "magenta", progressColor: "magenta", // progressColor: "rgb(63, 0, 63)", height: FRAME_HEIGHT }); handle.then(() => waveSurfer.destroy()); waveSurfer.load(src); setWaveSurfer(waveSurfer); handle.watch(getTimelineMute((val) => waveSurfer.setMute(val))); }); return () => { handle.cancel(); setWaveSurfer(undefined); }; }, [src, width]); return _jsx("div", { ref: ref, style: { width, left: startFrame * FRAME_WIDTH } }); }; export default memo(AudioRow, diffProps); //# sourceMappingURL=AudioRow.js.map