Last active
August 15, 2019 21:55
-
-
Save soxofaan/8a2ab706cbae8fb9c85eb02bf379bf12 to your computer and use it in GitHub Desktop.
Microphone Spectrum Analyser
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
license: mit | |
height: 500 | |
border: no |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<style> | |
body { | |
font-family: sans-serif; | |
} | |
</style> | |
<body> | |
<div id="target"> | |
<p>Access to microphone audio is required.</p> | |
</div> | |
<script src="https://d3js.org/d3.v5.min.js"></script> | |
<script> | |
function main() { | |
var target = d3.select("#target") | |
var AudioContext = window.AudioContext || window.webkitAudioContext | |
navigator.mediaDevices.getUserMedia({ audio: true }) | |
.then(function(stream) { init(stream); }) | |
.catch(function(reason) { | |
console.error(reason) | |
target.append("p").text("Failed to capture microphone audio.") | |
target.append("p").append("code").text(reason) | |
}) | |
function init(stream) { | |
// Set up audio source and analyser | |
console.log("Start capturing microphone audio") | |
var ctx = new AudioContext(); | |
var source = ctx.createMediaStreamSource(stream) | |
var analyser = ctx.createAnalyser() | |
var fftSize = 2048 | |
analyser.fftSize = fftSize | |
analyser.smoothingTimeConstant = 0.7 | |
analyser.maxDecibels = -20 | |
analyser.minDecibels = -100 | |
source.connect(analyser) | |
var maxFrequency = 5000 | |
var limit = Math.floor(fftSize * maxFrequency / ctx.sampleRate) | |
var bins = analyser.frequencyBinCount | |
var data = new Uint8Array(limit); | |
// Set up D3 elements | |
var width = 960 | |
var height = 500 | |
var svg = target.html("").append("svg").attr("width", width).attr("height", height) | |
var padding = 30 | |
var plot = svg.append("g") | |
.attr("class", "plot") | |
.attr("transform", "translate(" + padding + "," + (height - padding) + ")") | |
var xScale = d3.scaleLinear().domain([0, limit - 1]).range([0, width - 2 * padding]) | |
var yScale = d3.scaleLinear().domain([0, 255]).range([0, -height + 2 * padding]) | |
var colorScale = d3.interpolateRainbow | |
var axes = plot.append("g") | |
.attr("class", "axes") | |
.attr("font-size", 10) | |
axes.append("g").call(d3.axisBottom(xScale.copy().domain([0, limit * ctx.sampleRate / fftSize]))) | |
axes.append("text") | |
.attr("class", "label") | |
.attr("text-anchor", "end") | |
.attr("x", width - 2 * padding).attr("y", -5) | |
.text("Frequency (Hz)") | |
axes.append("g").call(d3.axisLeft(yScale.copy().domain([analyser.minDecibels, analyser.maxDecibels]))) | |
axes.append("text") | |
.attr("class", "label") | |
.attr("text-anchor", "start") | |
.attr("x", 5).attr("y", -height + 2 * padding) | |
.attr("dy", "0.5em") | |
.text("dB") | |
var chart = plot.append("g").attr("class", "chart") | |
// Draw functions | |
function fequencyColor(d, i) { | |
var x = Math.log2(i * ctx.sampleRate / fftSize) | |
return colorScale(x - Math.floor(x)) | |
} | |
function draw(data) { | |
var lollipops = chart.selectAll("g.lollipop") | |
.data(data) | |
var enter = lollipops.enter() | |
.append("g").attr("class", "lollipop") | |
enter.append("line") | |
.attr("x1", function (d, i) { return xScale(i); }) | |
.attr("y1", 0) | |
.attr("x2", function (d, i) { return xScale(i); }) | |
.attr("stroke", fequencyColor) | |
enter.append("circle") | |
.attr("r", 2) | |
.attr("cx", function (d, i) { return xScale(i); }) | |
.attr("fill", fequencyColor) | |
lollipops = lollipops.merge(enter) | |
lollipops | |
.select("circle") | |
.attr("cy", function (d, i) { return yScale(d); }) | |
lollipops | |
.select("line") | |
.attr("y2", function (d, i) { return yScale(d); }) | |
} | |
// Set up animation toggling | |
var timeout = 100 | |
function animate() { | |
analyser.getByteFrequencyData(data) | |
draw(data) | |
setTimeout(animate, timeout) | |
} | |
animate() | |
} | |
} | |
document.addEventListener('DOMContentLoaded', main) | |
</script> | |
</body> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment