2021-10-08 14:38:35 +00:00
|
|
|
import { useEffect, useState, useRef } from 'react';
|
2021-11-02 16:20:47 +00:00
|
|
|
import { Frames } from './App';
|
|
|
|
import { MediaSet } from './generated/media_set';
|
2021-10-08 14:38:35 +00:00
|
|
|
import { WaveformCanvas } from './WaveformCanvas';
|
|
|
|
import { secsToCanvasX } from './Helpers';
|
2021-11-06 20:52:47 +00:00
|
|
|
import { from, Observable } from 'rxjs';
|
2021-10-08 14:38:35 +00:00
|
|
|
|
|
|
|
interface Props {
|
|
|
|
mediaSet: MediaSet;
|
|
|
|
position: number;
|
|
|
|
viewport: Frames;
|
|
|
|
offsetPixels: number;
|
|
|
|
}
|
|
|
|
|
|
|
|
export const CanvasLogicalWidth = 2000;
|
|
|
|
export const CanvasLogicalHeight = 500;
|
|
|
|
|
|
|
|
export const Waveform: React.FC<Props> = ({
|
|
|
|
mediaSet,
|
|
|
|
position,
|
|
|
|
viewport,
|
|
|
|
offsetPixels,
|
|
|
|
}: Props) => {
|
2021-11-06 20:52:47 +00:00
|
|
|
const [peaks, setPeaks] = useState<Observable<number[]>>(from([]));
|
2021-10-08 14:38:35 +00:00
|
|
|
const hudCanvasRef = useRef<HTMLCanvasElement>(null);
|
|
|
|
|
|
|
|
// effects
|
|
|
|
|
|
|
|
// load peaks on MediaSet change
|
|
|
|
useEffect(() => {
|
|
|
|
(async function () {
|
|
|
|
if (mediaSet == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let endFrame = viewport.end;
|
|
|
|
if (endFrame <= viewport.start) {
|
2021-11-02 16:20:47 +00:00
|
|
|
endFrame = mediaSet.audioFrames;
|
2021-10-08 14:38:35 +00:00
|
|
|
}
|
|
|
|
|
2021-11-02 16:20:47 +00:00
|
|
|
// const resp = await fetch(
|
|
|
|
// `http://localhost:8888/api/media_sets/${mediaSet.id}/peaks?start=${viewport.start}&end=${endFrame}&bins=${CanvasLogicalWidth}`
|
|
|
|
// );
|
|
|
|
// const newPeaks = await resp.json();
|
|
|
|
// setPeaks(newPeaks);
|
2021-10-08 14:38:35 +00:00
|
|
|
})();
|
|
|
|
}, [mediaSet, viewport]);
|
|
|
|
|
|
|
|
// render HUD
|
|
|
|
useEffect(() => {
|
|
|
|
const canvas = hudCanvasRef.current;
|
|
|
|
if (canvas == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const ctx = canvas.getContext('2d');
|
|
|
|
if (ctx == null) {
|
|
|
|
console.error('no hud 2d context available');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
|
|
|
|
|
|
if (mediaSet == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-11-02 16:20:47 +00:00
|
|
|
const x = secsToCanvasX(position, mediaSet.audioSampleRate, viewport);
|
2021-10-08 14:38:35 +00:00
|
|
|
if (x == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx.strokeStyle = 'red';
|
|
|
|
ctx.beginPath();
|
|
|
|
ctx.moveTo(x, 0);
|
|
|
|
ctx.lineWidth = 4;
|
|
|
|
ctx.lineTo(x, canvas.height);
|
|
|
|
ctx.stroke();
|
|
|
|
}, [viewport, position]);
|
|
|
|
|
|
|
|
// render component
|
|
|
|
|
|
|
|
const containerStyles = {
|
|
|
|
background: 'black',
|
|
|
|
margin: '0 ' + offsetPixels + 'px',
|
|
|
|
flexGrow: 1,
|
|
|
|
position: 'relative',
|
|
|
|
} as React.CSSProperties;
|
|
|
|
|
|
|
|
const canvasStyles = {
|
|
|
|
position: 'absolute',
|
|
|
|
width: '100%',
|
|
|
|
height: '100%',
|
|
|
|
display: 'block',
|
|
|
|
} as React.CSSProperties;
|
|
|
|
|
|
|
|
return (
|
|
|
|
<>
|
|
|
|
<div style={containerStyles}>
|
|
|
|
<WaveformCanvas
|
|
|
|
peaks={peaks}
|
2021-11-06 20:52:47 +00:00
|
|
|
channels={mediaSet.audioChannels}
|
2021-10-08 14:38:35 +00:00
|
|
|
width={CanvasLogicalWidth}
|
|
|
|
height={CanvasLogicalHeight}
|
|
|
|
strokeStyle="green"
|
|
|
|
fillStyle="black"
|
|
|
|
zIndex={0}
|
|
|
|
alpha={1}
|
|
|
|
></WaveformCanvas>
|
|
|
|
<canvas
|
|
|
|
width={CanvasLogicalWidth}
|
|
|
|
height={CanvasLogicalHeight}
|
|
|
|
ref={hudCanvasRef}
|
|
|
|
style={canvasStyles}
|
|
|
|
></canvas>
|
|
|
|
</div>
|
|
|
|
</>
|
|
|
|
);
|
|
|
|
};
|