Skip to content

Commit 8f91c87

Browse files
committed
Addressing comments of the recent review
Fixes FFT being corrupted when multiple instances of Webamp exist and are playing at the same time Fixes multiple Webamp instances fighting over what the current state of the Main Window really is Moved a lot of global mutable variables to instead be owned by BarPaintHandler and PaintWavHandler Renamed visualizer functions since they now handle a lot of things
1 parent 4356be8 commit 8f91c87

File tree

2 files changed

+280
-227
lines changed

2 files changed

+280
-227
lines changed

packages/webamp/js/components/Vis.tsx

Lines changed: 79 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,4 @@
1-
import React, {
2-
useMemo,
3-
useCallback,
4-
useState,
5-
useLayoutEffect,
6-
useEffect,
7-
} from "react";
1+
import React, { useMemo, useState, useLayoutEffect, useEffect } from "react";
82

93
import * as Actions from "../actionCreators";
104
import * as Selectors from "../selectors";
@@ -23,25 +17,20 @@ type Props = {
2317
analyser: AnalyserNode;
2418
};
2519

26-
export let PIXEL_DENSITY = 1;
27-
export let renderHeight: number;
28-
export let doubled: boolean | undefined;
29-
export let smallVis: boolean | undefined;
30-
export let isMWOpen: boolean | undefined;
31-
3220
// Pre-render the background grid
3321
function preRenderBg(
3422
width: number,
3523
height: number,
3624
bgColor: string,
3725
fgColor: string,
38-
windowShade: boolean
26+
windowShade: boolean,
27+
pixelDensity: number
3928
): HTMLCanvasElement {
4029
// Off-screen canvas for pre-rendering the background
4130
const bgCanvas = document.createElement("canvas");
4231
bgCanvas.width = width;
4332
bgCanvas.height = height;
44-
const distance = 2 * PIXEL_DENSITY;
33+
const distance = 2 * pixelDensity;
4534

4635
const bgCanvasCtx = bgCanvas.getContext("2d");
4736
if (bgCanvasCtx == null) {
@@ -52,8 +41,8 @@ function preRenderBg(
5241
if (!windowShade) {
5342
bgCanvasCtx.fillStyle = fgColor;
5443
for (let x = 0; x < width; x += distance) {
55-
for (let y = PIXEL_DENSITY; y < height; y += distance) {
56-
bgCanvasCtx.fillRect(x, y, PIXEL_DENSITY, PIXEL_DENSITY);
44+
for (let y = pixelDensity; y < height; y += distance) {
45+
bgCanvasCtx.fillRect(x, y, pixelDensity, pixelDensity);
5746
}
5847
}
5948
}
@@ -64,78 +53,100 @@ export default function Vis({ analyser }: Props) {
6453
useLayoutEffect(() => {
6554
analyser.fftSize = 1024;
6655
}, [analyser, analyser.fftSize]);
56+
6757
const colors = useTypedSelector(Selectors.getSkinColors);
6858
const mode = useTypedSelector(Selectors.getVisualizerStyle);
6959
const audioStatus = useTypedSelector(Selectors.getMediaStatus);
7060
const getWindowShade = useTypedSelector(Selectors.getWindowShade);
7161
const getWindowOpen = useTypedSelector(Selectors.getWindowOpen);
72-
isMWOpen = getWindowOpen("main");
73-
doubled = useTypedSelector(Selectors.getDoubled);
74-
const dummyVizData = useTypedSelector(Selectors.getDummyVizData);
62+
const isMWOpen = getWindowOpen("main");
63+
const doubled = useTypedSelector(Selectors.getDoubled);
7564
const toggleVisualizerStyle = useActionCreator(Actions.toggleVisualizerStyle);
7665
const windowShade = getWindowShade("main");
7766

78-
smallVis = windowShade && isMWOpen;
67+
const smallVis = windowShade && isMWOpen;
68+
const renderHeight = smallVis ? 5 : 16;
7969
const renderWidth = 76;
80-
const renderWidthBG = !isMWOpen
81-
? renderWidth
82-
: windowShade
83-
? (doubled ? renderWidth : 38)
84-
: renderWidth * PIXEL_DENSITY;
85-
86-
renderHeight = smallVis ? 5 : 16;
87-
PIXEL_DENSITY = doubled && smallVis ? 2 : 1;
88-
89-
const width = renderWidth * PIXEL_DENSITY;
90-
const height = renderHeight * PIXEL_DENSITY;
70+
const pixelDensity = doubled && smallVis ? 2 : 1;
71+
const renderWidthBG = !isMWOpen
72+
? renderWidth
73+
: windowShade
74+
? doubled
75+
? renderWidth
76+
: 38
77+
: renderWidth * pixelDensity;
78+
79+
const width = renderWidth * pixelDensity;
80+
const height = renderHeight * pixelDensity;
9181

9282
const bgCanvas = useMemo(() => {
9383
return preRenderBg(
9484
renderWidthBG,
9585
height,
9686
colors[0],
9787
colors[1],
98-
Boolean(windowShade)
88+
Boolean(windowShade),
89+
pixelDensity
9990
);
100-
}, [colors, height, width, windowShade]);
91+
}, [colors, height, renderWidthBG, windowShade, pixelDensity]);
10192

10293
const [canvas, setCanvas] = useState<HTMLCanvasElement | null>(null);
10394

10495
//? painter administration
105-
const [painter, setPainter] = useState<VisPaintHandler | null>(null);
106-
107-
useEffect(() => {
108-
if (!canvas) return;
109-
const _setPainter = (PainterType: typeof VisPaintHandler) => {
110-
const _vis: IVis = {
111-
canvas,
112-
colors,
113-
analyser,
114-
oscStyle: "lines",
115-
bandwidth: "wide",
116-
coloring: "normal",
117-
peaks: true,
118-
saFalloff: "moderate",
119-
saPeakFalloff: "slow",
120-
sa: "analyzer",
121-
};
122-
const newPainter = new PainterType(_vis);
123-
setPainter(newPainter);
96+
const painter = useMemo(() => {
97+
if (!canvas) return null;
98+
99+
const vis: IVis = {
100+
canvas,
101+
colors,
102+
analyser,
103+
oscStyle: "lines",
104+
bandwidth: "wide",
105+
coloring: "normal",
106+
peaks: true,
107+
saFalloff: "moderate",
108+
saPeakFalloff: "slow",
109+
sa: "analyzer",
110+
renderHeight,
111+
smallVis,
112+
pixelDensity,
113+
doubled,
114+
isMWOpen,
124115
};
116+
125117
switch (mode) {
126118
case VISUALIZERS.OSCILLOSCOPE:
127-
_setPainter(WavePaintHandler);
128-
break;
119+
return new WavePaintHandler(vis);
129120
case VISUALIZERS.BAR:
130-
_setPainter(BarPaintHandler);
131-
break;
121+
return new BarPaintHandler(vis);
132122
case VISUALIZERS.NONE:
133-
_setPainter(NoVisualizerHandler);
134-
break;
123+
return new NoVisualizerHandler(vis);
135124
default:
136-
_setPainter(NoVisualizerHandler);
125+
return new NoVisualizerHandler(vis);
137126
}
138-
}, [analyser, canvas, mode, colors]);
127+
}, [
128+
analyser,
129+
canvas,
130+
mode,
131+
colors,
132+
renderHeight,
133+
smallVis,
134+
pixelDensity,
135+
doubled,
136+
isMWOpen,
137+
]);
138+
139+
useEffect(() => {
140+
if (canvas && painter) {
141+
const canvasCtx = canvas.getContext("2d");
142+
if (canvasCtx) {
143+
// wipes the canvas clean if playback is paused and doubled is changing
144+
if (audioStatus === MEDIA_STATUS.PAUSED) {
145+
canvasCtx.clearRect(0, 0, canvas.width, canvas.height);
146+
}
147+
}
148+
}
149+
}, [doubled, canvas, painter]);
139150

140151
useEffect(() => {
141152
if (canvas == null || painter == null) {
@@ -151,37 +162,31 @@ export default function Vis({ analyser }: Props) {
151162
let animationRequest: number | null = null;
152163

153164
const loop = () => {
154-
if (mode === VISUALIZERS.NONE) {
155-
canvasCtx.clearRect(0, 0, renderWidthBG, height);
156-
} else {
157-
canvasCtx.drawImage(bgCanvas, 0, 0);
158-
}
165+
canvasCtx.drawImage(bgCanvas, 0, 0);
159166
painter.prepare();
160167
painter.paintFrame();
161168
animationRequest = window.requestAnimationFrame(loop);
162169
};
163170

164171
if (audioStatus === MEDIA_STATUS.PLAYING) {
165-
loop();
166-
} else if (animationRequest !== null) {
167-
// Clean up the animation frame request if the status is not PLAYING
168-
window.cancelAnimationFrame(animationRequest);
169-
animationRequest = null;
172+
if (mode === VISUALIZERS.NONE) {
173+
canvasCtx.clearRect(0, 0, renderWidthBG, height);
174+
} else {
175+
loop();
176+
}
170177
}
171178

172179
return () => {
173180
if (animationRequest !== null) {
174181
window.cancelAnimationFrame(animationRequest);
175182
}
176183
};
177-
}, [audioStatus, canvas, painter, bgCanvas]);
184+
}, [audioStatus, canvas, painter, bgCanvas, renderWidthBG, height, mode]);
178185

179186
if (audioStatus === MEDIA_STATUS.STOPPED) {
180187
return null;
181188
}
182-
// @ts-ignore
183189

184-
// @ts-ignore
185190
return (
186191
<canvas
187192
id="visualizer"

0 commit comments

Comments
 (0)