Improve waveform selection behaviour
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Rob Watson 2021-12-13 05:10:07 +01:00
parent c8de6643e8
commit 34681821e4
2 changed files with 18 additions and 36 deletions

View File

@ -210,26 +210,26 @@ function App(): JSX.Element {
setPositionFromFrame(newViewport.start);
},
[mediaSet, audio, video]
[mediaSet, audio, video, selection]
);
// handler called when the selection in the main waveform view is changed.
const handleWaveformSelectionChange = useCallback(
(selection: Frames) => {
setSelection(selection);
(newSelection: Frames) => {
setSelection(newSelection);
if (mediaSet == null) {
return;
}
// move playback position to start of selection
const ratio = selection.start / mediaSet.audioFrames;
const ratio = newSelection.start / mediaSet.audioFrames;
const currentTime =
(mediaSet.audioFrames / mediaSet.audioSampleRate) * ratio;
audio.currentTime = currentTime;
video.currentTime = currentTime;
},
[mediaSet, audio, video]
[mediaSet, audio, video, selection]
);
const handlePlay = useCallback(() => {

View File

@ -71,30 +71,20 @@ export const Waveform: React.FC<Props> = ({
setPositionPixels(null);
return;
}
const logicalPixelsPerFrame =
CanvasLogicalWidth / (viewport.end - viewport.start);
const positionPixels = (frame - viewport.start) * logicalPixelsPerFrame;
const pixelsPerFrame = CanvasLogicalWidth / (viewport.end - viewport.start);
const positionPixels = (frame - viewport.start) * pixelsPerFrame;
setPositionPixels(positionPixels);
}, [mediaSet, position, viewport]);
// update selectedPixels on viewport change
useEffect(() => {
const start = frameToCanvasX(selectedFrames.start);
const end = frameToCanvasX(selectedFrames.end);
// more verbose than it has to be to make TypeScript happy
if (start == null && end == null) {
setSelectedPixels({ start: 0, end: 0 });
} else if (start == null && end != null) {
setSelectedPixels({ start: 0, end: end });
} else if (start != null && end == null) {
setSelectedPixels({ start: 0, end: CanvasLogicalWidth });
} else if (start != null && end != null) {
setSelectedPixels({ start, end });
} else {
console.error('unreachable');
}
}, [viewport]);
const start = Math.max(frameToCanvasX(selectedFrames.start), 0);
const end = Math.min(
frameToCanvasX(selectedFrames.end),
CanvasLogicalWidth
);
setSelectedPixels({ start, end });
}, [viewport, selectedFrames]);
// handlers
@ -112,26 +102,18 @@ export const Waveform: React.FC<Props> = ({
setSelectedFrames(selectedFrames);
onSelectionChange(selectedFrames);
},
[viewport]
[viewport, selectedFrames]
);
// helpers
const frameToCanvasX = useCallback(
(frame: number): number | null => {
if (mediaSet == null) {
return null;
}
if (frame < viewport.start || frame > viewport.end) {
return null;
}
(frame: number): number => {
const pixelsPerFrame =
CanvasLogicalWidth / (viewport.end - viewport.start);
return (frame - viewport.start) * pixelsPerFrame;
return Math.round((frame - viewport.start) * pixelsPerFrame);
},
[mediaSet, viewport]
[viewport]
);
// render component