Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# See https://help.github.com/ignore-files/ for more about ignoring files.

.vscode

# dependencies
/node_modules

Expand Down
60 changes: 26 additions & 34 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,48 +1,40 @@
import React, { Component } from 'react';
import AudioAnalyser from './AudioAnalyser';
import React, { useState } from "react";
import AudioAnalyser from "./AudioAnalyser";

class App extends Component {
constructor(props) {
super(props);
this.state = {
audio: null
};
this.toggleMicrophone = this.toggleMicrophone.bind(this);
}
function App() {
const [audio, setAudio] = useState(null);

async getMicrophone() {
const getMicrophone = async () => {
const audio = await navigator.mediaDevices.getUserMedia({
audio: true,
video: false
video: false,
});
this.setState({ audio });
}
setAudio(audio);
};

stopMicrophone() {
this.state.audio.getTracks().forEach(track => track.stop());
this.setState({ audio: null });
}
const stopMicrophone = () => {
audio.getTracks().forEach((track) => track.stop());
setAudio(null);
};

toggleMicrophone() {
if (this.state.audio) {
this.stopMicrophone();
const toggleMicrophone = () => {
if (audio) {
stopMicrophone();
} else {
this.getMicrophone();
getMicrophone();
}
}
};

render() {
return (
<div className="App">
<div className="controls">
<button onClick={this.toggleMicrophone}>
{this.state.audio ? 'Stop microphone' : 'Get microphone input'}
</button>
</div>
{this.state.audio ? <AudioAnalyser audio={this.state.audio} /> : ''}
return (
<div className="App">
<div className="controls">
<button onClick={toggleMicrophone}>
{audio ? "Stop microphone" : "Get microphone input"}
</button>
</div>
);
}
{audio ? <AudioAnalyser audio={audio} /> : ""}
</div>
);
}

export default App;
69 changes: 33 additions & 36 deletions src/AudioAnalyser.js
Original file line number Diff line number Diff line change
@@ -1,38 +1,35 @@
import React, { Component } from 'react';
import AudioVisualiser from './AudioVisualiser';

class AudioAnalyser extends Component {
constructor(props) {
super(props);
this.state = { audioData: new Uint8Array(0) };
this.tick = this.tick.bind(this);
}

componentDidMount() {
this.audioContext = new (window.AudioContext ||
window.webkitAudioContext)();
this.analyser = this.audioContext.createAnalyser();
this.dataArray = new Uint8Array(this.analyser.frequencyBinCount);
this.source = this.audioContext.createMediaStreamSource(this.props.audio);
this.source.connect(this.analyser);
this.rafId = requestAnimationFrame(this.tick);
}

tick() {
this.analyser.getByteTimeDomainData(this.dataArray);
this.setState({ audioData: this.dataArray });
this.rafId = requestAnimationFrame(this.tick);
}

componentWillUnmount() {
cancelAnimationFrame(this.rafId);
this.analyser.disconnect();
this.source.disconnect();
}

render() {
return <AudioVisualiser audioData={this.state.audioData} />;
}
}
import React, { useState, useEffect } from "react";
import AudioVisualiser from "./AudioVisualiser";

const AudioAnalyser = ({ audio }) => {
const [audioData, setAudioData] = useState(new Uint8Array(0));

useEffect(() => {
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
const analyser = audioContext.createAnalyser();
// const dataArray = new Uint8Array(analyser.frequencyBinCount);
const source = audioContext.createMediaStreamSource(audio);
source.connect(analyser);

const tick = () => {
const dataArray = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteTimeDomainData(dataArray);
// setAudioData(new Uint8Array(dataArray));
setAudioData(dataArray);
rafId = requestAnimationFrame(tick);
};

let rafId = requestAnimationFrame(tick);

return () => {
cancelAnimationFrame(rafId);
analyser.disconnect();
source.disconnect();
};
}, [audio]);

return <AudioVisualiser audioData={audioData} />;
};


export default AudioAnalyser;
62 changes: 28 additions & 34 deletions src/AudioVisualiser.js
Original file line number Diff line number Diff line change
@@ -1,42 +1,36 @@
import React, { Component } from 'react';
import React, { useRef, useEffect } from 'react';

class AudioVisualiser extends Component {
constructor(props) {
super(props);
this.canvas = React.createRef();
}
const AudioVisualiser = ({ audioData }) => {
const canvasRef = useRef();

componentDidUpdate() {
this.draw();
}
useEffect(() => {
const draw = () => {
const canvas = canvasRef.current;
const height = canvas.height;
const width = canvas.width;
const context = canvas.getContext('2d');
let x = 0;
const sliceWidth = (width * 1.0) / audioData.length;

draw() {
const { audioData } = this.props;
const canvas = this.canvas.current;
const height = canvas.height;
const width = canvas.width;
const context = canvas.getContext('2d');
let x = 0;
const sliceWidth = (width * 1.0) / audioData.length;
context.lineWidth = 2;
context.strokeStyle = '#000000';
context.clearRect(0, 0, width, height);

context.lineWidth = 2;
context.strokeStyle = '#000000';
context.clearRect(0, 0, width, height);
context.beginPath();
context.moveTo(0, height / 2);
for (const item of audioData) {
const y = (item / 255.0) * height;
context.lineTo(x, y);
x += sliceWidth;
}
context.lineTo(x, height / 2);
context.stroke();
};

context.beginPath();
context.moveTo(0, height / 2);
for (const item of audioData) {
const y = (item / 255.0) * height;
context.lineTo(x, y);
x += sliceWidth;
}
context.lineTo(x, height / 2);
context.stroke();
}
draw();
}, [audioData]);

render() {
return <canvas width="300" height="300" ref={this.canvas} />;
}
}
return <canvas width="300" height="300" ref={canvasRef} />;
};

export default AudioVisualiser;