bpm-detective
Version:
Detects the BPM of a song or audio sample
2 lines (1 loc) • 3.37 kB
JavaScript
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.DetectBPM=f()}})(function(){var define,module,exports;return function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r}()({1:[function(require,module,exports){"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.default=detect;var OfflineContext=window.OfflineAudioContext||window.webkitOfflineAudioContext;function detect(buffer){var source=getLowPassSource(buffer);source.start(0);return[findPeaks,identifyIntervals,groupByTempo(buffer.sampleRate),getTopCandidate].reduce(function(state,fn){return fn(state)},source.buffer.getChannelData(0))}function getTopCandidate(candidates){return candidates.sort(function(a,b){return b.count-a.count}).splice(0,5)[0].tempo}function getLowPassSource(buffer){var length=buffer.length,numberOfChannels=buffer.numberOfChannels,sampleRate=buffer.sampleRate;var context=new OfflineContext(numberOfChannels,length,sampleRate);var source=context.createBufferSource();source.buffer=buffer;var filter=context.createBiquadFilter();filter.type="lowpass";source.connect(filter);filter.connect(context.destination);return source}function findPeaks(data){var peaks=[];var threshold=.9;var minThresold=.3;var minPeaks=15;while(peaks.length<minPeaks&&threshold>=minThresold){peaks=findPeaksAtThreshold(data,threshold);threshold-=.05}if(peaks.length<minPeaks){throw new Error("Could not find enough samples for a reliable detection.")}return peaks}function findPeaksAtThreshold(data,threshold){var peaks=[];for(var i=0,l=data.length;i<l;i+=1){if(data[i]>threshold){peaks.push(i);i+=1e4}}return peaks}function identifyIntervals(peaks){var intervals=[];peaks.forEach(function(peak,index){var _loop=function _loop(i){var interval=peaks[index+i]-peak;var foundInterval=intervals.some(function(intervalCount){if(intervalCount.interval===interval){return intervalCount.count+=1}});if(!foundInterval){intervals.push({interval:interval,count:1})}};for(var i=0;i<10;i+=1){_loop(i)}});return intervals}function groupByTempo(sampleRate){return function(intervalCounts){var tempoCounts=[];intervalCounts.forEach(function(intervalCount){if(intervalCount.interval!==0){var theoreticalTempo=60/(intervalCount.interval/sampleRate);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}}},{}],2:[function(require,module,exports){module.exports=require("./detect").default},{"./detect":1}]},{},[2])(2)});