index.html 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>Document</title>
  7. <script src="./inc/shim/Base64.js"></script>
  8. <script src="./inc/shim/Base64binary.js"></script>
  9. <script src="./inc/shim/WebAudioAPI.js"></script>
  10. <script src="./inc/shim/WebMIDIAPI.js" type="text/javascript"></script>
  11. <!-- jasmid package -->
  12. <script src="./inc/jasmid/stream.js"></script>
  13. <script src="./inc/jasmid/midifile.js"></script>
  14. <script src="./inc/jasmid/replayer.js"></script>
  15. <script src="./js/midi/audioDetect.js" type="text/javascript"></script>
  16. <script src="./js/midi/gm.js"></script>
  17. <script src="./js/midi/loader.js"></script>
  18. <script src="./js/midi/plugin.audiotag.js"></script>
  19. <script src="./js/midi/plugin.webaudio.js"></script>
  20. <script src="./js/midi/plugin.webmidi.js"></script>
  21. <script src="./js/midi/player.js" type="text/javascript"></script>
  22. <script src="./js/midi/audioDetect.js"></script>
  23. <script src="./js/util/dom_request_xhr.js" type="text/javascript"></script>
  24. <script src="./js/util/dom_request_script.js" type="text/javascript"></script>
  25. <style>
  26. body {
  27. margin: 0px;
  28. padding: 0px;
  29. }
  30. select,
  31. button {
  32. border: 1px solid black;
  33. background-color: transparent;
  34. outline: none;
  35. font-weight: 400;
  36. padding: 1px 6px;
  37. }
  38. .huaji {
  39. background-color: transparent;
  40. background-image: url('./images/huaji1.png');
  41. background-repeat: no-repeat;
  42. background-size: contain;
  43. width: 28px;
  44. padding: 0px;
  45. padding-top: 59px;
  46. border: 0px;
  47. outline: 0px;
  48. appearance: none;
  49. }
  50. .huaji.down {
  51. background-image: url('./images/huaji2.png');
  52. }
  53. #openFile {
  54. display: none;
  55. }
  56. .play-mode {
  57. overflow: auto;
  58. word-wrap: none;
  59. white-space: nowrap;
  60. position: fixed;
  61. bottom: 0px;
  62. left: 0px;
  63. right: 0px;
  64. }
  65. .play-mode .huaji {
  66. width: 56px;
  67. padding-top: 118px;
  68. }
  69. #time {
  70. width: 40%;
  71. pointer-events: none;
  72. }
  73. .options>* {
  74. vertical-align: middle;
  75. }
  76. .options {
  77. padding: 10px 0px;
  78. overflow: auto;
  79. word-wrap: none;
  80. white-space: nowrap;
  81. }
  82. .options>*:first-child {
  83. margin-left: 8px !important;
  84. }
  85. .options>*:last-child {
  86. margin-right: 8px !important;
  87. }
  88. #keyboard {
  89. margin: auto 8px;
  90. }
  91. </style>
  92. </head>
  93. <body>
  94. <div class="options">
  95. <select onchange="openUrl('./midis/'+this.value+'.mid')">
  96. <option value="1" disabled selected>选择预置的乐谱</option>
  97. <optgroup label="万恶之源">
  98. <option value="Astronomia">Astronomia</option>
  99. <option value="aLIEz">aLIEz</option>
  100. </optgroup>
  101. <optgroup label="火星文">
  102. <option value="aLIEz">aLIEz</option>
  103. </optgroup>
  104. <optgroup label="某科学的超电磁炮">
  105. <option value="Only my railgun (full ver)">Only my railgun</option>
  106. <option value="Level 5 - Judgelight">Level 5 - Judgelight</option>
  107. <option value="Sister's Noise">Sister's Noise</option>
  108. </optgroup>
  109. <optgroup label="LoveLive!">
  110. <option value="SnowHalation">Snow Halation</option>
  111. <option value="Arifutarekanashiminohate">ありふれた悲しみの果て</option>
  112. </optgroup>
  113. </select>
  114. <input type="file" id="openFile" accept="audio/midi" onchange="openFile()">
  115. <button onclick="document.getElementById('openFile').click()">打开</button>
  116. <button id="play" onclick="play()">播放</button>
  117. <input type="range" id="time" value="0" readonly>
  118. <button onclick="stop()">停止</button>
  119. <label><input type="checkbox" onchange="modeChange()">弹奏模式</label>
  120. </div>
  121. <div style="margin: 0px 8px;"><i>如果你发现音乐好像有哪里不对,点一下停止然后重新开始播放就好!</i></div>
  122. <div id="keyboard">
  123. </div>
  124. <!-- <script src="midi.min.js"></script> -->
  125. <script>
  126. console.log(MIDI)
  127. var player;
  128. window.onload = function () {
  129. var press = false;
  130. var setPressTimeout;
  131. var keyboard = document.getElementById("keyboard")
  132. var buttons = []
  133. var time = document.getElementById("time")
  134. // console.log({keyboard})
  135. for (let index = 0; index < 88; index++) {
  136. var button = document.createElement("BUTTON")
  137. button.className = 'huaji';
  138. // button.classList.add("huaji")
  139. button.onmousedown = function () {
  140. this.classList.add("down")
  141. keyDown(index + 21)
  142. press = true
  143. }
  144. button.onmouseenter = function () {
  145. if (press) {
  146. this.classList.add("down")
  147. keyDown(index + 21)
  148. if (setPressTimeout) clearTimeout(setPressTimeout)
  149. }
  150. // console.log(index + 21 + "enter")
  151. }
  152. button.onmouseup = function () {
  153. this.classList.remove("down")
  154. keyUp(index + 21)
  155. press = false
  156. }
  157. button.onmouseleave = function () {
  158. this.classList.remove("down")
  159. keyUp(index + 21)
  160. if (press) setPressTimeout = setTimeout(function () {
  161. press = false
  162. }, 500);
  163. }
  164. button.innerText = MIDI.noteToKey[index + 21]
  165. buttons.push(button)
  166. keyboard.appendChild(button)
  167. }
  168. MIDI.loadPlugin({
  169. soundfontUrl: "./soundfont/",
  170. instruments: "acoustic_grand_piano",
  171. onprogress: function (state, progress) {
  172. // console.log(state, progress);
  173. },
  174. onsuccess: function () {
  175. var delay = 0; // play one note every quarter second
  176. var note = 50; // the MIDI note
  177. var velocity = 127; // how hard the note hits
  178. player = MIDI.Player
  179. player.addListener(function (data) {
  180. // console.log(data)
  181. var pianoKey = data.note - 21;
  182. // console.log('note', MIDI.noteToKey[data.note])
  183. if (data.message == 144) {
  184. time.value = data.now
  185. time.max = data.end
  186. buttons[pianoKey] && buttons[pianoKey].classList.add("down")
  187. } else {
  188. buttons[pianoKey] && buttons[pianoKey].classList.remove("down")
  189. }
  190. });
  191. player.timeWarp = 1; // speed the song is played back
  192. // play the note
  193. MIDI.setVolume(0, 127);
  194. }
  195. });
  196. function keyDown(note) {
  197. MIDI.noteOn(0, note, 127, 0);
  198. }
  199. function keyUp(note) {
  200. MIDI.noteOff(0, note, 0);
  201. }
  202. };
  203. function openFile() {
  204. // console.log("openFile",document.getElementById('openFile').files)
  205. if (document.getElementById('openFile').files.length > 0 && player) {
  206. playUrl(URL.createObjectURL(document.getElementById('openFile').files[0]))
  207. }
  208. }
  209. function openUrl(url) {
  210. player && playUrl(url)
  211. }
  212. function playUrl(url) {
  213. // console.log(player)
  214. player.loadFile(url, function () {
  215. player.start()
  216. document.getElementById("play").innerText = "暂停"
  217. });
  218. }
  219. function modeChange() {
  220. var keyboard = document.getElementById("keyboard")
  221. keyboard.classList[keyboard.classList.contains("play-mode") ? "remove" : "add"]("play-mode")
  222. }
  223. function play() {
  224. if (player && player.currentTime !== player.endTime) {
  225. if (player.playing) {
  226. document.getElementById("play").innerText = "播放"
  227. player.pause(true);
  228. } else {
  229. document.getElementById("play").innerText = "暂停"
  230. player.resume();
  231. }
  232. }
  233. }
  234. function stop() {
  235. if (player) {
  236. document.getElementById("play").innerText = "播放"
  237. player.stop();
  238. }
  239. }
  240. </script>
  241. </body>
  242. </html>