-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathVisualiser.tsx
96 lines (80 loc) · 2.73 KB
/
Visualiser.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import React, { useCallback, useRef } from "react";
import { DataType } from "components/nodes/Analyser/index";
import useAnimationFrame from "hooks/useAnimationFrame";
import { AnalyserNode } from "utils/audioContext";
interface OwnProps {
node: AnalyserNode;
paused: boolean;
type: DataType;
}
type Props = OwnProps & React.ComponentProps<"canvas">;
function drawTimeDomainData(context: CanvasRenderingContext2D, data: Uint8Array) {
let x = 0;
const height = context.canvas.height;
const width = context.canvas.width;
const bufferLength = data.length;
const sliceWidth = width / bufferLength;
context.fillStyle = "#001400";
context.fillRect(0, 0, width, 256);
context.lineWidth = 2;
context.strokeStyle = "#00c800";
context.beginPath();
context.moveTo(x, height - ((data[0] / 128.0) * height) / 2);
for (let i = 1; i < bufferLength; i++) {
const y = ((data[i] / 128.0) * height) / 2;
context.lineTo(x, height - y);
x += sliceWidth;
}
context.stroke();
}
function drawFrequencyData(context: CanvasRenderingContext2D, data: Uint8Array) {
let x = 0;
const height = context.canvas.height;
const width = context.canvas.width;
const bufferLength = data.length;
const barWidth = width / bufferLength;
context.fillStyle = "#001400";
context.fillRect(0, 0, width, height);
context.fillStyle = "#00c800";
for (let i = 0; i < bufferLength; i++) {
const barHeight = height * (data[i] / 255.0);
const y = height - barHeight;
context.fillRect(x, y, barWidth, barHeight);
x += barWidth;
}
}
function Visualiser({ node, paused, type, ...canvasProps }: Props) {
const audioData = useRef(new Uint8Array(node.frequencyBinCount));
const canvasRef = useRef<HTMLCanvasElement>(null);
const draw = useCallback(() => {
const canvas = canvasRef.current;
const context = canvas?.getContext("2d");
if (!canvas || !context) {
return;
}
if (type === DataType.TimeDomain) {
drawTimeDomainData(context, audioData.current);
} else if (type === DataType.Frequency) {
drawFrequencyData(context, audioData.current);
}
}, [type]);
const getData = useCallback(() => {
const bufferLength = node.frequencyBinCount;
const dataArray = new Uint8Array(bufferLength);
if (type === DataType.TimeDomain) {
node.getByteTimeDomainData(dataArray);
} else if (type === DataType.Frequency) {
node.getByteFrequencyData(dataArray);
}
audioData.current = dataArray;
}, [node, type]);
const tick = useCallback(() => {
if (!paused) {
getData();
draw();
}
}, [draw, getData, paused]);
useAnimationFrame(tick);
return <canvas ref={canvasRef} style={{ display: "block" }} {...canvasProps} />;
}
export default React.memo(Visualiser);