BPM.prototype = new Addon(); // assign prototype to marqer
BPM.constructor = BPM; // re-assign constructor
/**
* @summary
* BPM calculates beat per minutes based on a 'tap' function
* Tapped BPM Example on codepen:
* <a href="https://codepen.io/xangadix/pen/drqzPr" target="_blank">codepen</a>
*
* @description
* BPM returns a floating point between 1 and 0, in sync with a bpm the BPM is calculated based on a 'tap' function
*
* @example
* var mixer1 = new Mixer( renderer, { source1: mySource, source2: myOtherSource })
* var bpm = new BPM( renderer );
* bpm.add( mixer1.pod )
* window.addEventListener('keypress', function(ev) {
* if (ev.which == 13) bpm.tap()
* })
*
* @constructor Addon#BPM
* @implements Addon
* @param {GlRenderer} renderer
* @param {Object} options optional
*/
function BPM( renderer, options ) {
var _self = this
_self.function_list = [
["AUTO", "method", "toggleAutoBpm"],
["MODDOWN", "method", "modDown"],
["MODUP", "method", "modUp"],
["MOD", "method", "modNum"]
]
// only return the functionlist
if ( renderer == undefined ) return
// exposed variables.
_self.uuid = "BPM_" + (((1+Math.random())*0x100000000)|0).toString(16).substring(1);
window["bpm_" + _self.uuid]
_self.type = "Addon"
// set options
_self.options = {}
if ( options != undefined ) _self.options = options
/**
* @description Beats Per Minute
* @member Addon#BPM#bpm
* @param {number} Beats per minute
*
* actual Beats Per Minute
*
*/
_self.bpm = 128
/**
* @description Tapping beat control
* @member Addon#BPM#bps
*
* beats per second
*
*/
_self.bps = 2.133333 //
/**
* @description Second counter
* @member Addon#BPM#sec
*
* second counter, from which the actual float is calculated
*
*/
_self.sec = 0 //
/**
* @description
* BPM Float, current *position* of the BPM
* If the BMP is a Sinus going up and down, the float shows up where it is on the curve
* 'up' is 1 and down is '0', oscillating.
* @member Addon#BPM#bpm_float
*/
_self.bpm_float = 0.46875 // 60 / 128, current float of bpm
/**
* @description Tapping beat control
* @member Addon#BPM#mod
*/
_self.mod = 1 // 0.25, 0.5, 1, 2, 4, etc.
/**
* @description Audio analysis
* @member Addon#BPM#useAutoBpm#
* @member Addon#BPM#autoBpmData#
* @member Addon#BPM#tempodata_bpm#
* @member Addon#BPM#audio_src
* @member Addon#BPM#useMicrophone
*/
_self.useAutoBpm = false // auto bpm
_self.tempodata_bpm = 128 // from music
_self.mute = false
_self.autoBpmData = {} // info object for the auto bpm
_self.audio_src = "" // audio file or stream (useMicrophone = false)
// TODO
_self.useMicrophone = false // use useMicrophone for autoBPM
// DEPRICATED
_self.bypass = false
// source.renderer ?
var nodes = []
// counter
var c = 0
// add to renderer
renderer.add( _self )
// main ----------------------------------------------------------------------
// init with a tap contoller
_self.init = function() {
console.log("init BPM contoller.")
// initialize autoBPM with an audio object
// initializeAutoBpm()
}
// UPDATE
var starttime = (new Date()).getTime()
_self.update = function() {
if ( _self.bypass ) return
// rename useAnalyser?
//if ( _self.useAutoBpm ) {
// _self.bpm = _self.tempodata_bpm
//}
if ( !_self.disabled ) {
nodes.forEach( function( node ) {
node( _self.render() );
});
}
c = ((new Date()).getTime() - starttime) / 1000;
_self.sec = c * Math.PI * (_self.bpm * _self.mod) / 60 // * _self.mod
_self.bpm_float = ( Math.sin( _self.sec ) + 1 ) / 2 // Math.sin( 128 / 60 )
}
// add nodes, implicit
_self.add = function( _func ) {
nodes.push( _func )
}
_self.render = function() {
// returns current bpm 'position' as a value between 0 - 1
return _self.bpm_float
}
// actual --------------------------------------------------------------------
/**
* @description double the bpm
* @function Addon#BPM#modUp
*/
_self.modUp = function() { _self.mod *= 2; }
/**
* @description half the bpm
* @function Addon#BPM#modDown
*/
_self.modDown = function() { _self.mod *= .5; }
_self.modNum = function(_num) {
console.log("MOD ", _num)
var oldState = _self.useAutoBpm
_self.mod = _num;
_self.useAutoBpm = oldState
}
_self.toggleAutoBpm = function( _num ) {
_self.useAutoBpm = !_self.useAutoBpm
console.log("--->", _self.useAutoBpm )
}
_self.turnOff = function() {
bpm.audio.muted = false
bpm.useAutoBpm = false
}
// ---------------------------------------------------------------------------
// Tapped beat control
var last = Number(new Date());
var bpms = [ 128, 128 ,128 ,128 ,128 ];
var time = 0;
var avg = 0;
/**
* @description Tapping beat control
* @function Addon#BPM#tap
*/
_self.tap = function() {
_self.useAutoBPM = false
time = Number(new Date()) - last
last = Number(new Date());
if ( time < 10000 && time > 10 ) {
bpms.splice(0,1)
bpms.push( 60000/time )
avg = bpms.reduce(function(a, b) { return a + b; }) / bpms.length;
_self.bpm = avg
_self.bps = avg/60
}
}
/**
* @description Gets the current BPM (in bpm, as render() gives a float)
* @function Addon#BPM#getBpm
*/
_self.getBpm = function() {
return _self.bpm
}
console.log("set keypress")
window.addEventListener('keypress', function(ev) {
console.log(">>> ", ev.which)
if ( ev.which == 116 || ev.which == 32 ) {
_self.tap()
console.log(_self.bpm)
}
})
} // end BPM