Commit 
							
							·
						
						d659390
	
1
								Parent(s):
							
							2471741
								
Upload app.js
Browse files- javascript/app.js +389 -0
 
    	
        javascript/app.js
    CHANGED
    
    | 
         @@ -0,0 +1,389 @@ 
     | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
            +
            function gradioApp() {
         
     | 
| 2 | 
         
            +
                const elems = document.getElementsByTagName('gradio-app')
         
     | 
| 3 | 
         
            +
                const gradioShadowRoot = elems.length == 0 ? null : elems[0].shadowRoot
         
     | 
| 4 | 
         
            +
                return !!gradioShadowRoot ? gradioShadowRoot : document;
         
     | 
| 5 | 
         
            +
            }
         
     | 
| 6 | 
         
            +
             
     | 
| 7 | 
         
            +
            uiUpdateCallbacks = []
         
     | 
| 8 | 
         
            +
            msgReceiveCallbacks = []
         
     | 
| 9 | 
         
            +
             
     | 
| 10 | 
         
            +
            function onUiUpdate(callback){
         
     | 
| 11 | 
         
            +
                uiUpdateCallbacks.push(callback)
         
     | 
| 12 | 
         
            +
            }
         
     | 
| 13 | 
         
            +
             
     | 
| 14 | 
         
            +
            function onMsgReceive(callback){
         
     | 
| 15 | 
         
            +
                msgReceiveCallbacks.push(callback)
         
     | 
| 16 | 
         
            +
            }
         
     | 
| 17 | 
         
            +
             
     | 
| 18 | 
         
            +
            function runCallback(x, m){
         
     | 
| 19 | 
         
            +
                try {
         
     | 
| 20 | 
         
            +
                    x(m)
         
     | 
| 21 | 
         
            +
                } catch (e) {
         
     | 
| 22 | 
         
            +
                    (console.error || console.log).call(console, e.message, e);
         
     | 
| 23 | 
         
            +
                }
         
     | 
| 24 | 
         
            +
            }
         
     | 
| 25 | 
         
            +
            function executeCallbacks(queue, m) {
         
     | 
| 26 | 
         
            +
                queue.forEach(function(x){runCallback(x, m)})
         
     | 
| 27 | 
         
            +
            }
         
     | 
| 28 | 
         
            +
             
     | 
| 29 | 
         
            +
            document.addEventListener("DOMContentLoaded", function() {
         
     | 
| 30 | 
         
            +
                var mutationObserver = new MutationObserver(function(m){
         
     | 
| 31 | 
         
            +
                    executeCallbacks(uiUpdateCallbacks, m);
         
     | 
| 32 | 
         
            +
                });
         
     | 
| 33 | 
         
            +
                mutationObserver.observe( gradioApp(), { childList:true, subtree:true })
         
     | 
| 34 | 
         
            +
            });
         
     | 
| 35 | 
         
            +
             
     | 
| 36 | 
         
            +
            (()=>{
         
     | 
| 37 | 
         
            +
                let mse_receiver_inited = null
         
     | 
| 38 | 
         
            +
                onUiUpdate(()=>{
         
     | 
| 39 | 
         
            +
                    let app = gradioApp()
         
     | 
| 40 | 
         
            +
                    let msg_receiver = app.querySelector("#msg_receiver");
         
     | 
| 41 | 
         
            +
                    if(!!msg_receiver && mse_receiver_inited !== msg_receiver){
         
     | 
| 42 | 
         
            +
                        let mutationObserver = new MutationObserver(function(ms){
         
     | 
| 43 | 
         
            +
                            ms.forEach((m)=>{
         
     | 
| 44 | 
         
            +
                                m.addedNodes.forEach((node)=>{
         
     | 
| 45 | 
         
            +
                                    if(node.nodeName === "P"){
         
     | 
| 46 | 
         
            +
                                        let obj = JSON.parse(node.innerText);
         
     | 
| 47 | 
         
            +
                                        if(obj instanceof Array){
         
     | 
| 48 | 
         
            +
                                            obj.forEach((o)=>{executeCallbacks(msgReceiveCallbacks, o);});
         
     | 
| 49 | 
         
            +
                                        }else{
         
     | 
| 50 | 
         
            +
                                            executeCallbacks(msgReceiveCallbacks, obj);
         
     | 
| 51 | 
         
            +
                                        }
         
     | 
| 52 | 
         
            +
                                    }
         
     | 
| 53 | 
         
            +
                                })
         
     | 
| 54 | 
         
            +
                            })
         
     | 
| 55 | 
         
            +
                        });
         
     | 
| 56 | 
         
            +
                        mutationObserver.observe( msg_receiver, {childList:true, subtree:true, characterData:true})
         
     | 
| 57 | 
         
            +
                        console.log("receiver init");
         
     | 
| 58 | 
         
            +
                        mse_receiver_inited = msg_receiver;
         
     | 
| 59 | 
         
            +
                    }
         
     | 
| 60 | 
         
            +
                })
         
     | 
| 61 | 
         
            +
            })()
         
     | 
