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; }