mirror of
https://github.com/Tonejs/Tone.js
synced 2025-01-10 10:58:52 +00:00
180 lines
4.5 KiB
JavaScript
180 lines
4.5 KiB
JavaScript
|
/**
|
||
|
* StartAudioContext.js
|
||
|
* @author Yotam Mann
|
||
|
* @license http://opensource.org/licenses/MIT MIT License
|
||
|
* @copyright 2016 Yotam Mann
|
||
|
*/
|
||
|
(function (root, factory) {
|
||
|
if (typeof define === "function" && define.amd) {
|
||
|
define([], factory);
|
||
|
} else if (typeof module === 'object' && module.exports) {
|
||
|
module.exports = factory();
|
||
|
} else {
|
||
|
root.StartAudioContext = factory();
|
||
|
}
|
||
|
}(this, function () {
|
||
|
|
||
|
/**
|
||
|
* The StartAudioContext object
|
||
|
*/
|
||
|
var StartAudioContext = {
|
||
|
/**
|
||
|
* The audio context passed in by the user
|
||
|
* @type {AudioContext}
|
||
|
*/
|
||
|
context : null,
|
||
|
/**
|
||
|
* The TapListeners bound to the elements
|
||
|
* @type {Array}
|
||
|
* @private
|
||
|
*/
|
||
|
_tapListeners : [],
|
||
|
/**
|
||
|
* Callbacks to invoke when the audio context is started
|
||
|
* @type {Array}
|
||
|
* @private
|
||
|
*/
|
||
|
_onStarted : [],
|
||
|
};
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Set the context
|
||
|
* @param {AudioContext} ctx
|
||
|
* @returns {StartAudioContext}
|
||
|
*/
|
||
|
StartAudioContext.setContext = function(ctx){
|
||
|
StartAudioContext.context = ctx;
|
||
|
return StartAudioContext;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Add a tap listener to the audio context
|
||
|
* @param {Array|Element|String|jQuery} element
|
||
|
* @returns {StartAudioContext}
|
||
|
*/
|
||
|
StartAudioContext.on = function(element){
|
||
|
if (Array.isArray(element) || (NodeList && element instanceof NodeList)){
|
||
|
for (var i = 0; i < element.length; i++){
|
||
|
StartAudioContext.on(element[i]);
|
||
|
}
|
||
|
} else if (typeof element === "string"){
|
||
|
StartAudioContext.on(document.querySelectorAll(element));
|
||
|
} else if (element.jquery && typeof element.toArray === "function"){
|
||
|
StartAudioContext.on(element.toArray());
|
||
|
} else if (Element && element instanceof Element){
|
||
|
//if it's an element, create a TapListener
|
||
|
var tap = new TapListener(element, onTap);
|
||
|
StartAudioContext._tapListeners.push(tap);
|
||
|
}
|
||
|
return StartAudioContext;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Bind a callback to when the audio context is started.
|
||
|
* @param {Function} cb
|
||
|
* @return {StartAudioContext}
|
||
|
*/
|
||
|
StartAudioContext.onStarted = function(cb){
|
||
|
//if it's already started, invoke the callback
|
||
|
if (StartAudioContext.isStarted()){
|
||
|
cb();
|
||
|
} else {
|
||
|
StartAudioContext._onStarted.push(cb);
|
||
|
}
|
||
|
return StartAudioContext;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* returns true if the context is started
|
||
|
* @return {Boolean}
|
||
|
*/
|
||
|
StartAudioContext.isStarted = function(){
|
||
|
return (StartAudioContext.context !== null && StartAudioContext.context.state === "running");
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* @class Listens for non-dragging tap ends on the given element
|
||
|
* @param {Element} element
|
||
|
* @internal
|
||
|
*/
|
||
|
var TapListener = function(element){
|
||
|
|
||
|
this._dragged = false;
|
||
|
|
||
|
this._element = element;
|
||
|
|
||
|
this._bindedMove = this._moved.bind(this);
|
||
|
this._bindedEnd = this._ended.bind(this);
|
||
|
|
||
|
element.addEventListener("touchmove", this._bindedMove);
|
||
|
element.addEventListener("touchend", this._bindedEnd);
|
||
|
element.addEventListener("mouseup", this._bindedEnd);
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* drag move event
|
||
|
*/
|
||
|
TapListener.prototype._moved = function(e){
|
||
|
this._dragged = true;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* tap ended listener
|
||
|
*/
|
||
|
TapListener.prototype._ended = function(e){
|
||
|
if (!this._dragged){
|
||
|
onTap();
|
||
|
}
|
||
|
this._dragged = false;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* remove all the bound events
|
||
|
*/
|
||
|
TapListener.prototype.dispose = function(){
|
||
|
this._element.removeEventListener("touchmove", this._bindedMove);
|
||
|
this._element.removeEventListener("touchend", this._bindedEnd);
|
||
|
this._element.removeEventListener("mouseup", this._bindedEnd);
|
||
|
this._bindedMove = null;
|
||
|
this._bindedEnd = null;
|
||
|
this._element = null;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Invoked the first time of the elements is tapped.
|
||
|
* Creates a silent oscillator when a non-dragging touchend
|
||
|
* event has been triggered.
|
||
|
*/
|
||
|
function onTap(){
|
||
|
|
||
|
//start the audio context with a silent oscillator
|
||
|
if (StartAudioContext.context && !StartAudioContext.isStarted()){
|
||
|
var osc = StartAudioContext.context.createOscillator();
|
||
|
var silent = StartAudioContext.context.createGain();
|
||
|
silent.gain.value = 0;
|
||
|
osc.connect(silent);
|
||
|
silent.connect(StartAudioContext.context.destination);
|
||
|
var now = StartAudioContext.context.currentTime;
|
||
|
osc.start(now);
|
||
|
osc.stop(now+0.5);
|
||
|
}
|
||
|
|
||
|
//dispose all the tap listeners
|
||
|
if (StartAudioContext._tapListeners){
|
||
|
for (var i = 0; i < StartAudioContext._tapListeners.length; i++){
|
||
|
StartAudioContext._tapListeners[i].dispose();
|
||
|
}
|
||
|
StartAudioContext._tapListeners = null;
|
||
|
}
|
||
|
//the onstarted callbacks
|
||
|
if (StartAudioContext._onStarted){
|
||
|
for (var j = 0; j < StartAudioContext._onStarted.length; j++){
|
||
|
StartAudioContext._onStarted[j]();
|
||
|
}
|
||
|
StartAudioContext._onStarted = null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return StartAudioContext;
|
||
|
}));
|