199 lines
5.4 KiB
JavaScript
199 lines
5.4 KiB
JavaScript
|
/*
|
||
|
----------------------------------------------------------
|
||
|
MIDI.Plugin : 0.3.4 : 2015-03-26
|
||
|
----------------------------------------------------------
|
||
|
https://github.com/mudcube/MIDI.js
|
||
|
----------------------------------------------------------
|
||
|
Inspired by javax.sound.midi (albeit a super simple version):
|
||
|
http://docs.oracle.com/javase/6/docs/api/javax/sound/midi/package-summary.html
|
||
|
----------------------------------------------------------
|
||
|
Technologies
|
||
|
----------------------------------------------------------
|
||
|
Web MIDI API - no native support yet (jazzplugin)
|
||
|
Web Audio API - firefox 25+, chrome 10+, safari 6+, opera 15+
|
||
|
HTML5 Audio Tag - ie 9+, firefox 3.5+, chrome 4+, safari 4+, opera 9.5+, ios 4+, android 2.3+
|
||
|
----------------------------------------------------------
|
||
|
*/
|
||
|
|
||
|
if (typeof MIDI === 'undefined') MIDI = {};
|
||
|
|
||
|
MIDI.Soundfont = MIDI.Soundfont || {};
|
||
|
MIDI.Player = MIDI.Player || {};
|
||
|
|
||
|
(function(root) { 'use strict';
|
||
|
|
||
|
root.DEBUG = true;
|
||
|
root.USE_XHR = true;
|
||
|
root.soundfontUrl = './soundfont/';
|
||
|
|
||
|
/*
|
||
|
MIDI.loadPlugin({
|
||
|
onsuccess: function() { },
|
||
|
onprogress: function(state, percent) { },
|
||
|
targetFormat: 'mp3', // optionally can force to use MP3 (for instance on mobile networks)
|
||
|
instrument: 'acoustic_grand_piano', // or 1 (default)
|
||
|
instruments: [ 'acoustic_grand_piano', 'acoustic_guitar_nylon' ] // or multiple instruments
|
||
|
});
|
||
|
*/
|
||
|
|
||
|
root.loadPlugin = function(opts) {
|
||
|
if (typeof opts === 'function') {
|
||
|
opts = {onsuccess: opts};
|
||
|
}
|
||
|
|
||
|
root.soundfontUrl = opts.soundfontUrl || root.soundfontUrl;
|
||
|
|
||
|
/// Detect the best type of audio to use
|
||
|
root.audioDetect(function(supports) {
|
||
|
var hash = window.location.hash;
|
||
|
var api = '';
|
||
|
|
||
|
/// use the most appropriate plugin if not specified
|
||
|
if (supports[opts.api]) {
|
||
|
api = opts.api;
|
||
|
} else if (supports[hash.substr(1)]) {
|
||
|
api = hash.substr(1);
|
||
|
} else if (supports.webmidi) {
|
||
|
api = 'webmidi';
|
||
|
} else if (window.AudioContext) { // Chrome
|
||
|
api = 'webaudio';
|
||
|
} else if (window.Audio) { // Firefox
|
||
|
api = 'audiotag';
|
||
|
}
|
||
|
|
||
|
if (connect[api]) {
|
||
|
/// use audio/ogg when supported
|
||
|
if (opts.targetFormat) {
|
||
|
var audioFormat = opts.targetFormat;
|
||
|
} else { // use best quality
|
||
|
var audioFormat = supports['audio/ogg'] ? 'ogg' : 'mp3';
|
||
|
}
|
||
|
|
||
|
/// load the specified plugin
|
||
|
root.__api = api;
|
||
|
root.__audioFormat = audioFormat;
|
||
|
root.supports = supports;
|
||
|
root.loadResource(opts);
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
root.loadResource({
|
||
|
onsuccess: function() { },
|
||
|
onprogress: function(state, percent) { },
|
||
|
instrument: 'banjo'
|
||
|
})
|
||
|
*/
|
||
|
|
||
|
root.loadResource = function(opts) {
|
||
|
var instruments = opts.instruments || opts.instrument || 'acoustic_grand_piano';
|
||
|
///
|
||
|
if (typeof instruments !== 'object') {
|
||
|
if (instruments || instruments === 0) {
|
||
|
instruments = [instruments];
|
||
|
} else {
|
||
|
instruments = [];
|
||
|
}
|
||
|
}
|
||
|
/// convert numeric ids into strings
|
||
|
for (var i = 0; i < instruments.length; i ++) {
|
||
|
var instrument = instruments[i];
|
||
|
if (instrument === +instrument) { // is numeric
|
||
|
if (root.GM.byId[instrument]) {
|
||
|
instruments[i] = root.GM.byId[instrument].id;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
///
|
||
|
opts.format = root.__audioFormat;
|
||
|
opts.instruments = instruments;
|
||
|
///
|
||
|
connect[root.__api](opts);
|
||
|
};
|
||
|
|
||
|
var connect = {
|
||
|
webmidi: function(opts) {
|
||
|
// cant wait for this to be standardized!
|
||
|
root.WebMIDI.connect(opts);
|
||
|
},
|
||
|
audiotag: function(opts) {
|
||
|
// works ok, kinda like a drunken tuna fish, across the board
|
||
|
// http://caniuse.com/audio
|
||
|
requestQueue(opts, 'AudioTag');
|
||
|
},
|
||
|
webaudio: function(opts) {
|
||
|
// works awesome! safari, chrome and firefox support
|
||
|
// http://caniuse.com/web-audio
|
||
|
requestQueue(opts, 'WebAudio');
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var requestQueue = function(opts, context) {
|
||
|
var audioFormat = opts.format;
|
||
|
var instruments = opts.instruments;
|
||
|
var onprogress = opts.onprogress;
|
||
|
var onerror = opts.onerror;
|
||
|
///
|
||
|
var length = instruments.length;
|
||
|
var pending = length;
|
||
|
var waitForEnd = function() {
|
||
|
if (!--pending) {
|
||
|
onprogress && onprogress('load', 1.0);
|
||
|
root[context].connect(opts);
|
||
|
}
|
||
|
};
|
||
|
///
|
||
|
for (var i = 0; i < length; i ++) {
|
||
|
var instrumentId = instruments[i];
|
||
|
if (MIDI.Soundfont[instrumentId]) { // already loaded
|
||
|
waitForEnd();
|
||
|
} else { // needs to be requested
|
||
|
sendRequest(instruments[i], audioFormat, function(evt, progress) {
|
||
|
var fileProgress = progress / length;
|
||
|
var queueProgress = (length - pending) / length;
|
||
|
onprogress && onprogress('load', fileProgress + queueProgress, instrumentId);
|
||
|
}, function() {
|
||
|
waitForEnd();
|
||
|
}, onerror);
|
||
|
}
|
||
|
};
|
||
|
};
|
||
|
|
||
|
var sendRequest = function(instrumentId, audioFormat, onprogress, onsuccess, onerror) {
|
||
|
var soundfontPath = root.soundfontUrl + instrumentId + '-' + audioFormat + '.js';
|
||
|
if (root.USE_XHR) {
|
||
|
root.util.request({
|
||
|
url: soundfontPath,
|
||
|
format: 'text',
|
||
|
onerror: onerror,
|
||
|
onprogress: onprogress,
|
||
|
onsuccess: function(event, responseText) {
|
||
|
var script = document.createElement('script');
|
||
|
script.language = 'javascript';
|
||
|
script.type = 'text/javascript';
|
||
|
script.text = responseText;
|
||
|
document.body.appendChild(script);
|
||
|
///
|
||
|
onsuccess();
|
||
|
}
|
||
|
});
|
||
|
} else {
|
||
|
dom.loadScript.add({
|
||
|
url: soundfontPath,
|
||
|
verify: 'MIDI.Soundfont["' + instrumentId + '"]',
|
||
|
onerror: onerror,
|
||
|
onsuccess: function() {
|
||
|
onsuccess();
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
};
|
||
|
|
||
|
root.setDefaultPlugin = function(midi) {
|
||
|
for (var key in midi) {
|
||
|
root[key] = midi[key];
|
||
|
}
|
||
|
};
|
||
|
|
||
|
})(MIDI);
|