Skip to content

Instantly share code, notes, and snippets.

@battlesnake
Created February 3, 2021 21:33
Show Gist options
  • Save battlesnake/7719c7f3a18e936515f8c1087334a673 to your computer and use it in GitHub Desktop.
Save battlesnake/7719c7f3a18e936515f8c1087334a673 to your computer and use it in GitHub Desktop.
Dirty and simple web audio demo, plotting oscilloscope and spectrum
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Audio stuff</title>
<style>
html,
body {
height: 100%;
padding: 0;
margin: 0;
}
body {
background: black;
overflow: hidden;
}
.view,
.bars {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.bars {
display: flex;
}
.bar {
flex-grow: 1;
}
.freq .bars {
align-items: flex-end;
}
.time .bars {
align-items: center;
}
.freq .bar {
background: white;
}
.time .bar {
background: green;
}
.freq .labels {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
align-items: flex-end;
justify-content: space-between;
}
.freq .label {
font-family: monospace;
font-size: 14px;
color: yellow;
font-weight: bold;
box-shadow: 0px 0px 0px 2px rgba(0,0,0,1);
}
</style>
</head>
<body>
<div class="freq view">
<div class="bars">
</div>
<div class="labels">
<div class="label fmin">
</div>
<div class="label fmid">
</div>
<div class="label fmax">
</div>
</div>
</div>
<div class="time view">
<div class="bars">
</div>
</div>
<script>
(() => {
const um = navigator.getUserMedia({
video: false,
audio: true
}, callback, console.log)
let ctx
let anal
let buffer
function callback(stream) {
ctx = new AudioContext({
sampleRate: 48000,
latencyHint: 'interactive'
})
mic = ctx.createMediaStreamSource(stream)
anal = ctx.createAnalyser()
anal.fftSize = 512
anal.smoothingTimeConstant = 0.8
bufferLength = anal.frequencyBinCount
buffer = new Uint8Array(bufferLength)
mic.connect(anal)
// anal.connect(ctx.destination)
analyse()
}
function plotFreq() {
anal.getByteFrequencyData(buffer)
const elements = []
const range = 60
for (let i = 0; i < anal.frequencyBinCount; ++i) {
const db = 20 * Math.log10(buffer[i] / 255)
const height = Math.max((db + range) / range, 0) * 100
elements.push(`<div class="bar" style="height: ${height}%;"></div>`)
}
document.querySelector('.freq .bars').innerHTML = elements.join('')
const max_freq = anal.frequencyBinCount * ctx.sampleRate / anal.fftSize / 1000
document.querySelector('.freq .label.fmid').innerHTML = `${(max_freq / 2).toFixed(1)}kHz`
document.querySelector('.freq .label.fmax').innerHTML = `${max_freq.toFixed(1)}kHz`
}
function plotTime() {
anal.getByteTimeDomainData(buffer)
const elements = []
for (let i = 0; i < anal.frequencyBinCount; ++i) {
const height = Math.abs(buffer[i] - 128) * 100 / 128
elements.push(`<div class="bar" style="height: ${height}%;"></div>`)
}
document.querySelector('.time .bars').innerHTML = elements.join('')
}
function analyse() {
setTimeout(analyse, 100)
plotFreq()
plotTime()
}
})()
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment