Created
November 8, 2015 11:59
-
-
Save kevinzhang96/e3ca6ae693c4870a6dd4 to your computer and use it in GitHub Desktop.
Script for parsing BPM
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
var audioobj = document.getElementsByTagName("audio")[0]; | |
// var text = document.getElementById("text"); | |
var actualBPM; | |
var request = new XMLHttpRequest(); | |
console.log("Audio source: " + audioobj.src); | |
request.open('GET', audioobj.src, true); | |
request.responseType = 'arraybuffer'; | |
var targetspd = 1; | |
request.onload = function() { | |
console.log("Handling request now"); | |
//Create offline context | |
var OfflineContext = window.OfflineAudioContext || window.webkitOfflineAudioContext; | |
var offlineContext = new OfflineContext(1, 2, 44100); | |
offlineContext.decodeAudioData(request.response, function(buffer) { | |
console.log("1"); | |
// Create buffer source | |
var source = offlineContext.createBufferSource(); | |
source.buffer = buffer; | |
// Create filter | |
var filter = offlineContext.createBiquadFilter(); | |
filter.type = "lowpass"; | |
console.log("2"); | |
// Pipe the song into the filter, and the filter into the offline context | |
source.connect(filter); | |
filter.connect(offlineContext.destination); | |
// Schedule the song to start playing at time:0 | |
source.start(0); | |
var peaks, | |
initialThresold = 0.9, | |
thresold = initialThresold, | |
minThresold = 0.3, | |
minPeaks = 30; | |
console.log("3"); | |
do { | |
peaks = getPeaksAtThreshold(buffer.getChannelData(0), thresold); | |
thresold -= 0.05; | |
} while (peaks.length < minPeaks && thresold >= minThresold); | |
var intervals = countIntervalsBetweenNearbyPeaks(peaks); | |
var groups = groupNeighborsByTempo(intervals, buffer.sampleRate); | |
var top = groups.sort(function(intA, intB) { | |
return intB.count - intA.count; | |
}).splice(0, 5); | |
// text.innerText=Math.round(top[0].tempo); | |
actualBPM = Math.round(top[0].tempo); | |
console.log("Actual BPM: " + actualBPM); | |
audioobj.play(); | |
var c = function() { | |
audioobj.playbackRate += (targetspd - audio.playbackRate) * 0.1; | |
//console.log("playbackrate " + audio.playbackRate); | |
var x = setTimeout(requestAnimationFrame(c), 1000 / 16); | |
} | |
c(); | |
}); | |
}; | |
request.send(); | |
function countIntervalsBetweenNearbyPeaks(peaks) { | |
var intervalCounts = []; | |
peaks.forEach(function(peak, index) { | |
for (var i = 0; i < 10; i++) { | |
var interval = peaks[index + i] - peak; | |
var foundInterval = intervalCounts.some(function(intervalCount) { | |
if (intervalCount.interval === interval) | |
return intervalCount.count++; | |
}); | |
if (!foundInterval) { | |
intervalCounts.push({ | |
interval: interval, | |
count: 1 | |
}); | |
} | |
} | |
}); | |
return intervalCounts; | |
} | |
function groupNeighborsByTempo(intervalCounts, sampleRate) { | |
var tempoCounts = []; | |
intervalCounts.forEach(function(intervalCount, i) { | |
if (intervalCount.interval !== 0) { | |
// Convert an interval to tempo | |
var theoreticalTempo = 60 / (intervalCount.interval / sampleRate); | |
// Adjust the tempo to fit within the 90-180 BPM range | |
while (theoreticalTempo < 90) theoreticalTempo *= 2; | |
while (theoreticalTempo > 180) theoreticalTempo /= 2; | |
theoreticalTempo = Math.round(theoreticalTempo); | |
var foundTempo = tempoCounts.some(function(tempoCount) { | |
if (tempoCount.tempo === theoreticalTempo) | |
return tempoCount.count += intervalCount.count; | |
}); | |
if (!foundTempo) { | |
tempoCounts.push({ | |
tempo: theoreticalTempo, | |
count: intervalCount.count | |
}); | |
} | |
} | |
}); | |
return tempoCounts; | |
} | |
function getPeaksAtThreshold(data, threshold) { | |
var peaksArray = []; | |
var length = data.length; | |
for (var i = 0; i < length;) { | |
if (data[i] > threshold) { | |
peaksArray.push(i); | |
// Skip forward ~ 1/4s to get past this peak. | |
i += 10000; | |
} | |
i++; | |
} | |
return peaksArray; | |
} | |
var socket = io('http://localhost:3001'); | |
socket.on('kinect', function(msg) { | |
var bpm = Number(msg); | |
// $("#disp").text(bpm); | |
console.log("New bpm: " + bpm); | |
targetspd = bpm / actualBPM; //Number($("#text").text()); | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment