diff --git a/src/music/features/musicplayer/MusicPlayer.tsx b/src/music/features/musicplayer/MusicPlayer.tsx
index abb3cfb..b6fd92a 100644
--- a/src/music/features/musicplayer/MusicPlayer.tsx
+++ b/src/music/features/musicplayer/MusicPlayer.tsx
@@ -7,12 +7,10 @@ import { musicPlayer } from "./musicPlayerSlice";
function MusicPlayer() {
return (
-
-
-
+
diff --git a/src/music/features/visualizer/Renderer.ts b/src/music/features/visualizer/Renderer.ts
index bfc688d..0baea06 100644
--- a/src/music/features/visualizer/Renderer.ts
+++ b/src/music/features/visualizer/Renderer.ts
@@ -11,11 +11,14 @@ class RendererError extends Error {}
class Renderer {
private canvas: HTMLCanvasElement;
+ private overlay: HTMLSpanElement;
private analyser: AnalyserNode;
private analyserData: Uint8Array;
- private time: number;
+ private lastFrameTime: number;
+ private dTime: number;
+
private buffers: {
indices?: WebGLBuffer;
positions?: WebGLBuffer;
@@ -26,7 +29,8 @@ class Renderer {
constructor(
context: AudioContext,
node: AudioNode,
- canvas: HTMLCanvasElement
+ canvas: HTMLCanvasElement,
+ overlay: HTMLSpanElement
) {
const analyser = context.createAnalyser();
analyser.fftSize = 2048;
@@ -34,10 +38,12 @@ class Renderer {
node.connect(analyser);
this.canvas = canvas;
+ this.overlay = overlay;
this.analyser = analyser;
this.analyserData = new Uint8Array(analyser.frequencyBinCount);
- this.time = 0;
+ this.lastFrameTime = 0;
+ this.dTime = 0;
this.buffers = {};
}
@@ -150,7 +156,7 @@ class Renderer {
mat4.rotateY(
modelViewMatrix,
modelViewMatrix,
- this.time * ROTATION_SPEED
+ this.lastFrameTime * ROTATION_SPEED
);
mat4.translate(modelViewMatrix, modelViewMatrix, [-1.0, 0.0, 0.0]);
gl.uniformMatrix4fv(
@@ -222,6 +228,8 @@ class Renderer {
gl.vertexAttribDivisor(shader.getAttribute("aHeight"), 1);
gl.enableVertexAttribArray(shader.getAttribute("aHeight"));
+ const cpuTime = Math.round(performance.now() - this.lastFrameTime);
+
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.drawElementsInstanced(
gl.TRIANGLES,
@@ -231,8 +239,16 @@ class Renderer {
this.analyser.frequencyBinCount
);
+ const gpuTime = Math.round(performance.now() - this.lastFrameTime);
+
+ this.overlay.innerText = `${Math.round(
+ this.dTime
+ )}ms (${cpuTime}ms / ${gpuTime}ms)`;
+
requestAnimationFrame((time) => {
- this.time = time;
+ this.dTime = time - this.lastFrameTime;
+ this.lastFrameTime = time;
+
this.drawScene(gl, shader);
});
}
diff --git a/src/music/features/visualizer/Visualizer.tsx b/src/music/features/visualizer/Visualizer.tsx
index a940a96..c45228e 100644
--- a/src/music/features/visualizer/Visualizer.tsx
+++ b/src/music/features/visualizer/Visualizer.tsx
@@ -11,19 +11,37 @@ function Visualizer({
}) {
const [renderError, setRenderError] = useState
(null);
- const canvas = useCallback(
- (canvas: HTMLCanvasElement | null) => {
+ const visualizer = useCallback(
+ (visualizer: HTMLDivElement | null) => {
// If we're rendering an error message, we won't be
- // setting a canvas.
+ // setting up the visualizer.
//
// Also, nonintuitively, renderError will be null here on
// subsequent iterations, so we can't rely on it to
// identify errors.
- if (canvas === null) {
+ if (visualizer === null) {
return;
}
- const renderer = new Renderer(audioContext, audioNode, canvas);
+ const canvas = visualizer.children[0];
+ const overlay = visualizer.children[1];
+
+ if (
+ !(canvas instanceof HTMLCanvasElement) ||
+ !(overlay instanceof HTMLSpanElement)
+ ) {
+ throw new Error(
+ "react did not create our visualizer div correctly"
+ );
+ }
+
+ const renderer = new Renderer(
+ audioContext,
+ audioNode,
+ canvas,
+ overlay
+ );
+
try {
renderer.initializeScene();
} catch (error) {
@@ -78,7 +96,18 @@ function Visualizer({
);
if (renderError === null) {
- return ;
+ return (
+
+
+
+
+ );
} else {
return renderError;
}
diff --git a/src/music/music.scss b/src/music/music.scss
index 364124e..ab93198 100644
--- a/src/music/music.scss
+++ b/src/music/music.scss
@@ -3,6 +3,12 @@ $fa-font-path: "npm:@fortawesome/fontawesome-free/webfonts";
@import "~/node_modules/@fortawesome/fontawesome-free/scss/fontawesome";
@import "~/node_modules/@fortawesome/fontawesome-free/scss/solid";
-.is-overflow-hidden {
- overflow: hidden !important;
+.is-relative {
+ position: relative !important;
+}
+
+.is-bottom-left {
+ bottom: 0;
+ left: 0;
+ position: absolute !important;
}