loader.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. /*
  2. ----------------------------------------------------------
  3. MIDI.Plugin : 0.3.4 : 2015-03-26
  4. ----------------------------------------------------------
  5. https://github.com/mudcube/MIDI.js
  6. ----------------------------------------------------------
  7. Inspired by javax.sound.midi (albeit a super simple version):
  8. http://docs.oracle.com/javase/6/docs/api/javax/sound/midi/package-summary.html
  9. ----------------------------------------------------------
  10. Technologies
  11. ----------------------------------------------------------
  12. Web MIDI API - no native support yet (jazzplugin)
  13. Web Audio API - firefox 25+, chrome 10+, safari 6+, opera 15+
  14. HTML5 Audio Tag - ie 9+, firefox 3.5+, chrome 4+, safari 4+, opera 9.5+, ios 4+, android 2.3+
  15. ----------------------------------------------------------
  16. */
  17. if (typeof MIDI === 'undefined') MIDI = {};
  18. MIDI.Soundfont = MIDI.Soundfont || {};
  19. MIDI.Player = MIDI.Player || {};
  20. (function(root) { 'use strict';
  21. root.DEBUG = true;
  22. root.USE_XHR = true;
  23. root.soundfontUrl = './soundfont/';
  24. /*
  25. MIDI.loadPlugin({
  26. onsuccess: function() { },
  27. onprogress: function(state, percent) { },
  28. targetFormat: 'mp3', // optionally can force to use MP3 (for instance on mobile networks)
  29. instrument: 'acoustic_grand_piano', // or 1 (default)
  30. instruments: [ 'acoustic_grand_piano', 'acoustic_guitar_nylon' ] // or multiple instruments
  31. });
  32. */
  33. root.loadPlugin = function(opts) {
  34. if (typeof opts === 'function') {
  35. opts = {onsuccess: opts};
  36. }
  37. root.soundfontUrl = opts.soundfontUrl || root.soundfontUrl;
  38. /// Detect the best type of audio to use
  39. root.audioDetect(function(supports) {
  40. var hash = window.location.hash;
  41. var api = '';
  42. /// use the most appropriate plugin if not specified
  43. if (supports[opts.api]) {
  44. api = opts.api;
  45. } else if (supports[hash.substr(1)]) {
  46. api = hash.substr(1);
  47. } else if (supports.webmidi) {
  48. api = 'webmidi';
  49. } else if (window.AudioContext) { // Chrome
  50. api = 'webaudio';
  51. } else if (window.Audio) { // Firefox
  52. api = 'audiotag';
  53. }
  54. if (connect[api]) {
  55. /// use audio/ogg when supported
  56. if (opts.targetFormat) {
  57. var audioFormat = opts.targetFormat;
  58. } else { // use best quality
  59. var audioFormat = supports['audio/ogg'] ? 'ogg' : 'mp3';
  60. }
  61. /// load the specified plugin
  62. root.__api = api;
  63. root.__audioFormat = audioFormat;
  64. root.supports = supports;
  65. root.loadResource(opts);
  66. }
  67. });
  68. };
  69. /*
  70. root.loadResource({
  71. onsuccess: function() { },
  72. onprogress: function(state, percent) { },
  73. instrument: 'banjo'
  74. })
  75. */
  76. root.loadResource = function(opts) {
  77. var instruments = opts.instruments || opts.instrument || 'acoustic_grand_piano';
  78. ///
  79. if (typeof instruments !== 'object') {
  80. if (instruments || instruments === 0) {
  81. instruments = [instruments];
  82. } else {
  83. instruments = [];
  84. }
  85. }
  86. /// convert numeric ids into strings
  87. for (var i = 0; i < instruments.length; i ++) {
  88. var instrument = instruments[i];
  89. if (instrument === +instrument) { // is numeric
  90. if (root.GM.byId[instrument]) {
  91. instruments[i] = root.GM.byId[instrument].id;
  92. }
  93. }
  94. }
  95. ///
  96. opts.format = root.__audioFormat;
  97. opts.instruments = instruments;
  98. ///
  99. connect[root.__api](opts);
  100. };
  101. var connect = {
  102. webmidi: function(opts) {
  103. // cant wait for this to be standardized!
  104. root.WebMIDI.connect(opts);
  105. },
  106. audiotag: function(opts) {
  107. // works ok, kinda like a drunken tuna fish, across the board
  108. // http://caniuse.com/audio
  109. requestQueue(opts, 'AudioTag');
  110. },
  111. webaudio: function(opts) {
  112. // works awesome! safari, chrome and firefox support
  113. // http://caniuse.com/web-audio
  114. requestQueue(opts, 'WebAudio');
  115. }
  116. };
  117. var requestQueue = function(opts, context) {
  118. var audioFormat = opts.format;
  119. var instruments = opts.instruments;
  120. var onprogress = opts.onprogress;
  121. var onerror = opts.onerror;
  122. ///
  123. var length = instruments.length;
  124. var pending = length;
  125. var waitForEnd = function() {
  126. if (!--pending) {
  127. onprogress && onprogress('load', 1.0);
  128. root[context].connect(opts);
  129. }
  130. };
  131. ///
  132. for (var i = 0; i < length; i ++) {
  133. var instrumentId = instruments[i];
  134. if (MIDI.Soundfont[instrumentId]) { // already loaded
  135. waitForEnd();
  136. } else { // needs to be requested
  137. sendRequest(instruments[i], audioFormat, function(evt, progress) {
  138. var fileProgress = progress / length;
  139. var queueProgress = (length - pending) / length;
  140. onprogress && onprogress('load', fileProgress + queueProgress, instrumentId);
  141. }, function() {
  142. waitForEnd();
  143. }, onerror);
  144. }
  145. };
  146. };
  147. var sendRequest = function(instrumentId, audioFormat, onprogress, onsuccess, onerror) {
  148. var soundfontPath = root.soundfontUrl + instrumentId + '-' + audioFormat + '.js';
  149. if (root.USE_XHR) {
  150. root.util.request({
  151. url: soundfontPath,
  152. format: 'text',
  153. onerror: onerror,
  154. onprogress: onprogress,
  155. onsuccess: function(event, responseText) {
  156. var script = document.createElement('script');
  157. script.language = 'javascript';
  158. script.type = 'text/javascript';
  159. script.text = responseText;
  160. document.body.appendChild(script);
  161. ///
  162. onsuccess();
  163. }
  164. });
  165. } else {
  166. dom.loadScript.add({
  167. url: soundfontPath,
  168. verify: 'MIDI.Soundfont["' + instrumentId + '"]',
  169. onerror: onerror,
  170. onsuccess: function() {
  171. onsuccess();
  172. }
  173. });
  174. }
  175. };
  176. root.setDefaultPlugin = function(midi) {
  177. for (var key in midi) {
  178. root[key] = midi[key];
  179. }
  180. };
  181. })(MIDI);