I created an Audio visualizer using p5.js and React and i need some help.
I am trying to change the state of my button input text from Play
to Stop
when the song starts playing & from Stop
back to Play
when the user decides to stop the song at that moment.
I am using react-p5
library and everything works great until i setState
when a user clicks the play button. Since that causes a re render it breaks my canvas.
Is there a way to only re-render the button element? I am not too sure how i would go about changing the inner text of my button without a state change?
import React, { useState } from 'react';
import Sketch from 'react-p5';
import 'p5/lib/addons/p5.sound';
import Beat from '../../instrumental.mp3';
const App = () => {
let width = 900;
let height = 600;
let song;
let fft;
const [flag, setFlag] = useState(true);
const preload = (p) => {
p.soundFormats('mp3');
song = p.loadSound(Beat);
}
const setup = (p, canvasParentRef) => {
// react-p5 conveniently initializes window.p5 thats why all the other p5's
// have been changed to p in order to create an FFT object
fft = new p5.FFT();
// console.log(p.point)
// use parent to render the canvas in this ref
// without it p5 will render the canvas outside of this component
const canvas = p.createCanvas(width, height).parent(canvasParentRef);
}
const playStop = () => {
if (song.isPlaying()) {
song.pause();
setFlag(true);
//p.noLoop();
} else {
song.play();
setFlag(false);
//p.loop();
}
}
const draw = p => {
p.background(0);
// by default the stroke color is black
// we need to change this in order to see the wave
p.stroke(255, 204, 0);
// no fill in between waves
p.noFill();
// returns an array with 1024 elements
let wave = fft.waveform();
p.beginShape();
// By looping through the waveform data, we are able
// to draw the waveform across the canvas
for (let i = 0; i < width; i++) {
// create an index that maps the for loop variable
// to the index of the wave we want
// value must be integer thats we we use floor
let index = p.floor(p.map(i, 0, width, 0, wave.length));
let x = i;
let y = wave[index] * 100 + height / 2;
p.vertex(x, y);
}
p.endShape();
}
return (
<div className='outerbox'>
<h1>Audio Visualizer</h1>
<Sketch preload={preload} setup={setup} draw={draw}/>
{flag ? <button onClick={playStop}>Play</button> : <button onClick={playStop}>Stop</button>}
</div>
);
}
export default App;
The sad thing is there aren't many resources available that includes react + p5.js
If anyone would like to take the time and clone this repository down in order to see what the problem might be, i would very much appreciate that.
Repo link: https://github.com/imperium11/audio-visualizer
npm i
npm run dev-build
npm start