UNPKG

html-midi-player

Version:

MIDI file player and visualizer web components

9 lines (8 loc) 13.1 kB
/** * html-midi-player@1.5.0 * https://github.com/cifkao/html-midi-player.git * @author Ondřej Cífka (@cifkao) * @license BSD-2-Clause */ !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("@magenta/music/esm/core.js")):"function"==typeof define&&define.amd?define(["exports","@magenta/music/esm/core.js"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).midiPlayer={},t.core)}(this,(function(t,e){"use strict";function n(t,e,n,i,s,r,o){try{var a=t[r](o),l=a.value}catch(t){return void n(t)}a.done?e(l):Promise.resolve(l).then(i,s)}function i(t){return function(){var e=this,i=arguments;return new Promise((function(s,r){var o=t.apply(e,i);function a(t){n(o,s,r,a,l,"next",t)}function l(t){n(o,s,r,a,l,"throw",t)}a(void 0)}))}}var s=document.createElement("template");s.innerHTML="\n<style>\n".concat(":host {\n display: inline-block;\n width: 300px;\n margin: 3px;\n vertical-align: bottom;\n font-family: sans-serif;\n font-size: 14px;\n}\n\n:focus:not(.focus-visible) {\n outline: none;\n}\n\n.controls {\n width: inherit;\n height: inherit;\n box-sizing: border-box;\n display: flex;\n flex-direction: row;\n position: relative;\n overflow: hidden;\n align-items: center;\n border-radius: 100px;\n background: #f2f5f6;\n padding: 0 0.25em;\n user-select: none;\n}\n.controls > * {\n margin: 0.8em 0.45em;\n}\n.controls input, .controls button {\n cursor: pointer;\n}\n.controls input:disabled, .controls button:disabled {\n cursor: inherit;\n}\n.controls button {\n text-align: center;\n background: rgba(204, 204, 204, 0);\n border: none;\n width: 32px;\n height: 32px;\n border-radius: 100%;\n transition: background-color 0.25s ease 0s;\n padding: 0;\n}\n.controls button:not(:disabled):hover {\n background: rgba(204, 204, 204, 0.3);\n}\n.controls button:not(:disabled):active {\n background: rgba(204, 204, 204, 0.6);\n}\n.controls button .icon {\n display: none;\n}\n.controls button .icon, .controls button .icon svg {\n vertical-align: middle;\n}\n.controls button .icon svg {\n fill: currentColor;\n}\n.controls .seek-bar {\n flex: 1;\n min-width: 0;\n margin-right: 1.1em;\n background: transparent;\n}\n.controls .seek-bar::-moz-range-track {\n background-color: #555;\n}\n.controls.stopped .play-icon, .controls.playing .stop-icon, .controls.error .error-icon {\n display: inherit;\n}\n.controls.frozen > div, .controls > button:disabled .icon {\n opacity: 0.5;\n}\n.controls .overlay {\n z-index: 0;\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n margin: 0;\n box-sizing: border-box;\n display: none;\n opacity: 1;\n}\n.controls.loading .loading-overlay {\n display: block;\n background: linear-gradient(110deg, #92929200 5%, #92929288 25%, #92929200 45%);\n background-size: 250% 100%;\n background-repeat: repeat-y;\n animation: shimmer 1.5s linear infinite;\n}\n\n@keyframes shimmer {\n 0% {\n background-position: 125% 0;\n }\n 100% {\n background-position: -200% 0;\n }\n}",'\n</style>\n<div class="controls stopped frozen" part="control-panel">\n <button class="play" part="play-button" disabled>\n <span class="icon play-icon">').concat('<svg width="24" height="24" version="1.1" viewBox="0 0 6.35 6.35" xmlns="http://www.w3.org/2000/svg">\n <path d="m4.4979 3.175-2.1167 1.5875v-3.175z" stroke-width=".70201"/>\n</svg>\n','</span>\n <span class="icon stop-icon">').concat('<svg width="24" height="24" version="1.1" viewBox="0 0 6.35 6.35" xmlns="http://www.w3.org/2000/svg">\n <path d="m1.8521 1.5875v3.175h0.92604v-3.175zm1.7198 0v3.175h0.92604v-3.175z" stroke-width=".24153"/>\n</svg>\n','</span>\n <span class="icon error-icon">').concat('<svg width="24" height="24" version="1.1" viewBox="0 0 6.35 6.35" xmlns="http://www.w3.org/2000/svg">\n <path transform="scale(.26458)" d="m12 3.5a8.4993 8.4993 0 0 0-8.5 8.5 8.4993 8.4993 0 0 0 8.5 8.5 8.4993 8.4993 0 0 0 8.5-8.5 8.4993 8.4993 0 0 0-8.5-8.5zm-1.4062 3.5h3v6h-3v-6zm0 8h3v2h-3v-2z"/>\n</svg>\n','</span>\n </button>\n <div part="time"><span class="current-time" part="current-time">0:00</span> / <span class="total-time" part="total-time">0:00</span></div>\n <input type="range" min="0" max="0" value="0" step="any" class="seek-bar" part="seek-bar" disabled>\n <div class="overlay loading-overlay" part="loading-overlay"></div>\n</div>\n');var r=document.createElement("template");function o(t){var e=t<0,n=(t=Math.floor(Math.abs(t||0)))%60,i=(t-n)/60,s=(t-n-60*i)/3600,r=n>9?"".concat(n):"0".concat(n),o=i>9||!s?"".concat(i,":"):"0".concat(i,":");return(e?"-":"")+(s?"".concat(s,":"):"")+o+r}r.innerHTML="\n<style>\n".concat(":host {\n display: block;\n}\n\n::slotted(.piano-roll-visualizer) {\n overflow-x: auto;\n}","\n</style>\n<slot>\n</slot>\n");var a=["piano-roll","waterfall","staff"];class l extends HTMLElement{constructor(){super(...arguments),this.domInitialized=!1,this.ns=null,this._config={}}static get observedAttributes(){return["src","type"]}connectedCallback(){this.attachShadow({mode:"open"}),this.shadowRoot.appendChild(r.content.cloneNode(!0)),this.domInitialized||(this.domInitialized=!0,this.wrapper=document.createElement("div"),this.appendChild(this.wrapper),this.initVisualizerNow())}attributeChangedCallback(t,e,n){"src"!==t&&"type"!==t||this.initVisualizer()}initVisualizer(){null==this.initTimeout&&(this.initTimeout=window.setTimeout(()=>this.initVisualizerNow()))}initVisualizerNow(){var t=this;return i((function*(){if(t.initTimeout=null,t.domInitialized&&(t.src&&(t.ns=null,t.ns=yield e.urlToNoteSequence(t.src)),t.wrapper.innerHTML="",t.ns))if("piano-roll"===t.type){t.wrapper.classList.add("piano-roll-visualizer");var n=document.createElementNS("http://www.w3.org/2000/svg","svg");t.wrapper.appendChild(n),t.visualizer=new e.PianoRollSVGVisualizer(t.ns,n,t._config)}else if("waterfall"===t.type)t.wrapper.classList.add("waterfall-visualizer"),t.visualizer=new e.WaterfallSVGVisualizer(t.ns,t.wrapper,t._config);else if("staff"===t.type){t.wrapper.classList.add("staff-visualizer");var i=document.createElement("div");t.wrapper.appendChild(i),t.visualizer=new e.StaffSVGVisualizer(t.ns,i,t._config)}}))()}reload(){this.initVisualizerNow()}redraw(t){this.visualizer&&this.visualizer.redraw(t,null!=t)}clearActiveNotes(){this.visualizer&&this.visualizer.clearActiveNotes()}get noteSequence(){return this.ns}set noteSequence(t){this.ns!=t&&(this.ns=t,this.removeAttribute("src"),this.initVisualizer())}get src(){return this.getAttribute("src")}set src(t){this.ns=null,this.setOrRemoveAttribute("src",t),this.initVisualizer()}get type(){var t=this.getAttribute("type");return a.indexOf(t)<0&&(t="piano-roll"),t}set type(t){if(null!=t&&a.indexOf(t)<0)throw new Error("Unknown visualizer type ".concat(t,". Allowed values: ").concat(a.join(", ")));this.setOrRemoveAttribute("type",t)}get config(){return this._config}set config(t){this._config=t,this.initVisualizer()}setOrRemoveAttribute(t,e){null==e?this.removeAttribute(t):this.setAttribute(t,e)}}var c=["start","stop","note"],d=null;class u extends HTMLElement{constructor(){super(),this.domInitialized=!1,this.needInitNs=!1,this.visualizerListeners=new Map,this.ns=null,this._playing=!1,this.seeking=!1,this.attachShadow({mode:"open"}),this.shadowRoot.appendChild(s.content.cloneNode(!0)),this.controlPanel=this.shadowRoot.querySelector(".controls"),this.playButton=this.controlPanel.querySelector(".play"),this.currentTimeLabel=this.controlPanel.querySelector(".current-time"),this.totalTimeLabel=this.controlPanel.querySelector(".total-time"),this.seekBar=this.controlPanel.querySelector(".seek-bar")}static get observedAttributes(){return["sound-font","src","visualizer"]}connectedCallback(){if(!this.domInitialized){this.domInitialized=!0;var t=window.applyFocusVisiblePolyfill;null!=t&&t(this.shadowRoot),this.playButton.addEventListener("click",()=>{this.player.isPlaying()?this.stop():this.start()}),this.seekBar.addEventListener("input",()=>{this.seeking=!0,this.player&&"started"===this.player.getPlayState()&&this.player.pause()}),this.seekBar.addEventListener("change",()=>{var t=this.currentTime;this.currentTimeLabel.textContent=o(t),this.player&&this.player.isPlaying()&&(this.player.seekTo(t),"paused"===this.player.getPlayState()&&this.player.resume()),this.seeking=!1}),this.initPlayerNow()}}attributeChangedCallback(t,e,n){if(this.hasAttribute(t)||(n=null),"sound-font"===t||"src"===t)this.initPlayer();else if("visualizer"===t){var i=()=>{this.setVisualizerSelector(n)};"loading"===document.readyState?window.addEventListener("DOMContentLoaded",i):i()}}initPlayer(t=!0){this.needInitNs=this.needInitNs||t,null==this.initTimeout&&(this.stop(),this.setLoading(),this.initTimeout=window.setTimeout(()=>this.initPlayerNow(this.needInitNs)))}initPlayerNow(t=!0){var n=this;return i((function*(){if(n.initTimeout=null,n.needInitNs=!1,n.domInitialized)try{var i;if(t&&(n.src&&(n.ns=null,n.ns=yield e.urlToNoteSequence(n.src)),n.currentTime=0,n.ns||n.setError("No content loaded")),!(i=n.ns))return n.seekBar.max="0",void(n.totalTimeLabel.textContent=o(0));n.seekBar.max=String(i.totalTime),n.totalTimeLabel.textContent=o(i.totalTime);var s=n.soundFont,r={run:t=>n.ns===i&&n.noteCallback(t),stop:()=>{}};if(null===s?n.player=new e.Player(!1,r):(""===s&&(s="https://storage.googleapis.com/magentadata/js/soundfonts/sgm_plus"),n.player=new e.SoundFontPlayer(s,void 0,void 0,void 0,r),yield n.player.loadSamples(i)),n.ns!==i)return;n.setLoaded(),n.dispatchEvent(new CustomEvent("load"))}catch(t){throw n.setError(String(t)),t}}))()}reload(){this.initPlayerNow()}start(){this._start()}_start(t=!1){var e=this;i((function*(){if(e.player)if("stopped"==e.player.getPlayState()){!d||!d.playing||d==e&&t||d.stop(),d=e,e._playing=!0;var n=e.currentTime;0==e.ns.notes.filter(t=>t.startTime>n).length&&(n=0),e.currentTime=n,e.controlPanel.classList.remove("stopped"),e.controlPanel.classList.add("playing");try{for(var i of e.visualizerListeners.keys())i.noteSequence!=e.ns&&(i.noteSequence=e.ns,i.reload());var s=e.player.start(e.ns,void 0,n);t?e.dispatchEvent(new CustomEvent("loop")):e.dispatchEvent(new CustomEvent("start")),yield s,e.handleStop(!0)}catch(t){throw e.handleStop(),t}}else"paused"==e.player.getPlayState()&&e.player.resume()}))()}stop(){this.player&&this.player.isPlaying()&&this.player.stop(),this.handleStop(!1)}addVisualizer(t){var e={start:()=>{t.noteSequence=this.noteSequence},stop:()=>{t.clearActiveNotes()},note:e=>{t.redraw(e.detail.note)}};for(var n of c)this.addEventListener(n,e[n]);this.visualizerListeners.set(t,e)}removeVisualizer(t){var e=this.visualizerListeners.get(t);for(var n of c)this.removeEventListener(n,e[n]);this.visualizerListeners.delete(t)}noteCallback(t){this.playing&&(this.dispatchEvent(new CustomEvent("note",{detail:{note:t}})),this.seeking||(this.seekBar.value=String(t.startTime),this.currentTimeLabel.textContent=o(t.startTime)))}handleStop(t=!1){if(t){if(this.loop)return this.currentTime=0,void this._start(!0);this.currentTime=this.duration}this.controlPanel.classList.remove("playing"),this.controlPanel.classList.add("stopped"),this._playing&&(this._playing=!1,this.dispatchEvent(new CustomEvent("stop",{detail:{finished:t}})))}setVisualizerSelector(t){for(var e of this.visualizerListeners.values())for(var n of c)this.removeEventListener(n,e[n]);if(this.visualizerListeners.clear(),null!=t)for(var i of document.querySelectorAll(t))i instanceof l?this.addVisualizer(i):console.warn("Selector ".concat(t," matched non-visualizer element"),i)}setLoading(){this.playButton.disabled=!0,this.seekBar.disabled=!0,this.controlPanel.classList.remove("error"),this.controlPanel.classList.add("loading","frozen"),this.controlPanel.removeAttribute("title")}setLoaded(){this.controlPanel.classList.remove("loading","frozen"),this.playButton.disabled=!1,this.seekBar.disabled=!1}setError(t){this.playButton.disabled=!0,this.seekBar.disabled=!0,this.controlPanel.classList.remove("loading","stopped","playing"),this.controlPanel.classList.add("error","frozen"),this.controlPanel.title=t}get noteSequence(){return this.ns}set noteSequence(t){this.ns!=t&&(this.ns=t,this.removeAttribute("src"),this.initPlayer())}get src(){return this.getAttribute("src")}set src(t){this.ns=null,this.setOrRemoveAttribute("src",t),this.initPlayer()}get soundFont(){return this.getAttribute("sound-font")}set soundFont(t){this.setOrRemoveAttribute("sound-font",t)}get loop(){return null!=this.getAttribute("loop")}set loop(t){this.setOrRemoveAttribute("loop",t?"":null)}get currentTime(){return parseFloat(this.seekBar.value)}set currentTime(t){this.seekBar.value=String(t),this.currentTimeLabel.textContent=o(this.currentTime),this.player&&this.player.isPlaying()&&this.player.seekTo(t)}get duration(){return parseFloat(this.seekBar.max)}get playing(){return this._playing}setOrRemoveAttribute(t,e){null==e?this.removeAttribute(t):this.setAttribute(t,e)}}window.customElements.define("midi-player",u),window.customElements.define("midi-visualizer",l),t.PlayerElement=u,t.VisualizerElement=l,Object.defineProperty(t,"__esModule",{value:!0})})); //# sourceMappingURL=midi-player.min.js.map