/* ---------------------------------------------------------- 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);