| 62 | 
         
            +
             
     | 
| 63 | 
         
            +
            function HSVtoRGB(h, s, v) {
         
     | 
| 64 | 
         
            +
                let r, g, b, i, f, p, q, t;
         
     | 
| 65 | 
         
            +
                i = Math.floor(h * 6);
         
     | 
| 66 | 
         
            +
                f = h * 6 - i;
         
     | 
| 67 | 
         
            +
                p = v * (1 - s);
         
     | 
| 68 | 
         
            +
                q = v * (1 - f * s);
         
     | 
| 69 | 
         
            +
                t = v * (1 - (1 - f) * s);
         
     | 
| 70 | 
         
            +
                switch (i % 6) {
         
     | 
| 71 | 
         
            +
                    case 0: r = v; g = t; b = p; break;
         
     | 
| 72 | 
         
            +
                    case 1: r = q; g = v; b = p; break;
         
     | 
| 73 | 
         
            +
                    case 2: r = p; g = v; b = t; break;
         
     | 
| 74 | 
         
            +
                    case 3: r = p; g = q; b = v; break;
         
     | 
| 75 | 
         
            +
                    case 4: r = t; g = p; b = v; break;
         
     | 
| 76 | 
         
            +
                    case 5: r = v; g = p; b = q; break;
         
     | 
| 77 | 
         
            +
                }
         
     | 
| 78 | 
         
            +
                return {
         
     | 
| 79 | 
         
            +
                    r: Math.round(r * 255),
         
     | 
| 80 | 
         
            +
                    g: Math.round(g * 255),
         
     | 
| 81 | 
         
            +
                    b: Math.round(b * 255)
         
     | 
| 82 | 
         
            +
                };
         
     | 
| 83 | 
         
            +
            }
         
     | 
| 84 | 
         
            +
             
     | 
| 85 | 
         
            +
            class MidiVisualizer extends HTMLElement{
         
     | 
| 86 | 
         
            +
                constructor() {
         
     | 
| 87 | 
         
            +
                    super();
         
     | 
| 88 | 
         
            +
                    this.midiEvents = [];
         
     | 
| 89 | 
         
            +
                    this.activeNotes = [];
         
     | 
| 90 | 
         
            +
                    this.midiTimes = [];
         
     | 
| 91 | 
         
            +
                    this.wrapper = null;
         
     | 
| 92 | 
         
            +
                    this.svg = null;
         
     | 
| 93 | 
         
            +
                    this.timeLine = null;
         
     | 
| 94 | 
         
            +
                    this.config = {
         
     | 
| 95 | 
         
            +
                        noteHeight : 4,
         
     | 
| 96 | 
         
            +
                        beatWidth: 32
         
     | 
| 97 | 
         
            +
                    }
         
     | 
| 98 | 
         
            +
                    this.timePreBeat = 16
         
     | 
| 99 | 
         
            +
                    this.svgWidth = 0;
         
     | 
| 100 | 
         
            +
                    this.t1 = 0;
         
     | 
| 101 | 
         
            +
                    this.playTime = 0
         
     | 
| 102 | 
         
            +
                    this.playTimeMs = 0
         
     | 
| 103 | 
         
            +
                    this.colorMap = new Map();
         
     | 
| 104 | 
         
            +
                    this.playing = false;
         
     | 
| 105 | 
         
            +
                    this.timer = null;
         
     | 
| 106 | 
         
            +
                    this.init();
         
     | 
| 107 | 
         
            +
                }
         
     | 
| 108 | 
         
            +
             
     | 
| 109 | 
         
            +
                init(){
         
     | 
| 110 | 
         
            +
                    this.innerHTML=''
         
     | 
| 111 | 
         
            +
                    const shadow = this.attachShadow({mode: 'open'});
         
     | 
| 112 | 
         
            +
                    const style = document.createElement("style");
         
     | 
| 113 | 
         
            +
                    const wrapper = document.createElement('div');
         
     | 
| 114 | 
         
            +
                    style.textContent = ".note.active {stroke: black;stroke-width: 0.75;stroke-opacity: 0.75;}";
         
     | 
| 115 | 
         
            +
                    wrapper.style.overflowX= "scroll"
         
     | 
| 116 | 
         
            +
                    const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
         
     | 
| 117 | 
         
            +
                    svg.style.height = `${this.config.noteHeight*128}px`;
         
     | 
| 118 | 
         
            +
                    svg.style.width = `${this.svgWidth}px`;
         
     | 
| 119 | 
         
            +
                    const timeLine = document.createElementNS('http://www.w3.org/2000/svg', 'line');
         
     | 
| 120 | 
         
            +
                    timeLine.style.stroke = "green"
         
     | 
| 121 | 
         
            +
                    timeLine.style.strokeWidth = 2;
         
     | 
| 122 | 
         
            +
                    shadow.appendChild(style)
         
     | 
| 123 | 
         
            +
                    shadow.appendChild(wrapper);
         
     | 
| 124 | 
         
            +
                    wrapper.appendChild(svg);
         
     | 
| 125 | 
         
            +
                    svg.appendChild(timeLine)
         
     | 
| 126 | 
         
            +
                    this.wrapper = wrapper;
         
     | 
| 127 | 
         
            +
                    this.svg = svg;
         
     | 
| 128 | 
         
            +
                    this.timeLine= timeLine;
         
     | 
| 129 | 
         
            +
                    this.setPlayTime(0);
         
     | 
| 130 | 
         
            +
                }
         
     | 
| 131 | 
         
            +
             
     | 
| 132 | 
         
            +
                clearMidiEvents(){
         
     | 
| 133 | 
         
            +
                    this.pause()
         
     | 
| 134 | 
         
            +
                    this.midiEvents = [];
         
     | 
| 135 | 
         
            +
                    this.activeNotes = [];
         
     | 
| 136 | 
         
            +
                    this.midiTimes = [];
         
     | 
| 137 | 
         
            +
                    this.t1 = 0
         
     | 
| 138 | 
         
            +
                    this.colorMap.clear()
         
     | 
| 139 | 
         
            +
                    this.setPlayTime(0);
         
     | 
| 140 | 
         
            +
                    this.playTimeMs = 0
         
     | 
| 141 | 
         
            +
                    this.svgWidth = 0
         
     | 
| 142 | 
         
            +
                    this.svg.innerHTML = ''
         
     | 
| 143 | 
         
            +
                    this.svg.style.width = `${this.svgWidth}px`;
         
     | 
| 144 | 
         
            +
                    this.svg.appendChild(this.timeLine)
         
     | 
| 145 | 
         
            +
                }
         
     | 
| 146 | 
         
            +
             
     | 
| 147 | 
         
            +
                appendMidiEvent(midiEvent){
         
     | 
| 148 | 
         
            +
                    if(midiEvent instanceof Array && midiEvent.length > 0){
         
     | 
| 149 | 
         
            +
             
     | 
| 150 | 
         
            +
                        this.t1 += midiEvent[1]
         
     | 
| 151 | 
         
            +
                        let t = this.t1*this.timePreBeat + midiEvent[2]
         
     | 
| 152 | 
         
            +
                        midiEvent = [midiEvent[0], t].concat(midiEvent.slice(3))
         
     | 
| 153 | 
         
            +
                        if(midiEvent[0] === "note"){
         
     | 
| 154 | 
         
            +
                            let track = midiEvent[2]
         
     | 
| 155 | 
         
            +
                            let duration = midiEvent[3]
         
     | 
| 156 | 
         
            +
                            let channel = midiEvent[4]
         
     | 
| 157 | 
         
            +
                            let pitch = midiEvent[5]
         
     | 
| 158 | 
         
            +
                            let velocity = midiEvent[6]
         
     | 
| 159 | 
         
            +
                            let x = (t/this.timePreBeat)*this.config.beatWidth
         
     | 
| 160 | 
         
            +
                            let y = (127 - pitch)*this.config.noteHeight
         
     | 
| 161 | 
         
            +
                            let w = (duration/this.timePreBeat)*this.config.beatWidth
         
     | 
| 162 | 
         
            +
                            let h = this.config.noteHeight
         
     | 
| 163 | 
         
            +
                            this.svgWidth = Math.ceil(Math.max(x + w, this.svgWidth))
         
     | 
| 164 | 
         
            +
                            let color = this.getColor(track, channel)
         
     | 
| 165 | 
         
            +
                            let opacity = Math.min(1, velocity/127 + 0.1).toFixed(2)
         
     | 
| 166 | 
         
            +
                            let rect = this.drawNote(x,y,w,h, `rgba(${color.r}, ${color.g}, ${color.b}, ${opacity})`)
         
     | 
| 167 | 
         
            +
                            midiEvent.push(rect)
         
     | 
| 168 | 
         
            +
                            this.setPlayTime(t);
         
     | 
| 169 | 
         
            +
                            this.wrapper.scrollTo(this.svgWidth - this.wrapper.offsetWidth, 0)
         
     | 
| 170 | 
         
            +
                        }
         
     | 
| 171 | 
         
            +
                        this.midiEvents.push(midiEvent);
         
     | 
| 172 | 
         
            +
                        this.svg.style.width = `${this.svgWidth}px`;
         
     | 
| 173 | 
         
            +
                    }
         
     | 
| 174 | 
         
            +
             
     | 
| 175 | 
         
            +
                }
         
     | 
| 176 | 
         
            +
             
     | 
| 177 | 
         
            +
                getColor(track, channel){
         
     | 
| 178 | 
         
            +
                    let key = `${track},${channel}`;
         
     | 
| 179 | 
         
            +
                    let color = this.colorMap.get(key);
         
     | 
| 180 | 
         
            +
                    if(!!color){
         
     | 
| 181 | 
         
            +
                        return color;
         
     | 
| 182 | 
         
            +
                    }
         
     | 
| 183 | 
         
            +
                    color = HSVtoRGB(Math.random(),Math.random()*0.5 + 0.5,1);
         
     | 
| 184 | 
         
            +
                    this.colorMap.set(key, color);
         
     | 
| 185 | 
         
            +
                    return color;
         
     | 
| 186 | 
         
            +
                }
         
     | 
| 187 | 
         
            +
             
     | 
| 188 | 
         
            +
                drawNote(x, y, w, h, fill) {
         
     | 
| 189 | 
         
            +
                    if (!this.svg) {
         
     | 
| 190 | 
         
            +
                      return null;
         
     | 
| 191 | 
         
            +
                    }
         
     | 
| 192 | 
         
            +
                    const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
         
     | 
| 193 | 
         
            +
                    rect.classList.add('note');
         
     | 
| 194 | 
         
            +
                    rect.setAttribute('fill', fill);
         
     | 
| 195 | 
         
            +
                    // Round values to the nearest integer to avoid partially filled pixels.
         
     | 
| 196 | 
         
            +
                    rect.setAttribute('x', `${Math.round(x)}`);
         
     | 
| 197 | 
         
            +
                    rect.setAttribute('y', `${Math.round(y)}`);
         
     | 
| 198 | 
         
            +
                    rect.setAttribute('width', `${Math.round(w)}`);
         
     | 
| 199 | 
         
            +
                    rect.setAttribute('height', `${Math.round(h)}`);
         
     | 
| 200 | 
         
            +
                    this.svg.appendChild(rect);
         
     | 
| 201 | 
         
            +
                    return rect
         
     | 
| 202 | 
         
            +
                }
         
     | 
| 203 | 
         
            +
             
     | 
| 204 | 
         
            +
                finishAppendMidiEvent(){
         
     | 
| 205 | 
         
            +
                    this.pause()
         
     | 
| 206 | 
         
            +
                    let midiEvents = this.midiEvents.sort((a, b)=>a[1]-b[1])
         
     | 
| 207 | 
         
            +
                    let tempo = (60 / 120) * 10 ** 3
         
     | 
| 208 | 
         
            +
                    let ms = 0
         
     | 
| 209 | 
         
            +
                    let lastT = 0
         
     | 
| 210 | 
         
            +
                    this.midiTimes.push({ms:ms, t: 0, tempo: tempo})
         
     | 
| 211 | 
         
            +
                    midiEvents.forEach((midiEvent)=>{
         
     | 
| 212 | 
         
            +
                        let t = midiEvent[1]
         
     | 
| 213 | 
         
            +
                        ms += ((t- lastT) / this.timePreBeat) * tempo
         
     | 
| 214 | 
         
            +
                        if(midiEvent[0]==="set_tempo"){
         
     | 
| 215 | 
         
            +
                            tempo = (60 / midiEvent[3]) * 10 ** 3
         
     | 
| 216 | 
         
            +
                            this.midiTimes.push({ms:ms, t: t, tempo: tempo})
         
     | 
| 217 | 
         
            +
                        }
         
     | 
| 218 | 
         
            +
                        lastT = t
         
     | 
| 219 | 
         
            +
                    })
         
     | 
| 220 | 
         
            +
                }
         
     | 
| 221 | 
         
            +
             
     | 
| 222 | 
         
            +
                setPlayTime(t){
         
     | 
| 223 | 
         
            +
                    this.playTime = t
         
     | 
| 224 | 
         
            +
                    let x = Math.round((t/this.timePreBeat)*this.config.beatWidth)
         
     | 
| 225 | 
         
            +
                    this.timeLine.setAttribute('x1', `${x}`);
         
     | 
| 226 | 
         
            +
                    this.timeLine.setAttribute('y1', '0');
         
     | 
| 227 | 
         
            +
                    this.timeLine.setAttribute('x2', `${x}`);
         
     | 
| 228 | 
         
            +
                    this.timeLine.setAttribute('y2', `${this.config.noteHeight*128}`);
         
     | 
| 229 | 
         
            +
             
     | 
| 230 | 
         
            +
                    this.wrapper.scrollTo(Math.max(0, x - this.wrapper.offsetWidth/2), 0)
         
     | 
| 231 | 
         
            +
             
     | 
| 232 | 
         
            +
                    if(this.playing){
         
     | 
| 233 | 
         
            +
                        let activeNotes = []
         
     | 
| 234 | 
         
            +
                        this.removeActiveNotes(this.activeNotes)
         
     | 
| 235 | 
         
            +
                        this.midiEvents.forEach((midiEvent)=>{
         
     | 
| 236 | 
         
            +
                            if(midiEvent[0] === "note"){
         
     | 
| 237 | 
         
            +
                                let time = midiEvent[1]
         
     | 
| 238 | 
         
            +
                                let duration = midiEvent[3]
         
     | 
| 239 | 
         
            +
                                let note = midiEvent[midiEvent.length - 1]
         
     | 
| 240 | 
         
            +
                                if(time <=this.playTime && time+duration>= this.playTime){
         
     | 
| 241 | 
         
            +
                                    activeNotes.push(note)
         
     | 
| 242 | 
         
            +
                                }
         
     | 
| 243 | 
         
            +
                            }
         
     | 
| 244 | 
         
            +
                        })
         
     | 
| 245 | 
         
            +
                        this.addActiveNotes(activeNotes)
         
     | 
| 246 | 
         
            +
                    }
         
     | 
| 247 | 
         
            +
                }
         
     | 
| 248 | 
         
            +
             
     | 
| 249 | 
         
            +
                setPlayTimeMs(ms){
         
     | 
| 250 | 
         
            +
                    this.playTimeMs = ms
         
     | 
| 251 | 
         
            +
                    let playTime = 0
         
     | 
| 252 | 
         
            +
                    for(let i =0;i<this.midiTimes.length;i++){
         
     | 
| 253 | 
         
            +
                        let midiTime = this.midiTimes[i]
         
     | 
| 254 | 
         
            +
                        if(midiTime.ms>=ms){
         
     | 
| 255 | 
         
            +
                            break;
         
     | 
| 256 | 
         
            +
                        }
         
     | 
| 257 | 
         
            +
                        playTime = midiTime.t + (ms-midiTime.ms) * this.timePreBeat / midiTime.tempo
         
     | 
| 258 | 
         
            +
                    }
         
     | 
| 259 | 
         
            +
                    this.setPlayTime(playTime)
         
     | 
| 260 | 
         
            +
                }
         
     | 
| 261 | 
         
            +
             
     | 
| 262 | 
         
            +
                addActiveNotes(notes){
         
     | 
| 263 | 
         
            +
                    notes.forEach((note)=>{
         
     | 
| 264 | 
         
            +
                        this.activeNotes.push(note)
         
     | 
| 265 | 
         
            +
                        note.classList.add('active');
         
     | 
| 266 | 
         
            +
                    });
         
     | 
| 267 | 
         
            +
                }
         
     | 
| 268 | 
         
            +
             
     | 
| 269 | 
         
            +
                removeActiveNotes(notes){
         
     | 
| 270 | 
         
            +
                    notes.forEach((note)=>{
         
     | 
| 271 | 
         
            +
                        let idx = this.activeNotes.indexOf(note)
         
     | 
| 272 | 
         
            +
                        if(idx>-1)
         
     | 
| 273 | 
         
            +
                            this.activeNotes.splice(idx, 1);
         
     | 
| 274 | 
         
            +
                        note.classList.remove('active');
         
     | 
| 275 | 
         
            +
                    });
         
     | 
| 276 | 
         
            +
                }
         
     | 
| 277 | 
         
            +
             
     | 
| 278 | 
         
            +
                play(){
         
     | 
| 279 | 
         
            +
                    this.playing = true;
         
     | 
| 280 | 
         
            +
                    this.timer = setInterval(() => {
         
     | 
| 281 | 
         
            +
                        this.setPlayTimeMs(this.playTimeMs + 10)
         
     | 
| 282 | 
         
            +
                    }, 10);
         
     | 
| 283 | 
         
            +
                }
         
     | 
| 284 | 
         
            +
             
     | 
| 285 | 
         
            +
                pause(){
         
     | 
| 286 | 
         
            +
                    if(!!this.timer)
         
     | 
| 287 | 
         
            +
                        clearInterval(this.timer)
         
     | 
| 288 | 
         
            +
                    this.removeActiveNotes(this.activeNotes)
         
     | 
| 289 | 
         
            +
                    this.timer = null;
         
     | 
| 290 | 
         
            +
                    this.playing = false;
         
     | 
| 291 | 
         
            +
                }
         
     | 
| 292 | 
         
            +
             
     | 
| 293 | 
         
            +
             
     | 
| 294 | 
         
            +
                bindAudioPlayer(audio){
         
     | 
| 295 | 
         
            +
                    this.pause()
         
     | 
| 296 | 
         
            +
                    audio.addEventListener("play", (event)=>{
         
     | 
| 297 | 
         
            +
                        this.play()
         
     | 
| 298 | 
         
            +
                    })
         
     | 
| 299 | 
         
            +
                    audio.addEventListener("pause", (event)=>{
         
     | 
| 300 | 
         
            +
                        this.pause()
         
     | 
| 301 | 
         
            +
                    })
         
     | 
| 302 | 
         
            +
                    audio.addEventListener("timeupdate", (event)=>{
         
     | 
| 303 | 
         
            +
                        this.setPlayTimeMs(event.target.currentTime*10**3)
         
     | 
| 304 | 
         
            +
                    })
         
     | 
| 305 | 
         
            +
                }
         
     | 
| 306 | 
         
            +
            }
         
     | 
| 307 | 
         
            +
             
     | 
| 308 | 
         
            +
            customElements.define('midi-visualizer', MidiVisualizer);
         
     | 
| 309 | 
         
            +
             
     | 
| 310 | 
         
            +
            (()=>{
         
     | 
| 311 | 
         
            +
                let midi_visualizer_container_inited = null
         
     | 
| 312 | 
         
            +
                let midi_audio_inited = null;
         
     | 
| 313 | 
         
            +
                let midi_visualizer = document.createElement('midi-visualizer')
         
     | 
| 314 | 
         
            +
                onUiUpdate((m)=>{
         
     | 
| 315 | 
         
            +
                    let app = gradioApp()
         
     | 
| 316 | 
         
            +
                    let midi_visualizer_container = app.querySelector("#midi_visualizer_container");
         
     | 
| 317 | 
         
            +
                    if(!!midi_visualizer_container && midi_visualizer_container_inited!== midi_visualizer_container){
         
     | 
| 318 | 
         
            +
                        midi_visualizer_container.appendChild(midi_visualizer)
         
     | 
| 319 | 
         
            +
                        midi_visualizer_container_inited = midi_visualizer_container;
         
     | 
| 320 | 
         
            +
                    }
         
     | 
| 321 | 
         
            +
                    let midi_audio = app.querySelector("#midi_audio > audio");
         
     | 
| 322 | 
         
            +
                    if(!!midi_audio && midi_audio_inited!==midi_audio){
         
     | 
| 323 | 
         
            +
                        midi_visualizer.bindAudioPlayer(midi_audio)
         
     | 
| 324 | 
         
            +
                        midi_audio_inited = midi_audio
         
     | 
| 325 | 
         
            +
                    }
         
     | 
| 326 | 
         
            +
                })
         
     | 
| 327 | 
         
            +
             
     | 
| 328 | 
         
            +
                function createProgressBar(progressbarContainer){
         
     | 
| 329 | 
         
            +
                    let parentProgressbar = progressbarContainer.parentNode;
         
     | 
| 330 | 
         
            +
                    let divProgress = document.createElement('div');
         
     | 
| 331 | 
         
            +
                    divProgress.className='progressDiv';
         
     | 
| 332 | 
         
            +
                    let rect = progressbarContainer.getBoundingClientRect();
         
     | 
| 333 | 
         
            +
                    divProgress.style.width = rect.width + "px";
         
     | 
| 334 | 
         
            +
                    divProgress.style.background = "#b4c0cc";
         
     | 
| 335 | 
         
            +
                    divProgress.style.borderRadius = "8px";
         
     | 
| 336 | 
         
            +
                    let divInner = document.createElement('div');
         
     | 
| 337 | 
         
            +
                    divInner.className='progress';
         
     | 
| 338 | 
         
            +
                    divInner.style.color = "white";
         
     | 
| 339 | 
         
            +
                    divInner.style.background = "#0060df";
         
     | 
| 340 | 
         
            +
                    divInner.style.textAlign = "right";
         
     | 
| 341 | 
         
            +
                    divInner.style.fontWeight = "bold";
         
     | 
| 342 | 
         
            +
                    divInner.style.borderRadius = "8px";
         
     | 
| 343 | 
         
            +
                    divInner.style.height = "20px";
         
     | 
| 344 | 
         
            +
                    divInner.style.lineHeight = "20px";
         
     | 
| 345 | 
         
            +
                    divInner.style.paddingRight = "8px"
         
     | 
| 346 | 
         
            +
                    divInner.style.width = "0%";
         
     | 
| 347 | 
         
            +
                    divProgress.appendChild(divInner);
         
     | 
| 348 | 
         
            +
                    parentProgressbar.insertBefore(divProgress, progressbarContainer);
         
     | 
| 349 | 
         
            +
                }
         
     | 
| 350 | 
         
            +
             
     | 
| 351 | 
         
            +
                function removeProgressBar(progressbarContainer){
         
     | 
| 352 | 
         
            +
                    let parentProgressbar = progressbarContainer.parentNode;
         
     | 
| 353 | 
         
            +
                    let divProgress = parentProgressbar.querySelector(".progressDiv");
         
     | 
| 354 | 
         
            +
                    parentProgressbar.removeChild(divProgress);
         
     | 
| 355 | 
         
            +
                }
         
     | 
| 356 | 
         
            +
             
     | 
| 357 | 
         
            +
                function setProgressBar(progressbarContainer, progress, total){
         
     | 
| 358 | 
         
            +
                    let parentProgressbar = progressbarContainer.parentNode;
         
     | 
| 359 | 
         
            +
                    let divProgress = parentProgressbar.querySelector(".progressDiv");
         
     | 
| 360 | 
         
            +
                    let divInner = parentProgressbar.querySelector(".progress");
         
     | 
| 361 | 
         
            +
                    if(total===0)
         
     | 
| 362 | 
         
            +
                        total = 1;
         
     | 
| 363 | 
         
            +
                    divInner.style.width = `${(progress/total)*100}%`;
         
     | 
| 364 | 
         
            +
                    divInner.textContent = `${progress}/${total}`;
         
     | 
| 365 | 
         
            +
                }
         
     | 
| 366 | 
         
            +
             
     | 
| 367 | 
         
            +
                onMsgReceive((msg)=>{
         
     | 
| 368 | 
         
            +
                    switch (msg.name) {
         
     | 
| 369 | 
         
            +
                        case "visualizer_clear":
         
     | 
| 370 | 
         
            +
                            midi_visualizer.clearMidiEvents();
         
     | 
| 371 | 
         
            +
                            createProgressBar(midi_visualizer_container_inited)
         
     | 
| 372 | 
         
            +
                            break;
         
     | 
| 373 | 
         
            +
                        case "visualizer_append":
         
     | 
| 374 | 
         
            +
                            midi_visualizer.appendMidiEvent(msg.data);
         
     | 
| 375 | 
         
            +
                            break;
         
     | 
| 376 | 
         
            +
                        case "progress":
         
     | 
| 377 | 
         
            +
                            let progress = msg.data[0]
         
     | 
| 378 | 
         
            +
                            let total = msg.data[1]
         
     | 
| 379 | 
         
            +
                            setProgressBar(midi_visualizer_container_inited, progress, total)
         
     | 
| 380 | 
         
            +
                            break;
         
     | 
| 381 | 
         
            +
                        case "visualizer_end":
         
     | 
| 382 | 
         
            +
                            midi_visualizer.finishAppendMidiEvent()
         
     | 
| 383 | 
         
            +
                            midi_visualizer.setPlayTime(0);
         
     | 
| 384 | 
         
            +
                            removeProgressBar(midi_visualizer_container_inited);
         
     | 
| 385 | 
         
            +
                            break;
         
     | 
| 386 | 
         
            +
                        default:
         
     | 
| 387 | 
         
            +
                    }
         
     | 
| 388 | 
         
            +
                })
         
     | 
| 389 | 
         
            +
            })();
         
     |