Skip to content

Instantly share code, notes, and snippets.

@broady
Created January 17, 2018 05:49
Show Gist options
  • Save broady/c07dcc99e47c6c523a19e527261b4bc1 to your computer and use it in GitHub Desktop.
Save broady/c07dcc99e47c6c523a19e527261b4bc1 to your computer and use it in GitHub Desktop.
<!doctype html>
<script>
module = {};
</script>
<script src="https://cdn.jsdelivr.net/npm/webmidi"></script>
<script src="node_modules/beats/index.js"></script>
<script>
window.onload = function() {
navigator.getUserMedia({
audio: true,
}, function(stream) {
var ctx = new AudioContext();
var sampleRate = ctx.sampleRate;
var source = ctx.createMediaStreamSource(stream);
var analyser = ctx.createAnalyser();
analyser.fftSize = 2048; // 32768 max
source.connect(analyser);
var freq2Bin = function(freq) {
return Math.floor(freq / (ctx.sampleRate / analyser.fftSize));
};
var bins = [
{
lo: freq2Bin(20),
hi: freq2Bin(150),
},
{
lo: freq2Bin(150),
hi: freq2Bin(450),
},
{
lo: freq2Bin(450),
hi: freq2Bin(600),
},
];
var detector = beats(bins);
var squares = [
document.querySelector('#beat'),
document.querySelector('#beat2'),
document.querySelector('#beat3'),
];
var val = document.querySelector('#v');
var midiValues = [0, 0, 0];
var avgFrameRate = 60;
var frame = 0;
var freqData = new Uint8Array(freq2Bin(1000));
var lastFrame = +new Date;
function draw() {
requestAnimationFrame(draw);
var now = +new Date;
avgFrameRate = avgFrameRate * .2 + .8 * (1000 / (now - lastFrame));
frame++;
if (frame % 10 == 0) {
val.innerText = Math.floor(avgFrameRate) + 'fps';
frame = 0;
}
analyser.getByteFrequencyData(freqData);
var beatData = detector(freqData, now - lastFrame);
for (var i = 0; i < squares.length; i++) {
if (beatData[i] != 0) { // on beat
midiValues[i] = beatData[i] / 255;
} else {
midiValues[i] = midiValues[i] * .4; // decay
}
squares[i].style.opacity = midiValues[i];
if (midiOut) {
midiOut.sendPitchBend(midiValues[i] - .5, i+1);
}
}
lastFrame = now;
}
requestAnimationFrame(draw);
var midiOut;
WebMidi.enable(function(err) {
if (err) {
alert('WebMidi: '+ err);
return;
}
if (!WebMidi.outputs.length) {
console.log('no midi outputs');
return;
}
var selector = document.querySelector('#midiout');
for (var i = 0; i < WebMidi.outputs.length; i++) {
var option = document.createElement('option');
var out = WebMidi.outputs[i];
option.value = out.id;
option.label = out.name;
selector.appendChild(option);
}
midiOut = WebMidi.outputs[0];
});
}, function() {
alert('please allow audio')
})
};
</script>
<div id="beat"></div>
<div id="beat2"></div>
<div id="beat3"></div>
<div id="v"></div>
freq
<input type="range" min="0" max="500" id="freq_slider">
<div id="freq_indicator"></div>
Q
<input type="range" min="0" max="10" step="0.01" id="q_slider">
<div id="q_indicator"></div>
gain
<input type="range" min="0.1" max="5" step="0.01" id="gain_slider">
<div id="gain_indicator"></div>
<select id="midiout"></select>
<style>
#beat, #beat2, #beat3 {
width: 50px;
height: 50px;
background: black;
display: inline-block;
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment