=f&&h{let h=o.startPort<<4,d=(o.startPort<<4)+(16<=h&&r.part1?32:16)),c=o.device.getChVoice(h);t.fillText(`${h+1}`.padStart(2,"0"),o.fontPadding+a+(r>>(this.mode>1?5:4))*(t.canvas.width>>1),d,o.noteWidth*2.5),t.fillText(c.name,o.fontPadding+a+(r>>(this.mode>1?5:4))*(t.canvas.width>>1)+o.noteWidth*3,d,o.noteWidth*13);let f=u.length*h;[7,11,1,91,93,94,74,5,12,13].forEach((p,b)=>{t.fillRect(o.fontPadding*2+o.noteWidth*(16+b)+(r>>(this.mode>1?5:4))*(t.canvas.width>>1),o.lineHeight*(4+r%(this.mode>1?32:16)),o.noteWidth-o.noteOutline,(o.lineHeight-1)*(l.chContr[f+u[p]]/-127))})}}l.letter.expire<=i,t.globalCompositeOperation="xor",t.fillStyle="#fff";for(let r=0;r<16<>(this.mode>1?5:4))*(t.canvas.width>>1),o.lineHeight*(3+r%(this.mode>1?32:16)),o.noteWidth*16*(l.strength[h]/255),o.lineHeight-1)}for(let r in o.eventBuffer)delete o.eventBuffer[r];for(;o.eventQueue.length>0;)delete o.eventQueue[0],o.eventQueue.shift()}constructor(n){super(new ye,.1,.75);let l=this;this.context=n,this.resizeCanvas(1280,720),this.device.addEventListener("note",o=>{let t=o.data,i=t.part*128+t.note,a=this.eventBuffer[i];this.eventBuffer[i]=t,a?.velo>0&&t.velo==0&&this.eventQueue.push(a)})}},Dt=Fe;export{Dt as default};
diff --git a/dist/state.mjs b/dist/state.mjs
new file mode 100644
index 00000000..3617ef3f
--- /dev/null
+++ b/dist/state.mjs
@@ -0,0 +1,156 @@
+var X=function(e,n){let l=Math.min(e.length,n.length),f=e.slice(0,l),t=n.slice(0,l),a=0,r=0;for(;r0){let f=this.pool.length,t=1<=1&&r>=0;){if(r<=0)throw new Error("TTL reached.");if(a==f)a-=t;else{let s=X(n,this.pool[a]);switch(s){case 0:{r=0;break}case 1:{a+t<=f&&(a+=t);break}case-1:{a!=0&&(a-=t);break}default:console.warn(`Unexpected result ${s}.`)}}t=t>>1,r--}let i=!0;if(a>=this.pool.length)i=!1;else{let s=this;this.pool[a].forEach(function(o,c,h){i&&o!=n[c]&&(i=!1)}),!i&&X(n,this.pool[a])>0&&a++}return i||l?a:-1}else return l?0:-1},this.add=function(n,l){return n.data=l,this.pool.splice(this.point(n,!0),0,n),this},this.default=function(n){console.warn(`No match in "${this.name||"(unknown)"}" for "${n}". Default action not defined.`)},this.get=function(n){let l=this.point(n);if(l>-1)return this.pool[l].data;this.default(n)},this.run=function(n,...l){let f=this.point(n);f>-1?n.subarray?this.pool[f].data(n.subarray(this.pool[f].length),...l):this.pool[f].data(n.slice(this.pool[f].length),...l):this.default(n,...l)}};var F=class{#t={};addEventListener(e,n){this.#t[e]||(this.#t[e]=[]),this.#t[e].unshift(n)}removeEventListener(e,n){if(this.#t[e]){let l=this.#t[e].indexOf(n);l>-1&&this.#t[e].splice(l,1),this.#t[e].length<1&&delete this.#t[e]}}dispatchEvent(e,n){let l=new Event(e),f=this;l.data=n,this.#t[e]?.length>0&&this.#t[e].forEach(function(t){try{t?.call(f,l)}catch(a){console.error(a)}}),this[`on${e}`]&&this[`on${e}`](l)}};var ce=["MSB","PRG","LSB"],N=function(e){let n=Math.floor(e/10),l=e%10;return`${n.toString(16)}${l}`},H=class{#t;strictMode=!1;get(e=0,n=0,l=0,f){let t=[e,n,l],a,r=Array.from(arguments);switch(f){case"xg":{e==32?r[2]+=4:e==33||e==35||e==36?r[2]+=5:e==79?r[0]=95:e==80?r[0]=96:e==81?r[0]=97:e==82?r[0]=98:e==83?r[0]=99:e==84&&(r[0]=100);break}case"gs":{e==0&&l<5?r[2]=0:e>125&&l<5&&l!=2&&(r[2]=e,r[0]=0);break}case"sg":{e==8&&l==0&&(r[2]=5);break}case"s90es":{l<8?r[2]+=17:l<32?r[2]+=13:r[2]=(r[2]>>3)+19;break}case"motif":{l<8?r[2]+=28:l<32?r[2]+=13:r[2]=(r[2]>>3)+19;break}}let i=" ",s="M",o=!1,c=0;switch(r[0]){case 0:{r[2]==127?s="MT-a":r[2]==126?s="MT-b":r[2]==7?s="GM-k":r[2]==5?s="SG-a":r[2]==4?s="SP-l":r[2]==0||f=="gs"&&r[2]<5?s="GM-a":(s="y",o=!0);break}case 8:{f=="sg"?s="GM-s":s="r:";break}case 48:{s=`yM${(r[2]>>3).toString().padStart(2,"0")}`,o=!0;break}case 56:{s="GM-b";break}case 61:case 120:{s="rDrm";break}case 62:{s="kDrm";break}case 63:{if(r[2]<17){let $=r[2];s=$<10?"kP:":"kC:",s+=$%10}else r[2]<34?s=["Pre1","Pre2","Pre3","Pre4","Usr1","Usr2","DrmP","DrmU","Plg1","Plg2","Plg3","Pre1","Pre2","Pre3","Pre4","Pre5","Pre6"][r[2]-17]:s="Ds";break}case 64:{s="ySFX";break}case 67:{s="DX:S";break}case 80:case 81:case 82:case 83:{s=`Prg${"UABC"[r[0]-80]}`;break}case 88:case 89:case 90:case 91:{s=`Cmb${"UABC"[r[0]-88]}`;break}case 95:{s=`${["DR","PC"][r[2]]}-d`;break}case 96:{s=r[2]==106?"AP-a":"PF",r[2]>63&&(c=63),o=!0;break}case 97:{s="VL:",o=!0,c=112;break}case 98:{s="SG-a";break}case 99:{s="DX",r[2]>63&&(c=63),o=!0;break}case 100:{s="AN",r[2]>63&&(c=63),o=!0;break}case 121:{s=`GM-${r[2]?"":"a"}`,o=!0;break}case 122:{s="lDrm";break}case 126:{s="yDrS";break}case 127:{r[2]==127?s="rDrm":s="yDrm";break}default:r[0]<48?s="r:":s="M"}s.length<4&&(s+=`${(o?l:e)-c}`.padStart(4-s.length,"0")),f=="xg"&&e==16&&(a=`Voice${(l*128+n+1).toString().padStart(3,"0")}`,i=" ");let h=[r[0],r[1],r[2]];for(;!(a?.length>=0);)a=this.#t[r[1]||0][(r[0]<<7)+r[2]],a||(this.strictMode?(a="",i="?"):this.#t[r[1]||0][r[0]<<7]?r[0]==0?(r[2]=0,i="^"):r[2]<1?(r[0]=0,i="*"):(r[2]--,i="^"):e==48?(r[0]=0,r[2]=0,i="!"):e==62?(r[1]--,i=" ",r[1]<1&&!a?.length&&(r[0]=0,i="!")):e<63?r[0]==0?(r[2]=0,i="^"):r[2]<1?(r[0]=0,i="*"):r[2]--:e==80?(a=`PrgU:${n.toString().padStart(3,"0")}`,i="!"):e==88?(a=`CmbU:${n.toString().padStart(3,"0")}`,i="!"):e==121?(a=`GM2Vox0${l}`,i="#"):e==122?(r[1]==32?r[1]==0:r[1]%=7,a=this.#t[r[1]||0][(r[0]<<7)+r[2]],a?i=" ":(a="",i="*")):r[1]==0?(a=`${e.toString().padStart(3,"0")} ${n.toString().padStart(3,"0")} ${l.toString().padStart(3,"0")}`,i="!"):r[0]==0?(r[2]=0,i="^"):r[2]>0?r[2]--:r[1]>0?(r[1]=0,i="!"):(r[0]=0,i="?"));let b=[r[0],r[1],r[2]];(f=="gs"||f=="ns5r")&&i=="^"&&(i=" "),e==127&&i=="^"&&(i=" "),i!=" "&&self.debugMode&&(a="");let p="??";switch(r[0]){case 0:{r[2]==0?p="GM":r[2]==5||r[2]==7?p="KG":r[2]<120?p="XG":r[2]==127&&(p="MT");break}case 48:{p="MU";break}case 56:{p="AG";break}case 61:case 80:case 83:case 88:case 89:case 91:{p="AI";break}case 62:case 82:case 90:{p="XD";break}case 63:{r[2]<17?p="KR":r[2]<34?p="ES":p="DS";break}case 64:case 126:{p="XG";break}case 67:case 99:{p="DX";break}case 81:{p="RW";break}case 95:{p=["DR","PC"][r[2]];break}case 96:{p=r[2]==106?"AP":"PF";break}case 97:{p="VL";break}case 98:{p="SG";break}case 100:{p="AN";break}case 120:{p="GS";break}case 121:{p=r[2]?"G2":"GM";break}case 122:{p="KG";break}case 127:{p=r[2]==127?"MT":n==0?"GM":"XG";break}default:r[0]<48&&(r[0]==16&&f=="xg"?p="XG":p="GS")}return{name:a||`${N(e||0)} ${N(n||0)} ${N(l||0)}`,iid:h,eid:b,sid:t,ending:i,sect:s,standard:p}}async load(e,n,l){let f=this,t=[],a=0,r=0;e.split(`
+`).forEach(function(i,s){let o=i.split(" "),c=[];s==0?o.forEach(function(h,b){t[ce.indexOf(h)]=b}):o.forEach(async function(h,b){b>2?(f.#t[c[t[1]]]=f.#t[c[t[1]]]||[],(!f.#t[c[t[1]]][(c[t[0]]<<7)+c[t[2]]]?.length||n)&&(f.#t[c[t[1]]][(c[t[0]]<<7)+c[t[2]]]=o[3],a++),r++):c.push(parseInt(o[b]))})}),n||console.debug(`Map "${l||"(internal)"}": ${r} total, ${a} loaded.`)}clearRange(e){let n=e.prg!=null?e.prg.constructor==Array?e.prg:[e.prg,e.prg]:[0,127],l=e.msb!=null?e.msb.constructor==Array?e.msb:[e.msb,e.msb]:[0,127],f=e.lsb!=null?e.lsb.constructor==Array?e.lsb:[e.lsb,e.lsb]:[0,127];for(let t=l[0];t<=l[1];t++){let a=t<<7;for(let r=f[0];r<=f[1];r++){let i=a+r;for(let s=n[0];s<=n[1];s++)delete this.#t[s][i]}}}init(){this.#t=[];for(let e=0;e<128;e++)this.#t.push([""])}async loadFiles(...e){this.init();let n=this;e.forEach(async function(l,f){try{await fetch(`./data/bank/${l}.tsv`).then(function(t){return t.text()}).then(t=>{n.load(t,!1,l)})}catch{console.error(`Failed loading "${l}.tsv".`)}})}constructor(...e){this.loadFiles(...e)}};var K=class{#t={};context;set(e,n){this.#t[e]=n}has(e){return!!this.#t[e]}async read(e,n){if(!this.has(e))throw new Error(`No decoder registered for "${e}"`);return await this.#t[e].call(this.context||this,n)}};var he=function(e,n){let l=!0;return n.forEach((f,t)=>{l=l&&e[t]==f}),l},V=function(e){let n=0;return e.forEach(l=>{n*=256,n+=l}),n},v=new TextDecoder,P=new K;P.set("s7e",async function(e){let n=new Uint8Array(await e.slice(0,65536).arrayBuffer()),l="MSB LSB PRG NME",f=[0,0,0,0],t=32,a=0,r=0,i=!0,s=[],o=0;for(;i;){let c=n.subarray(a);([()=>{v.decode(c.subarray(0,4))=="YSFC"?(a+=80,r=1):a++},()=>{if(he(c.subarray(0,4),f))s.forEach((h,b,p)=>{let $=V(n.subarray(h.start+4,h.start+8));h.length=$}),r=2;else{let h=v.decode(c.subarray(0,4)),b=V(c.subarray(4,8));s.push({type:h,start:b}),a+=8}},()=>{let h=s[o],b=n.subarray(h.start,h.start+h.length),p=32;switch(h.type){case"ENVC":{let $=t;for(;$=s.length&&(r=3,i=!1)}][r]||(()=>{i=!1}))()}return l});var R=["off","hall","room","stage","plate","delay LCR","delay LR","echo","cross delay","early reflections","gate reverb","reverse gate"].concat(new Array(4),["white room","tunnel","canyon","basement","karaoke"],new Array(43),["pass through","chorus","celeste","flanger","symphonic","rotary speaker","tremelo","auto pan","phaser","distortion","overdrive","amplifier","3-band EQ","2-band EQ","auto wah"],new Array(1),["pitch change","harmonic","touch wah","compressor","noise gate","voice channel","2-way rotary speaker","ensemble detune","ambience"],new Array(4),["talking mod","Lo-Fi","dist + delay","comp + dist + delay","wah + dist + delay","V dist","dual rotor speaker"]),O=["melodic","drums","drum set 1","drum set 2","drum set 3","drum set 4","drum set 5","drum set 6","drum set 7","drum set 8"],fe=[17.1,18.6,20.2,21.8,23.3,24.9,26.5,28,29.6,31.2,32.8,34.3,35.9,37.5,39,40.6,42.2,43.7,45.3,46.9,48.4,50],T=[20,22,25,28,32,36,40,45,50,56,63,70,80,90,100,110,125,140,160,180,200,225,250,280,315,355,400,450,500,560,630,700,800,900,1e3,1100,1200,1400,1600,1800,2e3,2200,2500,2800,3200,3600,4e3,4500,5e3,5600,6300,7e3,8e3,9e3,1e4,11e3,12e3,14e3,16e3,18e3,2e4],z=[0,.04,.08,.13,.17,.21,.25,.29,.34,.38,.42,.46,.51,.55,.59,.63,.67,.72,.76,.8,.84,.88,.93,.97,1.01,1.05,1.09,1.14,1.18,1.22,1.26,1.3,1.35,1.39,1.43,1.47,1.51,1.56,1.6,1.64,1.68,1.72,1.77,1.81,1.85,1.89,1.94,1.98,2.02,2.06,2.1,2.15,2.19,2.23,2.27,2.31,2.36,2.4,2.44,2.48,2.52,2.57,2.61,2.65,2.69,2.78,2.86,2.94,3.03,3.11,3.2,3.28,3.37,3.45,3.53,3.62,3.7,3.87,4.04,4.21,4,37,4.54,4.71,4.88,5.05,5.22,5.38,5.55,5.72,6.06,6.39,6.73,7.07,7.4,7.74,8.08,8.41,8.75,9.08,9.42,9.76,10.1,10.8,11.4,12.1,12.8,13.5,14.1,14.8,15.5,16.2,16.8,17.5,18.2,19.5,20.9,22.2,23.6,24.9,26.2,27.6,28.9,30.3,31.6,33,34.3,37,39.7],q=function(e){let n=.1,l=-.3;return e>66?(n=5,l=315):e>56?(n=1,l=47):e>46&&(n=.5,l=18.5),n*e-l},Q=function(e){return e>105?fe[e-106]:e>100?e*1.1-100:e/10},Y=",a,i,u,e,o,ka,ki,ku,ke,ko,ky,kw,sa,si,su,se,so,sh,ta,ti,tu,te,to,t,ch,t,s,na,ni,nu,ne,no,ny,nn,ha,hi,hu,he,ho,hy,fa,fi,fu,fe,fo,ma,mi,mu,me,mo,my,mm,ya,yu,ye,yo,ra,ri,ru,re,ro,ry,wa,wi,we,wo,ga,gi,gu,ge,go,gy,gw,za,zi,zu,ze,zo,ja,ji,ju,je,jo,jy,da,di,du,de,do,dy,ba,bi,bu,be,bo,by,va,vi,vu,ve,vo,pa,pi,pu,pe,po,py,nga,ngi,ngu,nge,ngo,ngy,ng,hha,hhi,hhu,hhe,hho,hhy,hhw,*,_,,,~,.".split(","),G={};`hi*,
+ka,か
+ki,き
+ku,く
+ke,け
+ko,こ
+ky,き!
+kw,くl
+tsu,つ
+ts,つl
+sa,さ
+si,すぃ
+su,す
+se,せ
+so,そ
+shi,し
+sh,し!
+ta,た
+ti,てぃ
+tu,とぅ
+te,て
+to,と
+tchy,ち!
+tchi,ち
+na,な
+ni,に
+nu,ぬ
+ne,ね
+no,の
+ny,に!
+nn,ん
+ha,は
+hi,ひ
+hu,ほぅ
+he,へ
+ho,ほ
+hy,ひ!
+fa,ふぁ
+fi,ふぃ
+fu,ふ
+fe,ふぇ
+fo,ふぉ
+ma,ま
+mi,み
+mu,む
+me,め
+mo,も
+my,み!
+mm,
+ra,ら
+ri,り
+ru,る
+re,れ
+ro,ろ
+ry,り!
+wa,わ
+wi,うぃ
+we,うぇ
+wo,を
+nga,ガ
+ngi,ギ
+ngu,グ
+nge,ゲ
+ngo,ゴ
+ngy,ギ!
+ng,
+ga,が
+gi,ぎ
+gu,ぐ
+ge,げ
+go,ご
+gy,ぎ!
+gw,ぐl
+za,ざ
+zi,ずぃ
+zu,ず
+ze,ぜ
+zo,ぞ
+ja,じゃ
+ji,じ
+ju,じゅ
+je,じぇ
+jo,じょ
+jy,じ!
+da,だ
+di,でぃ
+du,どぅ
+de,で
+do,ど
+dy,で!
+ba,ば
+bi,び
+bu,ぶ
+be,べ
+bo,ぼ
+by,び!
+va,ゔぁ
+vi,ゔぃ
+vu,ゔ
+ve,ゔぇ
+vo,ゔぉ
+pa,ぱ
+pi,ぴ
+pu,ぷ
+pe,ペ
+po,ぽ
+py,ぴ!
+!ya,ゃ
+!yu,ゅ
+!ye,ぇ
+!yo,ょ
+ya,や
+yu,ゆ
+ye,いぇ
+yo,よ
+!a,ゃ
+!u,ゅ
+!e,ぇ
+!o,ょ
+!a,ゃ
+!u,ゅ
+!e,ぇ
+!o,ょ
+la,ぁ
+li,ぃ
+lu,ぅ
+le,ぇ
+lo,ぉ
+a,あ
+i,い
+u,う
+e,え
+o,お
+*,っ
+~,
+^,
+_,`.split(`
+`).forEach(e=>{let n=e.split(",");G[n[0]]=n[1]});var W=function(e){let n=e;e[0]=="*"&&(n=n.slice(1)),["aa","ii","uu","ee","oo"].forEach(f=>{for(;n.indexOf(f)>-1;)n=n.replace(f,f[0])});for(let f in G)n=n.replaceAll(f,G[f]);n.indexOf("ん")==0&&n.length>1&&(n=n.slice(1));let l=n.indexOf("!");return l>-1&&n.length>1&&(n=n.slice(l+1)),n},J=function(e){return e?e<96?`cc${e}`:["aftertouch","velocity","pitch bend"][e-96]:"off"};var L=["room 1","room 2","room 3","hall 1","hall 2","plate","delay","panning delay"],Z=["chorus 1","chorus 2","chorus 3","chorus 4","feedback","flanger","short delay","short delay feedback"],j=["delay 1","delay 2","delay 3","delay 4","pan delay 1","pan delay 2","pan delay 3","pan delay 4","delay to reverb","pan repeat"];var de={0:"thru",256:"stereo EQ",257:"spectrum",258:"enhancer",259:"humanizer",272:"overdrive",273:"distortion",288:"phaser",289:"auto wah",290:"rotary",291:"stereo flanger",292:"step flanger",293:"tremelo",294:"auto pan",304:"compressor",305:"limiter",320:"hexa chorus",321:"tremelo chorus",322:"stereo chorus",323:"space D",324:"3D chorus",336:"stereo delay",337:"modulated delay",338:"3-tap delay",339:"4-tap delay",340:"tremelo control delay",341:"reverb",342:"gate reverb",343:"3D delay",352:"2-pitch shifter",353:"feedback pitch shifter",368:"3D auto",369:"3D manual",370:"Lo-Fi 1",371:"Lo-Fi 2",512:"overdrive - chorus",513:"overdrive - flanger",514:"overdrive - delay",515:"distortion - chorus",516:"distortion - flanger",517:"distortion - delay",518:"enhancer - chorus",519:"enhancer - flanger",520:"enhancer - delay",521:"chorus - delay",522:"flanger - delay",523:"chorus - flanger",524:"rotary multi",1024:"guitar multi 1",1025:"guitar multi 2",1026:"guitar multi 3",1027:"clean guitar multi 1",1028:"clean guitar multi 2",1029:"bass multi",1030:"rhodes multi",1280:"keyboard multi",4352:"chorus / delay",4353:"flanger / delay",4354:"chorus / flanger",4355:"overdrive / distortion",4356:"overdrive / rotary",4357:"overdrive / phaser",4358:"overdrive / auto wah",4359:"phaser / rotary",4360:"phaser / auto wah"},ue={66307:["drive"],66309:["vowel",e=>"aiueo"[e]],94723:["pre-filter"],94724:["Lo-Fi type"],94725:["post-filter"],94979:["Lo-Fi type"],94980:["fill type",e=>["off","LPF","HPF"][e]],94984:["noise type",e=>["white","pink"][e]],94987:["disc type",e=>["LP","SP","EP","RND"]],94990:["hum type",e=>`${e+5}0Hz`],94993:["M/S",e=>["mono","stereo"][e]]},B=function(e){return de[(e[0]-32<<8)+e[1]]||`0x${e[0].toString(16).padStart(2,"0")}${e[1].toString(16).padStart(2,"0")}`},ee=function(e,n,l){let f=(e[0]-32<<16)+(e[1]<<8)+n,t=ue[f]||{},a=t[0];if(a?.length)return a+=`: ${(t[1]||function(){})(l)||l}`,a},_=[68,48,95,78,41,3,110,122,0];var E=function(e=64){return Math.round(2e3*Math.log10(e/64))/100};var te=function(e){let n=0;return e.forEach(l=>{n+=l,n=n&127}),~n+1&127},m=function(e,n){let l=0,f=0;for(let t=0;t>a&1)<<7,i=e[t];i+=r,t%8!=0?(n(i,l,e),l++):f=e[t]}},D=function(e){let n=Math.floor(e*14.2);return n<128?n:0};var x=["?","gm","gs","xg","g2","mt32","ns5r","ag10","x5d","05rw","k11","sg","krs","s90es","motif"],se=[[0,0,0,0,121,0,0,56,82,81,0,0,63,63,63],[0,0,4,0,0,127,0,0,0,0,0,0,0,0,0]],C=[120,127,120,127,120,127,61,62,62,62,120,122,122,127],be=[0,3,81,84,88],ae={8:"Off",9:"On",10:"Note aftertouch",11:"cc",12:"pc",13:"Channel aftertouch",14:"Pitch"},I={0:0,1:1,2:3,5:4},ie=[[0,24],[0,127],[0,127],[40,88],[0,127],[0,127]],re=[36,37],A=[20,21,22,23,24,25,26,28,29,30,31,36,37,64,65],U=[0,1,2,4,5,6,7,8,10,11,32,38,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,84,91,92,93,94,95,98,99,100,101,128,12,13,16,17,18,19],pe=[12,13,16,17,18,19],$e=[33,99,100,32,102,8,9,10],ne=[0,16,25,40,32,64,26,48],g={};x.forEach((e,n)=>{g[e]=n});var d={length:U.length};U.forEach((e,n)=>{d[e]=n});var oe={length:A.length};A.forEach((e,n)=>{oe[e]=n});var k=function(){return!!self.Bun||self.debugMode||!1},ge=function(e){let n=[],l=0;return e?.forEach(function(f,t){f==247?n.push(e.subarray(l,t)):f==240&&(l=t+1)}),n.length||n.push(e.subarray(0)),k()&&console.debug(n),n},le=function(e,n="",l="",f=2){return e?`${n}${e.toString().padStart(f,"0")}${l}`:""},u={ch:128,cc:U.length,nn:128,pl:512,tr:256,cmt:14,rpn:6,ace:8,drm:8,dpn:A.length,dnc:128,efx:7},Ie=class extends F{NOTE_IDLE=0;NOTE_ATTACK=1;NOTE_DECAY=2;NOTE_SUSTAIN=3;NOTE_HELD=4;NOTE_RELEASE=5;NOTE_SOSTENUTO_ATTACK=8;NOTE_SOSTENUTO_DECAY=9;NOTE_SOSTENUTO_SUSTAIN=10;NOTE_SOSTENUTO_HELD=11;CH_MELODIC=0;CH_DRUMS=1;CH_DRUM1=2;CH_DRUM2=3;CH_DRUM3=4;CH_DRUM4=5;CH_DRUM5=6;CH_DRUM6=7;CH_DRUM7=8;CH_DRUM8=9;#t=0;#p=0;#m=0;#v=new Array(11);get#$(){return this.#v[this.#p]}set#$(e){this.#v[this.#p]=e}#l=new Uint8Array(u.ch);#f=new Uint8Array(u.ch);#i=new Uint8Array(u.ch);#e=new Uint8Array(u.ch*u.cc);#R=new Uint8Array(u.ace);#r=new Uint8Array(u.ch);#o=new Uint8Array(u.ch*u.nn);#w=new Uint8Array(u.ch);#c=new Uint16Array(u.pl);#d=new Uint8Array(u.pl);#P=new Int16Array(u.ch);#x=new Uint8Array(u.ch);#B=0;#s=new Uint8Array(u.ch*u.rpn);#z=new Int8Array(u.ch*re.length);#J=new Uint8Array(u.drm*u.dpn*u.dnc);#C=new Uint8Array(u.ch);#A=new Uint8Array(128);#E=new Uint8Array(u.cmt*8);#q=new Uint8Array(1024);#N=new Uint8Array(u.cmt*64);#g=new Uint8Array(u.efx*3);#H=0;#k=0;#b=100;#O=0;#Q=500;#Y=0;#M="";#G=0;#W=0;#S=!0;#n=!1;#Z;#te=new Uint8Array(2);#a=[];#D=new Uint8Array(u.ch);#L=new Uint8Array(u.tr);baseBank=new H("gm","gm2","xg","gs","ns5r","gmega","plg-150vl","plg-150pf","plg-150dx","plg-150an","plg-150dr","plg-100sg","kross","s90es");userBank=new H("gm");initOnReset=!1;aiEfxName="";chRedir(e,n,l){if(this.#L[n])return(this.#L[n]-1)*16+e;if([2,3].indexOf(this.#k)>-1){if(l==1)return e;let f=0,t=!0;for(;t;)this.#D[e+f]==0?(this.#D[e+f]=n,console.debug(`Assign track ${n} to channel ${e+f+1}.`),t=!1):this.#D[e+f]==n?t=!1:(f+=16,f>=128&&(f=0,t=!1));return e+f}else return e}#u=[];#_;#h={nOff:(e,n)=>{let l=e*128+n,f=this.#c.lastIndexOf(l);f>-1&&(this.#e[u.cc*e+d[64]]>63?(this.#d[f]=this.NOTE_HELD,this.dispatchEvent("note",{part:e,note:n,velo:this.#o[l],state:this.NOTE_HELD})):this.#e[u.cc*e+d[66]]>63&&this.#d[f]==this.NOTE_SOSTENUTO_SUSTAIN?(this.#d[f]=this.NOTE_SOSTENUTO_HELD,this.dispatchEvent("note",{part:e,note:n,velo:this.#o[l],state:this.NOTE_SOSTENUTO_HELD})):(this.#c[f]=0,this.#o[l]=0,this.#d[f]=this.NOTE_IDLE,this.dispatchEvent("note",{part:e,note:n,velo:0,state:this.NOTE_IDLE})))},nOn:(e,n,l)=>{let f=e*128+n,t=0;for(this.#w[e]&&this.#h.ano(e);this.#d[t]>0&&this.#c[t]!=f;)t++;t{},cAt:(e,n)=>{},hoOf:e=>{this.#d.forEach((n,l)=>{if(n==this.NOTE_HELD){let f=this.#c[l],t=f>>7;e==t&&(this.#d[l]=this.NOTE_IDLE,this.#c[l]=0,this.#o[f]=0,this.dispatchEvent("note",{part:e,note:f&127,velo:0,state:this.NOTE_IDLE}))}})},soOn:e=>{this.#d.forEach((n,l)=>{let f;switch(n){case this.NOTE_ATTACK:{f=this.NOTE_SOSTENUTO_ATTACK;break}case this.NOTE_DECAY:{f=this.NOTE_SOSTENUTO_DECAY;break}case this.NOTE_SUSTAIN:{f=this.NOTE_SOSTENUTO_SUSTAIN;break}}if(f){this.#d[l]=f;let t=this.#c[l];this.dispatchEvent("note",{part:e,note:t&127,velo:this.#o[t],state:f})}})},soOf:e=>{this.#d.forEach((n,l)=>{if(n==this.NOTE_SOSTENUTO_HELD){let f=this.#c[l],t=f>>7;e==t&&(this.#d[l]=this.NOTE_IDLE,this.#c[l]=0,this.#o[f]=0,this.dispatchEvent("note",{part:e,note:f&127,velo:0,state:this.NOTE_IDLE}))}})},ano:e=>{this.#c.forEach((n,l,f)=>{let t=n>>7,a=n&127;n==0&&this.#o[0]==0||t==e&&this.#h.nOff(t,a)})}};#j={8:function(e){let n=e.channel,l=e.data[0];this.#h.nOff(n,l)},9:function(e){let n=e.channel;this.#l[n]=1;let l=e.data[0],f=e.data[1];f>0?this.#h.nOn(n,l,f):this.#h.nOff(n,l)},10:function(e){let n=e.channel,l=n*128+e.data[0];this.#c.indexOf(l)>-1&&(this.#o[l]=data[1],this.dispatchEvent("note",{part:n,note:e.data[0],velo:e.data[1],state:this.NOTE_SUSTAIN}))},11:function(e){let n=e.channel;[0,32].indexOf(e.data[0])>-1&&(()=>{switch(this.#t){case g.s90es:case g.motif:{if(e.data[0]==0){[0,63].indexOf(e.data[1])>-1&&(this.#l[n]=1);break}e.data[1]&&(this.#l[n]=1);break}default:{this.#l[n]=1;break}}})();let l=n*u.cc;switch(e.data[0]){case 96:return;case 97:return;case 120:return;case 121:{this.#h.ano(n),this.#P[n]=0;let f=n*u.cc;this.#e[f+d[1]]=0,this.#e[f+d[5]]=0,this.#e[f+d[64]]=0,this.#e[f+d[65]]=0,this.#e[f+d[66]]=0,this.#e[f+d[67]]=0,this.#e[f+d[11]]=127,this.#e[f+d[101]]=127,this.#e[f+d[100]]=127,this.#e[f+d[99]]=127,this.#e[f+d[98]]=127;return}case 123:{this.#h.ano(n);return}case 124:{this.#h.ano(n);return}case 125:{this.#h.ano(n);return}case 126:{this.#w[n]=1,this.#h.ano(n);return}case 127:{this.#w[n]=0,this.#h.ano(n);return}}if(d[e.data[0]]==null)console.warn(`cc${e.data[0]} is not accepted.`);else{switch(pe.indexOf(e.data[0])>-1&&this.allocateAce(e.data[0]),e.data[0]){case 0:{if(k()&&console.debug(`${x[this.#t]}, CH${n+1}: ${e.data[1]}`),this.#t==0)e.data[1]<48?(this.#i[n]>0&&(e.data[1]=this.#e[l],e.data[1]=120,console.debug(`Forced channel ${n+1} to stay drums.`)),e.data[1]>0&&(console.debug(`Roland GS detected with MSB: ${e.data[1]}`),this.switchMode("gs"))):e.data[1]==62?this.switchMode("x5d"):e.data[1]==63?this.switchMode("krs"):(e.data[1]==64||e.data[1]==127)&&this.switchMode("xg");else if(this.#t==g.gs)e.data[1]<56&&this.#i[n]>0&&(e.data[1]=this.#e[l],e.data[1]=120,console.debug(`Forced channel ${n+1} to stay drums.`));else if(this.#t==g.gm)e.data[1]<48?this.#i[n]>0&&(e.data[1]=120,this.switchMode("gs",!0),console.debug(`Forced channel ${n+1} to stay drums.`)):(e.data[1]==64||e.data[1]==127)&&this.switchMode("xg",!0);else if(this.#t==g.x5d){if(e.data[1]>0&&e.data[1]<8)this.switchMode("05rw",!0);else if(e.data[1]==56){let f=0;for(let t=0;t<16;t++){let a=this.#e[u.cc*t];(a==56||a==62)&&f++}f>14&&this.switchMode("ag10",!0)}}switch(this.#t){case g.xg:{[126,127].indexOf(e.data[1])>-1?this.#i[n]==0&&(this.setChType(n,this.CH_DRUM2),console.debug(`CH${n+1} set to drums by MSB.`)):this.#i[n]>0&&(this.setChType(n,this.CH_MELODIC),console.debug(`CH${n+1} set to melodic by MSB.`));break}case g["05rw"]:case g.x5d:case g.ns5r:{[61,62,126,127].indexOf(e.data[1])>-1?this.#i[n]==0&&(this.setChType(n,this.CH_DRUM2),console.debug(`CH${n+1} set to drums by MSB.`)):this.#i[n]>0&&(this.setChType(n,this.CH_MELODIC),console.debug(`CH${n+1} set to melodic by MSB.`));break}case g.g2:{e.data[1]==120?this.#i[n]==0&&(this.setChType(n,this.CH_DRUMS),console.debug(`CH${n+1} set to drums by MSB.`)):this.#i[n]>0&&(this.setChType(n,this.CH_MELODIC),console.debug(`CH${n+1} set to melodic by MSB.`));break}}this.dispatchEvent("voice",{part:n});break}case 6:{if(this.#B){[g.xg,g.gs,g.ns5r].indexOf(this.#t)<0&&console.warn(`NRPN commits are not available under "${x[this.#t]}" mode, even when they are supported in Octavia.`);let f=this.#e[l+d[99]],t=this.#e[l+d[98]];if(f==1){let a=$e.indexOf(t);if(a>-1)this.#e[l+d[71+a]]=e.data[1],k()&&console.debug(`Redirected NRPN 1 ${t} to cc${71+a}.`),this.dispatchEvent("cc",{part:n,cc:71+a,data:e.data[1]});else{let r=re.indexOf(t);r>-1?this.#z[n*10+r]=e.data[1]-64:console.warn(`NRPN 0x01${t.toString(16).padStart(2,"0")} is not supported.`),k()&&console.debug(`CH${n+1} voice NRPN ${t} commit`)}}else{if(A.indexOf(f)<0){let r=`NRPN 0x${f.toString(16).padStart(2,"0")}${t.toString(16).padStart(2,"0")} `;f==127?console.warn(`${r}is not necessary. Consider removing it.`):console.warn(`${r}is not supported.`)}else{let r=this.#i[n]-2;r<0?console.warn(`CH${n+1} cannot accept drum NRPN as type ${O[this.#i[n]]}.`):this.#J[(r*u.dpn+oe[f])*u.dnc+t]=e.data[1]-64}k()&&console.debug(`CH${n+1} (${O[this.#i[n]]}) drum NRPN ${f} commit`)}}else{let f=I[this.#e[l+d[100]]];this.#e[l+d[101]]==0&&f!=null&&(k()&&console.debug(`CH${n+1} RPN 0 ${this.#e[l+d[100]]} commit: ${e.data[1]}`),e.data[1]=Math.min(Math.max(e.data[1],ie[f][0]),ie[f][1]),this.#s[n*u.rpn+f]=e.data[1])}break}case 32:{switch(this.#t){case g.s90es:case g.motif:{this.#i[n]=+([32,40].indexOf(e.data[1])>-1)<<1;break}}this.dispatchEvent("voice",{part:n});break}case 38:{this.#B||this.#e[l+101]==0&&I[this.#e[l+100]]!=null&&(this.#s[n*u.rpn+I[this.#e[l+100]]+1]=e.data[1]);break}case 64:{e.data[1]<64&&this.#h.hoOf(n);break}case 66:{e.data[1]>>6?this.#h.soOn(n):this.#h.soOf(n);break}case 98:case 99:{this.#B=1;break}case 100:case 101:{this.#B=0;break}}this.#e[l+d[e.data[0]]]=e.data[1],this.dispatchEvent("cc",{part:n,cc:e.data[0],data:e.data[1]})}},12:function(e){let n=e.channel;switch(this.#t){case g.s90es:case g.motif:{e.data&&(this.#l[n]=1);break}default:this.#l[n]=1}this.#r[n]=e.data,this.#C[n]=0,k()&&console.debug(`T:${e.track} C:${n} P:${e.data}`),this.dispatchEvent("voice",{part:n})},13:function(e){let n=this,l=e.channel;this.#c.forEach(function(f){let t=f>>7;l==t&&(n.#o[f]=e.data,n.dispatchEvent("note",{part:l,note:f&127,velo:e.data,state:n.NOTE_SUSTAIN}))})},14:function(e){let n=e.channel;this.#P[n]=e.data[1]*128+e.data[0]-8192,this.dispatchEvent("pitch",{part:n,pitch:this.getPitchShift(n)})},15:function(e){ge(e.data).forEach(n=>{let l=n[0],f=n[1];(this.#ee[l]||function(){console.debug(`Unknown manufacturer ${l}.`)})(f,n.subarray(2),e.track)})},248:function(e){},250:function(e){},251:function(e){},252:function(e){},254:function(e){},255:function(e){(this.#u[e.meta]||function(l,f,t){}).call(this,e.data,e.track,e.meta),e.meta!=32&&(this.#O=0);let n=be.indexOf(e.meta)>-1;if(k()&&console.debug(e),n)return e.reply="meta",e}};#ee={64:(e,n,l)=>{this.#F.run(n,l,e)},65:(e,n,l)=>{if(n[0]<16)this.#T.run(n,l,e),console.warn("Unknown device SysEx!");else{let f=n[n.length-1],t=te(n.subarray(2,n.length-1));f==t?this.#T.run(n.subarray(0,n.length-1),l,e):console.warn(`Bad GS checksum ${f}. Should be ${t}.`)}},66:(e,n,l)=>{this.#U.run(n,l,e)},67:(e,n,l)=>{this.#y.run(n,l,e)},68:(e,n,l)=>{this.#V.run(n,l,e)},71:(e,n,l)=>{this.#K.run(n,l,e)},126:(e,n,l)=>{this.#I.run(n,l,e)},127:(e,n,l)=>{this.switchMode("gm"),this.#X.run(n,l,e)}};#I;#X;#y;#T;#U;#F;#K;#V;buildRchTree(){let e=[];this.#f.forEach((n,l)=>{e[n]?.constructor||(e[n]=[]),e[n].push(l)}),this.#Z=e}getActive(){let e=this.#l.slice();return this.#t==g.mt32,e}getCc(e){let n=e*u.cc,l=this.#e.subarray(n,n+u.cc);return l[d[0]]=l[d[0]]||this.#H,l[d[32]]=l[d[32]]||this.#k,l}getCcCh(e,n){if(U.indexOf(n)<0)throw new Error("CC number not accepted");return this.#e[u.cc*e+d[n]]}getCcAll(){let e=this.#e.slice();for(let n=0;n0&&(this.#e[e*u.cc+d[0]]=C[l])}getPitch(){return this.#P}getProgram(){return this.#r}getTexts(){return this.#a.slice()}getVel(e){let n=new Map,l=this;return l.#c.forEach(function(f,t){let a=Math.floor(f/128),r=f%128;e==a&&l.#o[f]>0&&n.set(r,{v:l.#o[f],s:l.#d[t]})}),n}getBitmap(){return{bitmap:this.#$,expire:this.#m}}getLetter(){return{text:this.#M,expire:this.#G}}getMode(){return x[this.#t]}getMaster(){return{volume:this.#b}}getRawStrength(){let e=this;return this.#c.forEach(function(n){let l=Math.floor(n/128);e.#o[n]>e.#x[l]&&(e.#x[l]=e.#o[n])}),this.#x}getStrength(){let e=[],n=this;return this.getRawStrength().forEach(function(l,f){e[f]=Math.floor(l*n.#e[f*u.cc+d[7]]*n.#e[f*u.cc+d[11]]*n.#b/803288)}),e}getRpn(){return this.#s}getNrpn(){return this.#z}getVoice(e,n,l,f){let t=e||this.#H,a=n,r=l||this.#k;x[this.#t]=="ns5r"&&t>0&&t<56&&(r=3);let i=this.userBank.get(t,a,r,f);if(x[this.#t]=="mt32"&&i.name.indexOf("MT-m:")==0){let s=parseInt(i.name.slice(5)),o=s*u.cmt,c="";this.#N.subarray(o,o+10).forEach(h=>{h>31&&(c+=String.fromCharCode(h))}),this.userBank.load(`MSB LSB PRG
+0 127 ${a} ${c}`,!0),i.name=c,i.ending=" "}return(i.ending!=" "||!i.name.length)&&(i=this.baseBank.get(t,a,r,f)),i}getChVoice(e){let n=this.getVoice(this.#e[e*u.cc+d[0]],this.#r[e],this.#e[e*u.cc+d[32]],x[this.#t]);if(this.#C[e])switch(this.#t){case g.mt32:n.ending="~",n.name="",this.#E.subarray(14*(e-1),14*(e-1)+10).forEach(l=>{l>31&&(n.name+=String.fromCharCode(l))})}return n}getPitchShift(e){let n=e*u.rpn;return this.#P[e]/8192*this.#s[n]+(this.#s[n+3]-64)+((this.#s[n+1]<<7)+this.#s[n+2]-8192)/8192}getEffectType(e=0){let n=3*e+1;return this.#g.subarray(n,n+2)}setEffectTypeRaw(e=0,n,l){let f=3*e;this.#g[f]=1,this.#g[f+1+ +n]=l}setEffectType(e=0,n,l){this.setEffectTypeRaw(e,!1,n),this.setEffectTypeRaw(e,!0,l)}setLetterDisplay(e,n,l=0,f=3200){let t=this,a;t.#M=" ".repeat(l),e.forEach(r=>{t.#M+=String.fromCharCode(r>31?r:32),r<32&&(a=a||new Set,a.add(r))}),t.#G=Date.now()+3200,t.#M=t.#M.padEnd(32," "),a&&(a=Array.from(a),a.forEach((r,i,s)=>{s[i]=r.toString(16).padStart(2,"0")}),console.warn(`${n}${n?" ":""}invalid code point${a.length>1?"s":""}: 0x${a.join(", 0x")}`))}allocateAce(e){if(!e||e>95){console.warn(`cc${e} cannot be allocated as an active custom effect.`);return}let n=!0,l=0;for(;n&&l=u.ace&&console.warn("ACE slots are full.")}getAce(){return this.#R}getChAce(e,n){if(n<0||n>=u.ace)throw new RangeError("No such ACE slot");let l=this.#R[n];if(l){if(U.indexOf(l)>=0)return this.#e[e*u.cc+d[l]];throw new Error(`Invalid ACE source: ${l}`)}else return 0}init(e=0){this.dispatchEvent("mode","?"),this.#t=0,this.#H=0,this.#k=0,this.#O=0,this.#l.fill(0),this.#e.fill(0),this.#R.fill(0),this.#r.fill(0),this.#o.fill(0),this.#c.fill(0),this.#x.fill(0),this.#P.fill(0),this.#z.fill(0),this.#J.fill(0),this.#b=100,this.#a=[],this.#Q=500,this.#Y=0,this.#G=0,this.#M="",this.#m=0,this.#p=0,this.#$.fill(0),this.#n=!1,this.#W=0,this.#S=!0,this.#f.forEach(function(n,l,f){f[l]=l}),this.buildRchTree(),e==0&&(this.#D.fill(0),this.#L.fill(0)),this.#e[u.cc*9]=C[0],this.#e[u.cc*25]=C[0],this.#e[u.cc*41]=C[0],this.#e[u.cc*57]=C[0],this.#i.fill(this.CH_MELODIC),this.#i[9]=this.CH_DRUM1,this.#i[25]=this.CH_DRUM3,this.#i[41]=this.CH_DRUMS,this.#i[57]=this.CH_DRUMS,this.#i[73]=this.CH_DRUM5,this.#i[89]=this.CH_DRUM7,this.#i[105]=this.CH_DRUMS,this.#i[121]=this.CH_DRUMS,this.#q.fill(0),this.#N.fill(0),this.#A.fill(0),this.#E.fill(0),this.#C.fill(0),this.#g.fill(0),this.aiEfxName="",this.userBank.clearRange({msb:0,lsb:127,prg:[0,127]});for(let n=0;n-1){if(this.#t==0||n){let f=this.#t;this.#t=l,this.#p=0,this.#H=se[0][l],this.#k=se[1][l];for(let a=0;a0&&this.#e[a*u.cc+d[0]]==C[f]&&(this.#e[a*u.cc]=C[l]);switch(this.initOnReset,l){case g.mt32:{_.forEach((a,r)=>{let i=r+1;this.#l[i]||(this.#r[i]=a,this.#e[i*u.cc+d[91]]=127)});break}}let t;switch(l){case g.gs:{t=[40,4,40,18,40,32,32,0,0,0,0,0,0,0];break}case g.x5d:case g.ns5r:{t=[44,1,44,19,44,0,44,0,0,0,0,0,0,0];break}default:t=[1,0,65,0,5,0,0,0,0,0,0,0,0,0]}for(let a=0;a14)return e.type==15&&e.data.constructor!=Uint8Array&&(e.data=Uint8Array.from(e.data)),this.#j[e.type].call(this,e);{let n=this.chRedir(e.part,e.track),l=!1;this.#Z[n]?.forEach(f=>{e.channel=f,l=!0,this.#j[e.type].call(this,e)}),l||console.warn(`${ae[e.type]?ae[e.type]:e.type}${[11,12].includes(e.type)?(e.data[0]!=null?e.data[0]:e.data).toString():""} event sent to CH${n+1} without any recipient.`)}this.#a.length>100&&this.#a.splice(100,this.#a.length-99)}runRaw(e){}async loadBank(e,n){switch(e=e.toLowerCase(),e){case"s7e":{this.userBank.clearRange({msb:63,lsb:[21,22]}),this.userBank.clearRange({msb:63,lsb:[24,27]});break}default:throw new Error(`Unknown bank format ${e}`)}switch(e){case"s7e":{P.context=this,this.userBank.load(await P.read(e,n));break}}}constructor(){super();let e=this;this.#$=new Uint8Array(256),this.#v[10]=new Uint8Array(512),this.#_=new S,this.userBank.strictMode=!0,this.userBank.load(`MSB PRG LSB NME
+062 000 000
+122 000 000
+122 001 000
+122 002 000
+122 003 000
+122 004 000
+122 005 000
+122 006 000 `),this.#u[1]=function(t){switch(t.slice(0,2)){case"@I":{this.#n=!0,this.#a.unshift(`Kar.Info: ${t.slice(2)}`);break}case"@K":{this.#n=!0,this.#a.unshift("Karaoke mode active."),console.debug(`Karaoke mode active: ${t.slice(2)}`);break}case"@L":{this.#n=!0,this.#a.unshift(`Language: ${t.slice(2)}`);break}case"@T":{this.#n=!0,this.#a.unshift(`Ka.Title: ${t.slice(2)}`);break}case"@V":{this.#n=!0,this.#a.unshift(`Kara.Ver: ${t.slice(2)}`);break}case"XF":{let a=t.slice(2).split(":");switch(a[0]){case"hd":{a.slice(1).forEach((r,i)=>{r.length&&this.#a.unshift(`${["SongDate","SnRegion","SongCat.","SongBeat","SongInst","Sn.Vocal","SongCmp.","SongLrc.","SongArr.","SongPerf","SongPrg.","SongTags"][i]}: ${r}`)});break}case"ln":{a.slice(1).forEach((r,i)=>{r.length&&this.#a.unshift(`${["Kar.Lang","Kar.Name","Kar.Cmp.","Kar.Lrc.","kar.Arr.","Kar.Perf","Kar.Prg."][i]}: ${r}`)});break}default:this.#a.unshift(`XGF_Data: ${t}`)}break}default:this.#n?t[0]=="\\"?this.#a.unshift(`@ ${t.slice(1)}`):t[0]=="/"?this.#a.unshift(t.slice(1)):this.#a[0]+=t:(this.#a[0]=t,this.#a.unshift(""))}},this.#u[2]=function(t){this.#a.unshift(`Copyrite: ${t}`)},this.#u[3]=function(t,a){a<1&&this.#O<1&&this.#a.unshift(`TrkTitle: ${t}`)},this.#u[4]=function(t,a){this.#a.unshift(`${le(this.#O,""," ")}Instrmnt: ${t}`)},this.#u[5]=function(t){t.trim()==""?this.#a.unshift(""):this.#a[0]+=`${t}`},this.#u[6]=function(t){this.#a.unshift(`${le(this.#O,""," ")}C.Marker: ${t}`)},this.#u[7]=function(t){this.#a.unshift(`CuePoint: ${t}`)},this.#u[32]=function(t){this.#O=t[0]+1},this.#u[33]=function(t,a){console.debug(`Track ${a} requests to get assigned to output ${t}.`),e.#L[a]=t+1},this.#u[81]=function(t,a){e.#Q=t/1e3},this.#u[127]=function(t,a){e.#_.run(t,a)},this.#_.default=function(t){console.warn(`Unrecognized sequencer-specific byte sequence: ${t}`)},this.#_.add([67,0,1],function(t,a){e.#L[a]=t[0]+1}),this.#I=new S("universal non-realtime"),this.#X=new S("universal realtime"),this.#y=new S("Yamaha"),this.#T=new S("Roland"),this.#U=new S("Korg"),this.#F=new S("Kawai"),this.#K=new S("Akai"),this.#V=new S("Casio");let n=function(t){console.info(`Unrecognized SysEx in "${this.name}" set.`,t)};this.#I.default=n,this.#X.default=n,this.#y.default=n,this.#T.default=n,this.#U.default=n,this.#F.default=n,this.#K.default=n,this.#V.default=n,this.#I.add([9],t=>{e.switchMode(["gm","?","g2"][t[0]-1],!0),e.#n=e.#n||!1,console.info(`MIDI reset: ${["GM","Init","GM2"][t[0]-1]}`),t[0]==2&&e.init()}),this.#X.add([4,1],t=>{e.#b=((t[1]<<7)+t[0])/16383*100}).add([4,3],t=>((t[1]<<7)+t[0]-8192)/8192).add([4,4],t=>t[1]-64),this.#y.add([76,0,0],t=>{switch(t[0]){case 125:{console.info(`XG drum setup reset: ${t}`);break}case 126:{e.switchMode("xg",!0),e.#n=!1,console.info("MIDI reset: XG");break}default:{let a=[0,0,0,0],r=(i,s)=>{a[s]=i};if(t.subarray(1).forEach((i,s)=>{let o=s+t[0];([r,r,r,r,c=>{this.#b=c*129/16383*100},c=>{},c=>{}][o]||(()=>{}))(i,s)}),t[0]<4){let i=0;a.forEach(s=>{i=i<<4,i+=s}),i-=1024}}}}).add([76,2,1],t=>{let a="XG ";t[0]<32?(a+="reverb ",t.subarray(1).forEach((r,i)=>{([s=>{e.setEffectTypeRaw(0,!1,s),console.info(`${a}main type: ${R[s]}`)},s=>{e.setEffectTypeRaw(0,!0,s),console.debug(`${a}sub type: ${s+1}`)},s=>{console.debug(`${a}time: ${q(s)}s`)},s=>{console.debug(`${a}diffusion: ${s}`)},s=>{console.debug(`${a}initial delay: ${s}`)},s=>{console.debug(`${a}HPF cutoff: ${T[s]}Hz`)},s=>{console.debug(`${a}LPF cutoff: ${T[s]}Hz`)},s=>{console.debug(`${a}width: ${s}`)},s=>{console.debug(`${a}height: ${s}`)},s=>{console.debug(`${a}depth: ${s}`)},s=>{console.debug(`${a}wall type: ${s}`)},s=>{console.debug(`${a}dry/wet: ${s}`)},s=>{console.debug(`${a}send: ${E(s)}dB`)},s=>{console.debug(`${a}pan: ${s-64}`)},!1,!1,s=>{console.debug(`${a}delay: ${s}`)},s=>{console.debug(`${a}density: ${s}`)},s=>{console.debug(`${a}balance: ${s}`)},s=>{},s=>{console.debug(`${a}feedback: ${s}`)},s=>{}][t[0]+i]||function(){console.warn(`Unknown XG reverb address: ${t[0]}.`)})(r)})):t[0]<64?(a+="chorus ",t.subarray(1).forEach((r,i)=>{([s=>{e.setEffectTypeRaw(1,!1,s),console.info(`${a}main type: ${R[s]}`)},s=>{e.setEffectTypeRaw(1,!0,s),console.debug(`${a}sub type: ${s+1}`)},s=>{console.debug(`${a}LFO: ${z[s]}Hz`)},s=>{},s=>{console.debug(`${a}feedback: ${s}`)},s=>{console.debug(`${a}delay offset: ${Q(s)}ms`)},s=>{},s=>{console.debug(`${a}low: ${T[s]}Hz`)},s=>{console.debug(`${a}low: ${s-64}dB`)},s=>{console.debug(`${a}high: ${T[s]}Hz`)},s=>{console.debug(`${a}high: ${s-64}dB`)},s=>{console.debug(`${a}dry/wet: ${s}`)},s=>{console.debug(`${a}send: ${E(s)}dB`)},s=>{console.debug(`${a}pan: ${s-64}`)},s=>{console.debug(`${a}to reverb: ${E(s)}dB`)},!1,s=>{},s=>{},s=>{},s=>{console.debug(`${a}LFO phase diff: ${(s-64)*3}deg`)},s=>{console.debug(`${a}input mode: ${s?"stereo":"mono"}`)},s=>{}][t[0]-32+i]||function(){console.warn(`Unknown XG chorus address: ${t[0]}.`)})(r)})):t[0]<86?(a+="variation ",t.subarray(1).forEach((r,i)=>{([s=>{e.setEffectTypeRaw(2,!1,s),console.info(`${a}main type: ${R[s]}`)},s=>{e.setEffectTypeRaw(2,!0,s),console.debug(`${a}sub type: ${s+1}`)}][t[0]-64+i]||function(){})(r)})):t[0]<97?(a+="variation ",t.subarray(1).forEach((r,i)=>{[s=>{console.debug(`${a}send: ${E(s)}dB`)},s=>{console.debug(`${a}pan: ${s-64}`)},s=>{console.debug(`${a}to reverb: ${E(s)}dB`)},s=>{console.debug(`${a}to chorus: ${E(s)}dB`)},s=>{console.debug(`${a}connection: ${s?"system":"insertion"}`)},s=>{console.debug(`${a}channel: CH${s+1}`)},s=>{console.debug(`${a}mod wheel: ${s-64}`)},s=>{console.debug(`${a}bend wheel: ${s-64}`)},s=>{console.debug(`${a}channel after touch: ${s-64}`)},s=>{console.debug(`${a}AC1: ${s-64}`)},s=>{console.debug(`${a}AC2: ${s-64}`)}][t[0]-86+i](r)})):t[0]>111&&t[0]<118?a+="variation ":console.warn(`Unknown XG variation address: ${t[0]}`)}).add([76,2,64],t=>{t.subarray(1).forEach((a,r)=>{let i=r+t[0];if(i==0)console.debug(`XG EQ preset: ${["flat","jazz","pop","rock","classic"][a]}`);else{let s=i-1>>2,o=i-1&3,c=`XG EQ ${s} ${["gain","freq","Q","shape"][o]}: `;[()=>{console.debug(`${c}${a-64}dB`)},()=>{console.debug(`${c}${a} (raw)`)},()=>{console.debug(`${c}${a/10}`)},()=>{console.debug(`${c}${["shelf","peak"][+!!a]}`)}][o]()}})}).add([76,3],t=>{let a=t[0],r=t[1],i=`XG Insertion ${t[0]+1} `;t.subarray(2).forEach((s,o)=>{([c=>{e.setEffectTypeRaw(3+a,!1,c),console.info(`${i}main type: ${R[c]}`)},c=>{e.setEffectTypeRaw(3+a,!0,c),console.debug(`${i}sub type: ${c+1}`)}][r+o]||function(){})(s)})}).add([76,6,0],t=>{let a=t[0];a<64?e.setLetterDisplay(t.subarray(1),"XG letter display",a):e.#G=Date.now()}).add([76,7,0],t=>{let a=t[0];e.#p=0,e.#m=Date.now()+3200,e.#$.fill(0);let r=t.subarray(1);for(let i=0;i>6-p&1,p++})}).add([76,8],(t,a)=>{let r=e.chRedir(t[0],a,!0),i=t[1],s=u.cc*r,o=`XG CH${r+1} `,c=`Unknown XG part address ${i}.`;t.subarray(2).forEach((h,b)=>{i<1?console.debug(c):i<41?([()=>{e.#e[s+d[0]]=h},()=>{e.#e[s+d[32]]=h},()=>{e.#r[r]=h},()=>{let p=e.chRedir(h,a,!0);e.#f[r]=p,r!=p&&(e.buildRchTree(),console.info(`${o}receives from CH${p+1}`))},()=>{e.#w[r]=+!h},()=>{},()=>{e.setChType(r,h,g.xg),console.debug(`${o}type: ${O[h]||h}`)},()=>{e.#s[u.rpn*r+3]=h},!1,!1,()=>{e.#e[s+d[7]]=h},!1,!1,()=>{e.#e[s+d[10]]=h||128},!1,!1,()=>{e.#e[s+d[128]]=h},()=>{e.#e[s+d[93]]=h},()=>{e.#e[s+d[91]]=h},()=>{e.#e[s+d[94]]=h},()=>{e.#e[s+d[76]]=h},()=>{e.#e[s+d[77]]=h},()=>{e.#e[s+d[78]]=h},()=>{e.#e[s+d[74]]=h},()=>{e.#e[s+d[71]]=h},()=>{e.#e[s+d[73]]=h},()=>{e.#e[s+d[75]]=h},()=>{e.#e[s+d[72]]=h}][i+b-1]||(()=>{}))():i<48?console.debug(c):i<111?i>102&&i<105&&(e.#e[s+d[[5,65][i&1]]]=h):i<114?console.debug(c):i<116?console.debug(`${o}EQ ${["bass","treble"][i&1]} gain: ${h-64}dB`):i<118?console.debug(c):i<120?console.debug(`${o}EQ ${["bass","treble"][i&1]} freq: ${h}`):console.debug(c)})}).add([76,9],(t,a)=>{let r=e.chRedir(t[0],a,!0),i=t[1],s=`PLG-150VL CH${r+1} `;t.subarray(2).forEach((o,c)=>{let h=c+i;switch(h){case 1:{console.info(`${s}breath mode: ${["system","breath","velocity","touch EG"][o]}`);break}case 0:case 27:case 28:break;default:if(h<27){let b=["pressure","embouchure","tonguing","scream","breath noise","growl","throat formant","harmonic enhancer","damping","absorption","amplification","brightness"][h-3>>1];h&1?h<23?(console.debug(`${s}${b} control source: ${J(o)}`),o&&o<96&&e.allocateAce(o)):console.debug(`${s}${b} scale break point: ${o}`):console.debug(`${s}${b} depth: ${o-64}`)}}})}).add([76,10],t=>{}).add([76,16],t=>{}).add([76,17,0,0],t=>{}).add([76,112],t=>{console.debug(`XG enable PLG-1${["50VL","00SG","50DX"][t[0]]} for CH${t[2]+1}.`)}).add([73,0,0],(t,a)=>{let r=t[0];t.subarray(1).forEach((i,s)=>{let o=r+s;o==8?console.debug(`MU1000 set LCD contrast to ${i}.`):o>9&&o<16&&[()=>{e.dispatchEvent("channelactive",i)},()=>{i<8?(e.dispatchEvent("channelmin",i<<4),console.info(`Octavia System: Minimum CH${(i<<4)+1}`)):(e.dispatchEvent("channelreset"),console.info("Octavia System: Clear channel ranges"))},()=>{i<8?(e.dispatchEvent("channelmax",(i<<4)+15),console.info(`Octavia System: Maximum CH${(i<<4)+16}`)):(e.dispatchEvent("channelreset"),console.info("Octavia System: Clear channel ranges"))},()=>{e.dispatchEvent("channelreset"),console.info("Octavia System: Clear channel ranges")},()=>{e.#S=!!i,console.info(`Octavia System: RS receiving ${["dis","en"][i]}abled.`)}][o-10]()})}).add([73,10,0],(t,a)=>{let r=t[0],i=`MU1000 RS${e.#S?"":" (ignored)"}: `;if(r<16)switch(r){case 2:{let s=e.chRedir(0,a,!0);e.#S&&(e.dispatchEvent("channelmin",s),e.dispatchEvent("channelmax",s+63)),console.info(`${i}Show CH1~64`);break}case 3:{let s=e.chRedir(t[1]<<5,a,!0);e.#S&&e.dispatchEvent("channelmin",s),e.#S&&e.dispatchEvent("channelmax",s+31),console.info(`${i}Show CH${s+1}~CH${s+32}`);break}default:console.debug(`${i}unknown switch ${r} invoked.`)}else if(r<32){if(e.#S){let s=e.chRedir(r-16+(e.#W<<4),a,!0);e.dispatchEvent("channelactive",s)}}else if(r<36){let s=e.chRedir(r-32<<4,a,!0);e.#S&&(e.dispatchEvent("channelmin",s),e.dispatchEvent("channelmax",s+15),e.#W=r-32),console.info(`${i}Show CH${s+1}~CH${s+16}`)}}).add([93,3],(t,a)=>{let r=e.chRedir(t[0],a,!0),i=`PLG-100SG CH${r+1} `,s=Date.now();if(t[1]==0){let o="",c=0;t.subarray(2).forEach((h,b)=>{b%2==0?o+=Y[h]||h.toString().padStart("0"):c+=h*13}),s>=e.#Y&&e.#a.unshift("SG Lyric: "),e.#a[0]+=`${W(o)}`,e.#Y=s+Math.ceil(c/2)+e.#Q,k()&&console.debug(`${i}vocals: ${o}`)}else console.warn(`Unknown PLG-100SG data: ${t}`)}),this.#y.add([76,48],t=>{}).add([76,49],t=>{}).add([76,50],t=>{}).add([76,51],t=>{}),this.#y.add([89,0],(t,a,r)=>{if(e.eprom){let i=t[0],s=(t[1]<<14)+(t[2]<<7)+t[3]+(e.eprom.offset||0);k()&&console.debug(`MU1000 EPROM trail to 0x${s.toString(16).padStart(6,"0")}, ${i} bytes.`);let o=e.eprom.data;t.subarray(4).forEach((c,h)=>{let b=h>>3,p=h&7;if(p==7)for(let $=0;$<7;$++)o[s+7*b+$]+=(c>>6-$&1)<<7;else o[s+7*b+p]=c})}}).add([89,1],(t,a,r)=>{let i=(t[0]<<21)+(t[1]<<14)+(t[2]<<7)+t[3];k()&&console.debug(`MU1000 EPROM jump to 0x${i.toString(16).padStart(6,"0")}.`),e.eprom&&(e.eprom.offset=i)}).add([89,2],(t,a,r)=>{if(e.eprom){let i=(t[0]<<21)+(t[1]<<14)+(t[2]<<7)+t[3]+(e.eprom.offset||0);k()&&console.debug(`MU1000 EPROM write to 0x${i.toString(16).padStart(6,"0")}.`);let s=e.eprom.data;t.subarray(4).forEach((o,c)=>{let h=c>>3,b=c&7;if(b==7)for(let p=0;p<7;p++)s[i+7*h+p]+=(o>>6-p&1)<<7;else s[i+7*h+b]=o})}}).add([89,3],(t,a,r)=>{}),this.#y.add([39,48],(t,a,r)=>{}).add([43,0,0],(t,a,r)=>{let i=[0,0,0,0],s=(o,c)=>{i[c]=o};if(t.subarray(1).forEach((o,c)=>{let h=c+t[0];[s,s,s,s,()=>{this.#b=o*129/16383*100},()=>o-64,()=>o||128,()=>o,()=>o,()=>{console.debug(`TG300 variation on cc${o}.`)}][h](o,h)}),t[0]<4){let o=0;i.forEach(c=>{o=o<<4,o+=c}),o-=1024}}).add([43,1,0],(t,a,r)=>{}).add([43,2],(t,a,r)=>{let i=e.chRedir(t[0],a,!0),s=t[1],o=u.cc*i,c=`TG300 CH${i+1} `;t.subarray(2).forEach((h,b)=>{b<5?([()=>{},()=>{e.#e[o+d[0]]=h},()=>{e.#e[o+d[32]]=h},()=>{e.#r[i]=h},()=>{let p=e.chRedir(h,a,!0);e.#f[i]=p,i!=p&&(e.buildRchTree(),console.info(`${c}receives from CH${p+1}`))}][b+s]||(()=>{}))(h,b+s):b<21||(b<47?([()=>{e.#w[i]=+!h},()=>{},()=>{},()=>{e.#s[u.rpn*i+3]=h},()=>{},()=>{e.#e[o+d[7]]=h},!1,!1,()=>{e.#e[o+d[10]]=h||128},!1,!1,()=>{console.debug(`${c} AC1 at cc${h}`)},()=>{console.debug(`${c} AC2 at cc${h}`)},()=>{e.#e[o+d[128]]=h},()=>{e.#e[o+d[93]]=h},()=>{e.#e[o+d[91]]=h},()=>{e.#e[o+d[94]]=h},()=>{e.#e[o+d[76]]=h},()=>{e.#e[o+d[77]]=h},()=>{e.#e[o+d[74]]=h},()=>{e.#e[o+d[71]]=h},()=>{e.#e[o+d[73]]=h},()=>{e.#e[o+d[75]]=h},()=>{e.#e[o+d[72]]=h},()=>{e.#e[o+d[78]]=h}][b+s-21]||(()=>{}))(h,b+s):b<95||([()=>{e.#e[o+d[65]]=h},()=>{e.#e[o+d[5]]=h}][b+s-95]||(()=>{}))(h,b+s))})}).add([43,7,0],(t,a,r)=>{let i=t[0];e.setLetterDisplay(t.subarray(1),"TG300 letter display",i)}).add([43,7,1],(t,a,r)=>{e.#p=0,e.#m=Date.now()+3200,e.#$.fill(0),t.forEach(function(i,s){let o=Math.floor(s/16),c=s%16,h=(c*3+o)*7,b=7,p=0;for(h-=c*5,o==2&&(b=2);p>6-p&1,p++})}),this.#T.add([66,18,0,0,127],(t,a,r)=>{e.switchMode("gs",!0),e.#e[u.cc*9]=120,e.#e[u.cc*25]=120,e.#e[u.cc*41]=120,e.#e[u.cc*57]=120,e.#k=3,e.#n=!1,e.#D.fill(0),console.info(`GS system to ${["single","dual"][t[0]]} mode.`)}).add([66,18,64,0],(t,a,r)=>{switch(t[0]){case 127:{e.switchMode("gs",!0),e.#e[u.cc*9]=120,e.#e[u.cc*25]=120,e.#e[u.cc*41]=120,e.#e[u.cc*57]=120,e.#n=!1,e.#D.fill(0),console.info("MIDI reset: GS");break}default:{let i=[0,0,0,0],s=(o,c)=>{i[c]=o};if(t.subarray(1).forEach((o,c)=>{let h=c+t[0];[s,s,s,s,b=>{this.#b=b*129/16383*100},b=>{},b=>{}][h](o,c)}),t[0]<4){let o=0;i.forEach(c=>{o=o<<4,o+=c}),o-=1024}}}}).add([66,18,64,1],t=>{let a=t[0];if(a<16){let r="".padStart(a," ");t.subarray(1).forEach((i,s)=>{r+=String.fromCharCode(Math.max(32,i))}),r=r.padEnd(16," "),console.debug(`GS patch name: ${r}`)}else a<48||(a<65?t.subarray(1).forEach((r,i)=>{let s=`GS ${a+i>55?"chorus":"reverb"} `;([()=>{console.info(`${s}type: ${L[r]}`),e.setEffectType(0,40,r)},()=>{},()=>{},()=>{},()=>{},()=>{},!1,()=>{console.debug(`${s}predelay: ${r}ms`)},()=>{console.info(`${s}type: ${Z[r]}`),e.setEffectType(1,40,16+r)},()=>{},()=>{},()=>{},()=>{},()=>{},()=>{},()=>{console.debug(`${s}to reverb: ${E(r)}`)},()=>{console.debug(`${s}to delay: ${E(r)}`)}][a+i-48]||(()=>{}))()}):a<80?console.debug(`Unknown GS patch address: ${a}`):a<91?t.subarray(1).forEach((r,i)=>{let s="GS delay ";([()=>{console.info(`${s}type: ${j[r]}`),e.setEffectType(2,40,32+r)},()=>{},()=>{},()=>{},()=>{},()=>{},()=>{},()=>{},()=>{},()=>{},()=>{console.debug(`${s}to reverb: ${E(r)}`)}][a+i-80]||(()=>{}))()}):console.debug(`Unknown GS patch address: ${a}`))}).add([66,18,64,2],t=>{let a="GS EQ ";t.subarray(1).forEach((r,i)=>{([()=>{console.debug(`${a}low freq: ${[200,400][r]}Hz`)},()=>{console.debug(`${a}low gain: ${r-64}dB`)},()=>{console.debug(`${a}high freq: ${[3e3,6e3][r]}Hz`)},()=>{console.debug(`${a}high gain: ${r-64}dB`)}][t[0]+i]||function(){console.warn(`Unknown GS EQ address: ${t[0]+i}`)})()})}).add([66,18,64,3],t=>{let a="GS EFX ",r=function(i,s){let o=ee(e.#g.subarray(10,12),s,i);o&&console.debug(`${a}${B(e.#g.subarray(10,12))} ${o}`)};t.subarray(1).forEach((i,s)=>{([()=>{e.setEffectTypeRaw(3,!1,32+i)},()=>{e.setEffectTypeRaw(3,!0,i),console.info(`${a}type: ${B(e.#g.subarray(10,12))}`)},!1,r,r,r,r,r,r,r,r,r,r,r,r,r,r,r,r,r,r,r,r,()=>{console.debug(`${a}to reverb: ${E(i)}dB`)},()=>{console.debug(`${a}to chorus: ${E(i)}dB`)},()=>{console.debug(`${a}to delay: ${E(i)}dB`)},!1,()=>{console.debug(`${a}1 source: ${i}`),i&&i<96&&e.allocateAce(i)},()=>{console.debug(`${a}1 depth: ${i-64}`)},()=>{console.debug(`${a}2 source: ${i}`),i&&i<96&&e.allocateAce(i)},()=>{console.debug(`${a}2 depth: ${i-64}`)},()=>{console.debug(`${a}to EQ: ${i?"ON":"OFF"}`)}][t[0]+s]||function(o,c){console.warn(`Unknown GS EFX address: ${c}`)})(i,t[0]+s)})}).add([66,18,65],t=>{}).add([69,18,16],t=>{switch(t[0]){case 0:{let a=t[1];e.setLetterDisplay(t.subarray(2),"GS display text",a);break}case 32:{e.#m=Date.now()+3200,t[1]==0&&(e.#p=Math.max(Math.min(t[2]-1,9),0));break}default:if(t[0]<11){e.#p>9&&(e.#p=0),e.#m=Date.now()+3200,e.#v[t[0]-1]?.length||(e.#v[t[0]-1]=new Uint8Array(256));let a=e.#v[t[0]-1],r=t[1];a.fill(0);let i=t.subarray(2);for(let s=0;s>4-$&1,$++})}else console.warn(`Unknown GS display section: ${t[0]}`)}});let l=function(t,a,r){let i=t[0],s=u.cc*a,o=u.rpn*a,c=`GS CH${a+1} `;i<3?t.subarray(1).forEach((h,b)=>{[()=>{e.#e[s+d[0]]=h},()=>{e.#r[a]=h},()=>{let p=e.chRedir(h,r,!0);e.#f[a]=p,a!=p&&(e.buildRchTree(),console.info(`${c}receives from CH${p+1}`))}][i+b]()}):i<19||(i<44?t.subarray(1).forEach((h,b)=>{([()=>{e.#w[a]=+!h},!1,()=>{e.setChType(a,h<<1,g.gs),console.debug(`${c}type: ${h?"drum ":"melodic"}${h||""}`)},()=>{e.#s[o+3]=h},!1,()=>{e.#e[s+d[7]]=h},!1,!1,()=>{e.#e[s+d[10]]=h||128},!1,!1,()=>{console.debug(`${c}CC 1: cc${h}`)},()=>{console.debug(`${c}CC 2: cc${h}`)},()=>{e.#e[s+d[93]]=h},()=>{e.#e[s+d[91]]=h},!1,!1,()=>{e.#s[o+1]=h},()=>{e.#s[o+2]=h},()=>{e.#e[s+d[94]]=h}][i+b-19]||(()=>{}))()}):i<76||console.debug(`Unknown GS part address: ${i}`))},f=function(t,a){let r=t[0],i=`GS CH${a+1} `;r<2?t.subarray(1).forEach((s,o)=>{[()=>{e.#e[u.cc*a+d[32]]=s},()=>{}][r+o]()}):r<32?console.warn(`Unknown GS misc address: ${r}`):r<35?t.subarray(1).forEach((s,o)=>{[()=>{console.debug(`${i}EQ: o${["ff","n"][s]}`)},()=>{},()=>{console.debug(`${i}EFX: o${["ff","n"][s]}`)}][r+o-32]()}):console.warn(`Unknown GS misc address: ${r}`)};this.#T.add([66,18,64,16],(t,a)=>{l(t,e.chRedir(9,a,!0),a)}).add([66,18,64,17],(t,a)=>{l(t,e.chRedir(0,a,!0),a)}).add([66,18,64,18],(t,a)=>{l(t,e.chRedir(1,a,!0),a)}).add([66,18,64,19],(t,a)=>{l(t,e.chRedir(2,a,!0),a)}).add([66,18,64,20],(t,a)=>{l(t,e.chRedir(3,a,!0),a)}).add([66,18,64,21],(t,a)=>{l(t,e.chRedir(4,a,!0),a)}).add([66,18,64,22],(t,a)=>{l(t,e.chRedir(5,a,!0),a)}).add([66,18,64,23],(t,a)=>{l(t,e.chRedir(6,a,!0),a)}).add([66,18,64,24],(t,a)=>{l(t,e.chRedir(7,a,!0),a)}).add([66,18,64,25],(t,a)=>{l(t,e.chRedir(8,a,!0),a)}).add([66,18,64,26],(t,a)=>{l(t,e.chRedir(10,a,!0),a)}).add([66,18,64,27],(t,a)=>{l(t,e.chRedir(11,a,!0),a)}).add([66,18,64,28],(t,a)=>{l(t,e.chRedir(12,a,!0),a)}).add([66,18,64,29],(t,a)=>{l(t,e.chRedir(13,a,!0),a)}).add([66,18,64,30],(t,a)=>{l(t,e.chRedir(14,a,!0),a)}).add([66,18,64,31],(t,a)=>{l(t,e.chRedir(15,a,!0),a)}).add([66,18,64,64],(t,a)=>{f(t,e.chRedir(9,a,!0))}).add([66,18,64,65],(t,a)=>{f(t,e.chRedir(0,a,!0))}).add([66,18,64,66],(t,a)=>{f(t,e.chRedir(1,a,!0))}).add([66,18,64,67],(t,a)=>{f(t,e.chRedir(2,a,!0))}).add([66,18,64,68],(t,a)=>{f(t,e.chRedir(3,a,!0))}).add([66,18,64,69],(t,a)=>{f(t,e.chRedir(4,a,!0))}).add([66,18,64,70],(t,a)=>{f(t,e.chRedir(5,a,!0))}).add([66,18,64,71],(t,a)=>{f(t,e.chRedir(6,a,!0))}).add([66,18,64,72],(t,a)=>{f(t,e.chRedir(7,a,!0))}).add([66,18,64,73],(t,a)=>{f(t,e.chRedir(8,a,!0))}).add([66,18,64,74],(t,a)=>{f(t,e.chRedir(10,a,!0))}).add([66,18,64,75],(t,a)=>{f(t,e.chRedir(11,a,!0))}).add([66,18,64,76],(t,a)=>{f(t,e.chRedir(12,a,!0))}).add([66,18,64,77],(t,a)=>{f(t,e.chRedir(13,a,!0))}).add([66,18,64,78],(t,a)=>{f(t,e.chRedir(14,a,!0))}).add([66,18,64,79],(t,a)=>{f(t,e.chRedir(15,a,!0))}),this.#U.add([54,65],(t,a)=>{e.switchMode("x5d");let r=(t[1]<<7)+t[0],i=(t[3]<<7)+t[2],s=e.chRedir(r&15,a,!0),o=u.cc*s;[()=>{i<1||(i<101?(e.setChType(s,e.CH_MELODIC,g.x5d),e.#r[s]=i-1,e.#e[o+d[0]]=82):i<229?(e.setChType(s,e.CH_MELODIC,g.x5d),e.#r[s]=i-101,e.#e[o+d[0]]=56):(e.setChType(s,e.CH_DRUMS,g.x5d),e.#r[s]=ne[i-229]||0,e.#e[o+d[0]]=62))},()=>{e.#e[o+d[7]]=i},()=>{i<31&&(e.#e[o+d[10]]=Math.round((i-15)*4.2+64))},()=>{e.#e[o+d[93]]=D(i)},()=>{e.#e[o+d[91]]=D(i)},()=>{e.#s[s*u.rpn+3]=i>8191?i-16320:64+i},()=>{e.#s[s*u.rpn+1]=i>8191?i-16320:64+i},()=>{i>0&&(e.#s[s*u.rpn]=i)},()=>{}][r>>4]()}).add([54,76,0],(t,a)=>{e.switchMode("x5d",!0);let r="",i=82,s=0,o=0,c="MSB PRG LSB NME";m(t,function(h,b){if(b<16400){let p=b%164;switch(!0){case p<10:{h>31&&(r+=String.fromCharCode(h));break}case p==11:{c+=`
+${i} ${s} ${o} ${r.trim().replace("Init Voice","")}`,s++,r="";break}}s>99&&(i=90,s=0)}}),e.userBank.clearRange({msb:82,prg:[0,99],lsb:0}),e.userBank.load(c)}).add([54,77,0],(t,a)=>{e.switchMode("x5d",!0);let r="",i=90,s=0,o=0,c="MSB PRG LSB NME";m(t,function(h,b){if(b<13600){let p=b%136;switch(!0){case p<10:{h>31&&(r+=String.fromCharCode(h));break}case p==11:{c+=`
+${i} ${s} ${o} ${r.trim().replace("Init Combi","")}`,s++,r="";break}}}}),e.userBank.clearRange({msb:90,prg:[0,99],lsb:0}),e.userBank.load(c)}).add([54,78],(t,a)=>{e.switchMode("x5d",!0),console.debug(`X5D mode switch requested: ${["combi","combi edit","prog","prog edit","multi","global"][t[0]]} mode.`)}).add([54,85],(t,a)=>{e.switchMode("x5d",!0),m(t,(r,i)=>{i>0&&i<3&&e.setEffectType(i-1,44,r)})}).add([54,104],(t,a)=>{e.switchMode("x5d",!0),m(t,function(r,i,s,o){if(i<192){let c=e.chRedir(Math.floor(i/12),a,!0),h=c*u.cc;switch(i%12){case 0:{r<128?(e.setChType(c,e.CH_MELODIC,g.x5d),e.#e[h+d[0]]=82,e.#r[c]=r):(e.setChType(c,e.CH_DRUMS,g.x5d),e.#e[h+d[0]]=62,e.#r[c]=ne[r-128]),r>0&&(e.#l[c]=1);break}case 1:{e.#e[h+d[7]]=r;break}case 2:{e.#s[c*u.rpn+3]=r>127?r-192:64+r;break}case 3:{e.#s[c*u.rpn+1]=r>127?r-192:64+r;break}case 4:{r<31&&(e.#e[h+d[10]]=Math.round((r-15)*4.2+64));break}case 5:{let b=r>>4,p=r&15;e.#e[h+d[91]]=D(p),e.#e[h+d[93]]=D(b);break}case 10:break;case 11:{let b=e.chRedir(r&15,a,!0),p=r>>4;e.#f[c]=r,(b!=c||p)&&(console.info(`X5D Part CH${c+1} receives from CH${b+1}.`),e.buildRchTree())}}}else{let c=e.chRedir(i-192,a,!0)}})}),this.#T.add([22,18,127],t=>{e.switchMode("mt32",!0),e.#n=!1,e.userBank.clearRange({msb:0,lsb:127,prg:[0,127]}),console.info("MIDI reset: MT-32")}).add([22,18,0],(t,a,r)=>{e.switchMode("mt32");let i=e.chRedir(r,a,!0),s=t[1];t.subarray(2).forEach((o,c)=>{let h=c+s;e.#A[h+(i-1)*16]=o,([!1,()=>{let b=e.#A[i-1<<4];if(b<3)if(e.#C[i]=1,b==2)for(let p=0;p{e.#s[i*u.rpn+3]=o+40},()=>{e.#s[i*u.rpn+1]=o+14},()=>{e.#s[i*u.rpn]=o},!1,()=>{e.#e[u.cc*i+d[91]]=o?127:0},!1,()=>{e.#e[u.cc*i+d[7]]=o},()=>{e.#e[u.cc*i+d[10]]=Math.ceil(o*9.05)}][h]||(()=>{}))()})}).add([22,18,1],(t,a,r)=>{e.switchMode("mt32");let i=e.chRedir(r,a,!0)}).add([22,18,2],(t,a,r)=>{e.switchMode("mt32");let i=e.chRedir(r,a,!0),s=t[1]+(t[0]<<7);s<10&&(e.#C[i]=1),t.subarray(2).forEach((o,c)=>{let h=c+s;h<14&&(e.#E[(i-1)*u.cmt+h]=o)})}).add([22,18,3],(t,a,r)=>{if(e.switchMode("mt32"),t[0]){let i=t[1]-16}else{let i=t[1];t.subarray(2).forEach((s,o)=>{let c=o+i;e.#A[c]=s;let h=e.chRedir(1+c>>4,a,!0),b=c&15;([!1,()=>{let p=e.#A[h-1<<4];if(p<3)if(e.#C[h]=1,p==2)for(let $=0;${e.#s[h*u.rpn+3]=s+40},()=>{e.#s[h*u.rpn+1]=s+14},()=>{e.#s[h*u.rpn]=s},!1,()=>{e.#e[u.cc*h+d[91]]=s?127:0},!1,()=>{e.#e[u.cc*h+d[7]]=s},()=>{e.#e[u.cc*h+d[10]]=Math.ceil(s*9.05)}][b]||(()=>{}))()})}}).add([22,18,4],(t,a,r)=>{e.switchMode("mt32");let i=t[1]+(t[0]<<7);t.subarray(2).forEach((s,o)=>{let c=o+i,h=e.chRedir(Math.floor(c/246+1),a,!0),b=c%246;b<14&&(e.#E[(h-1)*u.cmt+b]=s),b<10&&(e.#C[h]=1)})}).add([22,18,5],(t,a,r)=>{e.switchMode("mt32");let i=(t[0]<<7)+t[1];t.subarray(2).forEach((s,o)=>{let c=i+o,h=Math.floor(c/8),b=c&7,p=h*8;e.#q[c]=s,([!1,()=>{let $=e.#q[p];if($<3){let y="";if($==2){let w=u.cmt*h;y=`MT-m:${s.toString().padStart(3,"0")}`}else y=e.baseBank.get(0,s+($<<6),127,"mt32").name;e.userBank.clearRange({msb:0,lsb:127,prg:h}),e.userBank.load(`MSB LSB PRG NME
+000 127 ${h} ${y}`,!0)}}][b]||(()=>{}))()})}).add([22,18,8],(t,a,r)=>{e.switchMode("mt32");let i=((t[0]&1)<<7)+t[1];t.subarray(2).forEach((s,o)=>{let c=i+o;c>1)*u.cmt+c]=s)})}).add([22,18,16],(t,a,r)=>{e.switchMode("mt32");let i=t[1],s=!1,o=function(c,h){e.#f[h-12]=c,s=!0};t.subarray(2).forEach((c,h)=>{let b=h+i;([!1,!1,!1,!1,!1,!1,!1,!1,!1,!1,!1,!1,!1,o,o,o,o,o,o,o,o,o,()=>{e.#b=c}][b]||(()=>{}))(c,h)}),s&&e.buildRchTree()}).add([22,18,32],t=>{e.switchMode("mt32");let a=t[1],r=" ".repeat(a);t.subarray(2).forEach(i=>{i>31&&(r+=String.fromCharCode(i))}),e.#M=r.padStart(20," "),e.#G=Date.now()+3200}).add([22,18,82],(t,a)=>{let r=e.chRedir(0,a,!0);for(let i=0;i<16;i++)e.#h.ano(r+i),i&&i<10&&(e.#r[r+i]=_[i-1]);console.info("MT-32 alt reset complete.")}),this.#U.add([66,0],(t,a)=>{e.switchMode("ns5r",!0),e.#n=!1,console.debug(`NS5R mode switch requested: ${["global","multi","prog edit","comb edit","drum edit","effect edit"][t[0]]} mode.`)}).add([66,1],(t,a)=>{e.switchMode(["ns5r","05rw"][t[0]],!0),e.#n=!1}).add([66,18,0,0],(t,a)=>{let r=t[0];switch(r){case 124:case 126:case 127:{e.switchMode("ns5r",!0),e.#n=!1;break}case 125:{console.info(`NS5R drum setup reset: ${t}`);break}default:if(r<10){let i=[0,0,0,0],s=(o,c)=>{i[c]=o};if(t.subarray(1).forEach((o,c)=>{[s,s,s,s,()=>{e.#b=o*129/16383*100},()=>o-64,()=>o-64,()=>{},()=>{},()=>{}][r+c]()}),t[0]<4){let o=0;i.forEach(c=>{o=o<<4,o+=c}),o-=1024}}}}).add([66,18,0,1],(t,a)=>{}).add([66,18,0,2],(t,a)=>{}).add([66,18,1],(t,a)=>{let r=e.chRedir(t[0],a,!0),i=r*u.cc,s=t[1],o=`NS5R CH${r+1} `;t.subarray(2).forEach((c,h)=>{let b=s+h;b<3?[()=>{e.#e[i+d[0]]=c||121},()=>{e.#e[i+d[32]]=c},()=>{e.#r[r]=c}][b]():b<8||(b<14?[()=>{let p=e.chRedir(c,a,!0);e.#f[r]=p,r!=p&&(e.buildRchTree(),console.info(`${o}receives from CH${p+1}`))},()=>{e.#w[r]=+!c},()=>{e.setChType(r,c,g.ns5r),console.debug(`${o}type: ${O[c]}`)},()=>{e.#s[u.rpn*r+3]=c},()=>{},()=>{}][b-8]():b<16||(b<33?[()=>{e.#e[i+d[7]]=c},()=>{e.#e[i+d[11]]=c},()=>{},()=>{},()=>{e.#e[i+d[10]]=c||128},()=>{},()=>{},()=>{e.#e[i+d[93]]=c},()=>{e.#e[i+d[91]]=c},()=>{e.#e[i+d[76]]=c},()=>{e.#e[i+d[77]]=c},()=>{e.#e[i+d[78]]=c},()=>{e.#e[i+d[74]]=c},()=>{e.#e[i+d[71]]=c},()=>{e.#e[i+d[73]]=c},()=>{e.#e[i+d[75]]=c},()=>{e.#e[i+d[72]]=c}][b-16]():b<112||b<114&&[()=>{e.#e[i+d[5]]=c},()=>{e.#e[i+d[65]]=c}][b-112]()))})}).add([66,18,8,0],(t,a)=>{let r=t[0];if(r<32)e.setLetterDisplay(t.subarray(1,33),"NS5R letter display");else{let i=r-32;e.#m=Date.now()+3200,e.#p=10,e.#$.fill(0);let s=t.subarray(1),o=4;s.forEach(function(c,h){let b=h+i,p=b>>4,$=b&15;if(b<80){let y=p>3,w=0,M=p0;)e.#$[$*32+p*7+(M-w)]=y&1,y=y>>1,w++}})}}).add([66,52],(t,a)=>{e.switchMode("ns5r",!0),e.#n=!1;let r="";m(t,(i,s)=>{s<8?(i>31&&(r+=String.fromCharCode(i)),s==7&&(e.aiEfxName=r)):s<10&&e.setEffectType(s-8,44,i)})}).add([66,53],(t,a)=>{e.switchMode("ns5r",!0),e.#n=!1,m(t,function(r,i){switch(!0){case i<2944:{let s=e.chRedir(Math.floor(i/92),a,!0),o=s*u.cc;switch(i%92){case 0:{e.#e[o+d[0]]=r||121;break}case 1:{e.#e[o+d[32]]=r;break}case 2:{e.#r[s]=r,r>0&&(e.#l[s]=1);break}case 3:{let c=e.chRedir(r,a,!0);e.#f[s]=c,s!=c&&(console.info(`NS5R CH${s+1} receives from CH${c+1}.`),e.buildRchTree())}case 7:break;case 8:{e.#s[s*u.rpn+3]=r<40||r>88?r+(r>63?-192:64):r;break}case 9:case 10:{e.#e[o+d[7]]=r;break}case 11:{e.#e[o+d[11]]=r;break}case 14:{e.#e[o+d[10]]=r||128;break}case 19:{e.#e[o+d[93]]=r;break}case 20:{e.#e[o+d[91]]=r;break}case 84:{e.#e[o+d[65]]=r;break}case 85:{e.#e[o+d[5]]=r;break}}break}case i<3096:break;case i<3134:break;case i<8566:break}})}).add([66,54],(t,a)=>{e.switchMode("ns5r",!0);let r="",i=80,s=0,o=0,c="MSB PRG LSB NME";m(t,function(h,b){let p=b%158;switch(!0){case p<10:{h>31&&(r+=String.fromCharCode(h));break}case p==11:{i=h&127;break}case p==12:{o=h&127;break}case p==13:{c+=`
+${i} ${s} ${o} ${r.trim().replace("Init Voice","")}`,s++,r="";break}}}),e.userBank.clearRange({msb:80,lsb:0}),e.userBank.load(c)}).add([66,55],(t,a)=>{e.switchMode("ns5r",!0);let r="",i=88,s=0,o=0,c="MSB PRG LSB NME";m(t,function(h,b){let p=b%126;switch(!0){case p<10:{h>31&&(r+=String.fromCharCode(h));break}case p==11:break;case p==12:break;case p==13:{c+=`
+${i} ${s} ${o} ${r.trim().replace("Init Combi","")}`,s++,r="";break}}}),e.userBank.clearRange({msb:88,lsb:0}),e.userBank.load(c)}).add([66,125],t=>{e.dispatchEvent("backlight",["green","orange","red",!1,"yellow","blue","purple"][t[0]]||"white")}).add([66,127],t=>{let a=new Uint8Array(5760);m(t,(r,i,s)=>{if(i<720)for(let o=0;o<8;o++)a[i*8+o]=r>>7-o&1}),e.dispatchEvent("screen",{type:"ns5r",data:a})}).add([76],(t,a,r)=>{e.#U.run([66,...t],a,r)}),this.#F.add([16,0,8,0],(t,a,r)=>{let i=(t[2]<<4)+t[3],s="K11 ";([()=>{e.switchMode("k11",!0),e.#n=!1,e.#k=i?4:0,console.info("MIDI reset: GMega/K11")},()=>{console.debug(`${s}reverb type: ${i}`)},()=>{console.debug(`${s}reverb time: ${i}`)},()=>{console.debug(`${s}reverb time: ${i}`)},()=>{console.debug(`${s}reverb predelay: ${i}`)},()=>{console.debug(`${s}reverb predelay: ${i}`)},()=>{console.debug(`${s}depth high: ${i}`)},()=>{console.debug(`${s}depth high: ${i}`)},()=>{console.debug(`${s}depth low: ${i}`)},()=>{console.debug(`${s}depth low: ${i}`)}][t[0]]||(()=>{}))()}).add([16,0,8,1],(t,a,r)=>{let i=e.chRedir(t[1],a,!0),s=u.cc*i,o=u.rpn*i,c=(t[3]<<4)+t[4],h=`K11 CH${i+1} `;([()=>{c<128?(e.setChType(i,e.CH_MELODIC,g.k11),e.#e[s+d[0]]=0,e.#r[i]=c):(e.setChType(i,e.CH_DRUMS,g.k11),e.#r[i]=c-128)},()=>{let b=e.chRedir(c,a,!0);e.#f[i]=b,i!=b&&(e.buildRchTree(),console.info(`${h}receives from CH${b+1}`))},()=>{e.#e[s+d[7]]=c},()=>{e.#l[i]=c},()=>{e.#e[s+d[10]]=c},()=>{e.#s[o+3]=c+40},()=>{e.#s[o+1]=c>>1,e.#s[o+2]=c&1},()=>{e.#e[s+d[91]]=c?127:0},()=>{},()=>{e.#e[s+d[74]]=c},()=>{e.#e[s+d[73]]=c},()=>{e.#e[s+d[72]]=c}][t[0]]||(()=>{}))()}).add([16,0,9,0],(t,a,r)=>{let i=(t[2]<<4)+t[3],s="GMLX ";([()=>{console.debug(`${s}reverb type: ${i}`)},()=>{console.debug(`${s}reverb time: ${i}`)},()=>{console.debug(`${s}reverb predelay: ${i}`)},()=>{console.debug(`${s}depth high: ${i}`)},()=>{console.debug(`${s}depth low: ${i}`)}][t[0]]||(()=>{}))()}).add([16,0,9,3],(t,a,r)=>{let i=(t[2]<<4)+t[3],s=e.chRedir(t[1],a,!0),o=s*u.cc;[()=>{i<128?(e.setChType(s,e.CH_MELODIC,g.k11),e.#e[o+d[0]]=0,e.#e[o+d[32]]=0,e.#r[s]=i):i<160?(e.setChType(s,e.CH_MELODIC,g.k11),e.#e[o+d[0]]=0,e.#e[o+d[32]]=7,e.#r[s]=i-100):(e.setChType(s,e.CH_DRUMS,g.k11),e.#e[o+d[0]]=122,e.#e[o+d[32]]=0,e.#r[s]=i-160)},()=>{let c=e.chRedir(i,a,!0);e.#f[s]=c,s!=c&&(e.buildRchTree(),console.info(`GMLX CH${s+1} receives from CH${c+1}`))}][t[0]]()}).add([16,0,9,4],(t,a,r)=>{let i=(t[2]<<4)+t[3],s=e.chRedir(t[1],a,!0),o=s*u.cc,c=s*u.rpn,h=`GMLX CH${s+1} `;[()=>{e.#l[s]=i},()=>{e.#e[o+d[7]]=i},()=>{e.#e[o+d[10]]=i},()=>{e.#e[o+d[91]]=i?127:0},()=>{e.#s[c+3]=i+40},()=>{e.#s[c+1]=i},()=>{e.#s[c]=i},()=>{}][t[0]]()}),this.#K.add([66,93,64],(t,a,r)=>{let i=t[2];switch(t[0]){case 0:{switch(t[1]){case 4:{e.#b=i*129/16383*100;break}case 5:{i-64;break}case 6:{console.debug(`SG global reverb: ${i?"on":"off"}`);break}case 127:{e.switchMode("sg",!0);break}}break}case 1:{switch(t[1]){case 48:{console.debug(`SG reverb type: ${L[i]}`);break}}break}default:if(t[0]>>4==1){let s=e.chRedir(t[0]&15,a,!0);if(t[1]==2){let o=e.chRedir(i,a,!0);e.#f[s]=o,s!=o&&(e.buildRchTree(),console.info(`SG CH${s+1} receives from CH${o+1}`))}else t[1]==19&&(e.#e[u.cc*s+d[7]]=i)}else console.warn(`Unknown AKAI SG SysEx: ${t}`)}}),this.#V.add([9],(t,a,r)=>{console.debug(`GZ set effect: ${["stage reverb","hall reverb","room reverb","chorus","tremelo","phaser","rotary speaker","enhancer","flanger","EQ"][t[0]]||"off"}`)}),this.#y.add([127,0],(t,a,r)=>{e.switchMode("motif");let i=new Uint8Array([127,1,...t]);e.#y.run(i,a,r)}).add([127,1,0,0],(t,a,r)=>{e.switchMode("s90es");let i="S90/Motif ES system ",s=t[0];t.subarray(1).forEach((o,c)=>{([()=>{e.#b=o*12900/16383}][s+c]||(()=>{console.info(`Unrecognized ${i}ID: ${s+c}`)}))()})}).add([127,1,0,0,14],(t,a,r)=>{e.switchMode("s90es");let i="S90/Motif ES bulk header ",s=[];s[95]=(o,c,h)=>{console.debug(`${i}multi edit buffer: ${o[1]}`)},(s[t[0]]||(()=>{console.info(`Unrecognized ${i}ID: ${t[0]}.`)}))(t.subarray(1))}).add([127,1,0,0,15],(t,a,r)=>{e.switchMode("s90es");let i="S90/Motif ES bulk footer ",s=[];s[95]=(o,c,h)=>{console.debug(`${i}multi edit buffer: ${o[1]}`)},(s[t[0]]||(()=>{console.info(`Unrecognized ${i}ID: ${t[0]}.`)}))(t.subarray(1))}).add([127,1,0,58,55],(t,a,r)=>{e.switchMode("s90es");let i=e.chRedir(t[0],a,!0),s=u.cc*i,o=t[1],c=`S90/Motif ES bulk CH${i<16?i+1:"U"+(i-95)} `;console.debug(c,t),!(t[0]>15)&&t.subarray(2).forEach((h,b)=>{([()=>{e.#e[s+d[0]]=h},()=>{h&&(e.#l[i]=1),e.#e[s+d[32]]=h,e.#i[i]=+([32,40].indexOf(h)>-1)<<1},()=>{h&&(e.#l[i]=1),e.#r[i]=h},()=>{let p=e.chRedir(h,a,!0);e.#f[i]=p,i!=p&&(e.buildRchTree(),console.info(`${c}receives from CH${p+1}`))},()=>{e.#w[i]=h?0:1},!1,!1,!1,!1,!1,!1,!1,!1,()=>{e.#e[s+d[7]]=h},()=>{e.#e[s+d[10]]=h},!1,!1,!1,()=>{e.#e[s+d[91]]=h},()=>{e.#e[s+d[93]]=h},()=>{e.#e[s+d[94]]=h},()=>{e.#e[s+d[128]]=h},()=>{},()=>{e.#e[s+d[74]]=h},()=>{e.#e[s+d[71]]=h},!1,()=>{e.#e[s+d[65]]=h},()=>{e.#e[s+d[5]]=h},()=>{}][o+b]||(()=>{}))()})}).add([127,1,54,16],(t,a,r)=>{e.switchMode("s90es");let i=t[0];t.subarray(1).forEach((s,o)=>{let h=`S90/Motif ES EQ${(o>>2)+1} `;([()=>{let b=s-64},()=>{let b=T[s]},()=>{let b=s/10},()=>{let b=s}][i+o&3]||(()=>{}))()})})}};export{Ie as OctaviaDevice,u as allocated,d as ccToPos,oe as dnToPos};
diff --git a/dist/state_skim.mjs b/dist/state_skim.mjs
new file mode 100644
index 00000000..51762f5b
--- /dev/null
+++ b/dist/state_skim.mjs
@@ -0,0 +1,151 @@
+var U=function(e,t){let s=Math.min(e.length,t.length),i=e.slice(0,s),r=t.slice(0,s),n=0,a=0;for(;a0){let i=this.pool.length,r=1<=1&&a>=0;){if(a<=0)throw new Error("TTL reached.");if(n==i)n-=r;else{let c=U(t,this.pool[n]);switch(c){case 0:{a=0;break}case 1:{n+r<=i&&(n+=r);break}case-1:{n!=0&&(n-=r);break}default:console.warn(`Unexpected result ${c}.`)}}r=r>>1,a--}let l=!0;if(n>=this.pool.length)l=!1;else{let c=this;this.pool[n].forEach(function(u,f,b){l&&u!=t[f]&&(l=!1)}),!l&&U(t,this.pool[n])>0&&n++}return l||s?n:-1}else return s?0:-1},this.add=function(t,s){return t.data=s,this.pool.splice(this.point(t,!0),0,t),this},this.default=function(t){console.warn(`No match in "${this.name||"(unknown)"}" for "${t}". Default action not defined.`)},this.get=function(t){let s=this.point(t);if(s>-1)return this.pool[s].data;this.default(t)},this.run=function(t,...s){let i=this.point(t);i>-1?t.subarray?this.pool[i].data(t.subarray(this.pool[i].length),...s):this.pool[i].data(t.slice(this.pool[i].length),...s):this.default(t,...s)}};var T=class{#t={};addEventListener(e,t){this.#t[e]||(this.#t[e]=[]),this.#t[e].unshift(t)}removeEventListener(e,t){if(this.#t[e]){let s=this.#t[e].indexOf(t);s>-1&&this.#t[e].splice(s,1),this.#t[e].length<1&&delete this.#t[e]}}dispatchEvent(e,t){let s=new Event(e),i=this;s.data=t,this.#t[e]?.length>0&&this.#t[e].forEach(function(r){try{r?.call(i,s)}catch(n){console.error(n)}}),this[`on${e}`]&&this[`on${e}`](s)}};var P=class{#t={};context;set(e,t){this.#t[e]=t}has(e){return!!this.#t[e]}async read(e,t){if(!this.has(e))throw new Error(`No decoder registered for "${e}"`);return await this.#t[e].call(this.context||this,t)}};var K=function(e,t){let s=!0;return t.forEach((i,r)=>{s=s&&e[r]==i}),s},N=function(e){let t=0;return e.forEach(s=>{t*=256,t+=s}),t},M=new TextDecoder,G=new P;G.set("s7e",async function(e){let t=new Uint8Array(await e.slice(0,65536).arrayBuffer()),s="MSB LSB PRG NME",i=[0,0,0,0],r=32,n=0,a=0,l=!0,c=[],u=0;for(;l;){let f=t.subarray(n);([()=>{M.decode(f.subarray(0,4))=="YSFC"?(n+=80,a=1):n++},()=>{if(K(f.subarray(0,4),i))c.forEach((b,g,d)=>{let p=N(t.subarray(b.start+4,b.start+8));b.length=p}),a=2;else{let b=M.decode(f.subarray(0,4)),g=N(f.subarray(4,8));c.push({type:b,start:g}),n+=8}},()=>{let b=c[u],g=t.subarray(b.start,b.start+b.length),d=32;switch(b.type){case"ENVC":{let p=r;for(;p=c.length&&(a=3,l=!1)}][a]||(()=>{l=!1}))()}return s});var F=["off","hall","room","stage","plate","delay LCR","delay LR","echo","cross delay","early reflections","gate reverb","reverse gate"].concat(new Array(4),["white room","tunnel","canyon","basement","karaoke"],new Array(43),["pass through","chorus","celeste","flanger","symphonic","rotary speaker","tremelo","auto pan","phaser","distortion","overdrive","amplifier","3-band EQ","2-band EQ","auto wah"],new Array(1),["pitch change","harmonic","touch wah","compressor","noise gate","voice channel","2-way rotary speaker","ensemble detune","ambience"],new Array(4),["talking mod","Lo-Fi","dist + delay","comp + dist + delay","wah + dist + delay","V dist","dual rotor speaker"]);var X=",a,i,u,e,o,ka,ki,ku,ke,ko,ky,kw,sa,si,su,se,so,sh,ta,ti,tu,te,to,t,ch,t,s,na,ni,nu,ne,no,ny,nn,ha,hi,hu,he,ho,hy,fa,fi,fu,fe,fo,ma,mi,mu,me,mo,my,mm,ya,yu,ye,yo,ra,ri,ru,re,ro,ry,wa,wi,we,wo,ga,gi,gu,ge,go,gy,gw,za,zi,zu,ze,zo,ja,ji,ju,je,jo,jy,da,di,du,de,do,dy,ba,bi,bu,be,bo,by,va,vi,vu,ve,vo,pa,pi,pu,pe,po,py,nga,ngi,ngu,nge,ngo,ngy,ng,hha,hhi,hhu,hhe,hho,hhy,hhw,*,_,,,~,.".split(","),V={};`hi*,
+ka,か
+ki,き
+ku,く
+ke,け
+ko,こ
+ky,き!
+kw,くl
+tsu,つ
+ts,つl
+sa,さ
+si,すぃ
+su,す
+se,せ
+so,そ
+shi,し
+sh,し!
+ta,た
+ti,てぃ
+tu,とぅ
+te,て
+to,と
+tchy,ち!
+tchi,ち
+na,な
+ni,に
+nu,ぬ
+ne,ね
+no,の
+ny,に!
+nn,ん
+ha,は
+hi,ひ
+hu,ほぅ
+he,へ
+ho,ほ
+hy,ひ!
+fa,ふぁ
+fi,ふぃ
+fu,ふ
+fe,ふぇ
+fo,ふぉ
+ma,ま
+mi,み
+mu,む
+me,め
+mo,も
+my,み!
+mm,
+ra,ら
+ri,り
+ru,る
+re,れ
+ro,ろ
+ry,り!
+wa,わ
+wi,うぃ
+we,うぇ
+wo,を
+nga,ガ
+ngi,ギ
+ngu,グ
+nge,ゲ
+ngo,ゴ
+ngy,ギ!
+ng,
+ga,が
+gi,ぎ
+gu,ぐ
+ge,げ
+go,ご
+gy,ぎ!
+gw,ぐl
+za,ざ
+zi,ずぃ
+zu,ず
+ze,ぜ
+zo,ぞ
+ja,じゃ
+ji,じ
+ju,じゅ
+je,じぇ
+jo,じょ
+jy,じ!
+da,だ
+di,でぃ
+du,どぅ
+de,で
+do,ど
+dy,で!
+ba,ば
+bi,び
+bu,ぶ
+be,べ
+bo,ぼ
+by,び!
+va,ゔぁ
+vi,ゔぃ
+vu,ゔ
+ve,ゔぇ
+vo,ゔぉ
+pa,ぱ
+pi,ぴ
+pu,ぷ
+pe,ペ
+po,ぽ
+py,ぴ!
+!ya,ゃ
+!yu,ゅ
+!ye,ぇ
+!yo,ょ
+ya,や
+yu,ゆ
+ye,いぇ
+yo,よ
+!a,ゃ
+!u,ゅ
+!e,ぇ
+!o,ょ
+!a,ゃ
+!u,ゅ
+!e,ぇ
+!o,ょ
+la,ぁ
+li,ぃ
+lu,ぅ
+le,ぇ
+lo,ぉ
+a,あ
+i,い
+u,う
+e,え
+o,お
+*,っ
+~,
+^,
+_,`.split(`
+`).forEach(e=>{let t=e.split(",");V[t[0]]=t[1]});var z=["?","gm","gs","xg","g2","mt32","ns5r","ag10","x5d","05rw","k11","sg","krs","s90es","motif"];var R=[20,21,22,23,24,25,26,28,29,30,31,36,37,64,65],v=[0,1,2,4,5,6,7,8,10,11,32,38,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,84,91,92,93,94,95,98,99,100,101,128,12,13,16,17,18,19];var q={};z.forEach((e,t)=>{q[e]=t});var Q={length:v.length};v.forEach((e,t)=>{Q[e]=t});var Y={length:R.length};R.forEach((e,t)=>{Y[e]=t});var Ge={ch:128,cc:v.length,nn:128,pl:512,tr:256,cmt:14,rpn:6,ace:8,drm:8,dpn:R.length,dnc:128,efx:7};var W=["MSB","PRG","LSB"],O=function(e){let t=Math.floor(e/10),s=e%10;return`${t.toString(16)}${s}`},x=class{#t;strictMode=!1;get(e=0,t=0,s=0,i){let r=[e,t,s],n,a=Array.from(arguments);switch(i){case"xg":{e==32?a[2]+=4:e==33||e==35||e==36?a[2]+=5:e==79?a[0]=95:e==80?a[0]=96:e==81?a[0]=97:e==82?a[0]=98:e==83?a[0]=99:e==84&&(a[0]=100);break}case"gs":{e==0&&s<5?a[2]=0:e>125&&s<5&&s!=2&&(a[2]=e,a[0]=0);break}case"sg":{e==8&&s==0&&(a[2]=5);break}case"s90es":{s<8?a[2]+=17:s<32?a[2]+=13:a[2]=(a[2]>>3)+19;break}case"motif":{s<8?a[2]+=28:s<32?a[2]+=13:a[2]=(a[2]>>3)+19;break}}let l=" ",c="M",u=!1,f=0;switch(a[0]){case 0:{a[2]==127?c="MT-a":a[2]==126?c="MT-b":a[2]==7?c="GM-k":a[2]==5?c="SG-a":a[2]==4?c="SP-l":a[2]==0||i=="gs"&&a[2]<5?c="GM-a":(c="y",u=!0);break}case 8:{i=="sg"?c="GM-s":c="r:";break}case 48:{c=`yM${(a[2]>>3).toString().padStart(2,"0")}`,u=!0;break}case 56:{c="GM-b";break}case 61:case 120:{c="rDrm";break}case 62:{c="kDrm";break}case 63:{if(a[2]<17){let p=a[2];c=p<10?"kP:":"kC:",c+=p%10}else a[2]<34?c=["Pre1","Pre2","Pre3","Pre4","Usr1","Usr2","DrmP","DrmU","Plg1","Plg2","Plg3","Pre1","Pre2","Pre3","Pre4","Pre5","Pre6"][a[2]-17]:c="Ds";break}case 64:{c="ySFX";break}case 67:{c="DX:S";break}case 80:case 81:case 82:case 83:{c=`Prg${"UABC"[a[0]-80]}`;break}case 88:case 89:case 90:case 91:{c=`Cmb${"UABC"[a[0]-88]}`;break}case 95:{c=`${["DR","PC"][a[2]]}-d`;break}case 96:{c=a[2]==106?"AP-a":"PF",a[2]>63&&(f=63),u=!0;break}case 97:{c="VL:",u=!0,f=112;break}case 98:{c="SG-a";break}case 99:{c="DX",a[2]>63&&(f=63),u=!0;break}case 100:{c="AN",a[2]>63&&(f=63),u=!0;break}case 121:{c=`GM-${a[2]?"":"a"}`,u=!0;break}case 122:{c="lDrm";break}case 126:{c="yDrS";break}case 127:{a[2]==127?c="rDrm":c="yDrm";break}default:a[0]<48?c="r:":c="M"}c.length<4&&(c+=`${(u?s:e)-f}`.padStart(4-c.length,"0")),i=="xg"&&e==16&&(n=`Voice${(s*128+t+1).toString().padStart(3,"0")}`,l=" ");let b=[a[0],a[1],a[2]];for(;!(n?.length>=0);)n=this.#t[a[1]||0][(a[0]<<7)+a[2]],n||(this.strictMode?(n="",l="?"):this.#t[a[1]||0][a[0]<<7]?a[0]==0?(a[2]=0,l="^"):a[2]<1?(a[0]=0,l="*"):(a[2]--,l="^"):e==48?(a[0]=0,a[2]=0,l="!"):e==62?(a[1]--,l=" ",a[1]<1&&!n?.length&&(a[0]=0,l="!")):e<63?a[0]==0?(a[2]=0,l="^"):a[2]<1?(a[0]=0,l="*"):a[2]--:e==80?(n=`PrgU:${t.toString().padStart(3,"0")}`,l="!"):e==88?(n=`CmbU:${t.toString().padStart(3,"0")}`,l="!"):e==121?(n=`GM2Vox0${s}`,l="#"):e==122?(a[1]==32?a[1]==0:a[1]%=7,n=this.#t[a[1]||0][(a[0]<<7)+a[2]],n?l=" ":(n="",l="*")):a[1]==0?(n=`${e.toString().padStart(3,"0")} ${t.toString().padStart(3,"0")} ${s.toString().padStart(3,"0")}`,l="!"):a[0]==0?(a[2]=0,l="^"):a[2]>0?a[2]--:a[1]>0?(a[1]=0,l="!"):(a[0]=0,l="?"));let g=[a[0],a[1],a[2]];(i=="gs"||i=="ns5r")&&l=="^"&&(l=" "),e==127&&l=="^"&&(l=" "),l!=" "&&self.debugMode&&(n="");let d="??";switch(a[0]){case 0:{a[2]==0?d="GM":a[2]==5||a[2]==7?d="KG":a[2]<120?d="XG":a[2]==127&&(d="MT");break}case 48:{d="MU";break}case 56:{d="AG";break}case 61:case 80:case 83:case 88:case 89:case 91:{d="AI";break}case 62:case 82:case 90:{d="XD";break}case 63:{a[2]<17?d="KR":a[2]<34?d="ES":d="DS";break}case 64:case 126:{d="XG";break}case 67:case 99:{d="DX";break}case 81:{d="RW";break}case 95:{d=["DR","PC"][a[2]];break}case 96:{d=a[2]==106?"AP":"PF";break}case 97:{d="VL";break}case 98:{d="SG";break}case 100:{d="AN";break}case 120:{d="GS";break}case 121:{d=a[2]?"G2":"GM";break}case 122:{d="KG";break}case 127:{d=a[2]==127?"MT":t==0?"GM":"XG";break}default:a[0]<48&&(a[0]==16&&i=="xg"?d="XG":d="GS")}return{name:n||`${O(e||0)} ${O(t||0)} ${O(s||0)}`,iid:b,eid:g,sid:r,ending:l,sect:c,standard:d}}async load(e,t,s){let i=this,r=[],n=0,a=0;e.split(`
+`).forEach(function(l,c){let u=l.split(" "),f=[];c==0?u.forEach(function(b,g){r[W.indexOf(b)]=g}):u.forEach(async function(b,g){g>2?(i.#t[f[r[1]]]=i.#t[f[r[1]]]||[],(!i.#t[f[r[1]]][(f[r[0]]<<7)+f[r[2]]]?.length||t)&&(i.#t[f[r[1]]][(f[r[0]]<<7)+f[r[2]]]=u[3],n++),a++):f.push(parseInt(u[g]))})}),t||console.debug(`Map "${s||"(internal)"}": ${a} total, ${n} loaded.`)}clearRange(e){let t=e.prg!=null?e.prg.constructor==Array?e.prg:[e.prg,e.prg]:[0,127],s=e.msb!=null?e.msb.constructor==Array?e.msb:[e.msb,e.msb]:[0,127],i=e.lsb!=null?e.lsb.constructor==Array?e.lsb:[e.lsb,e.lsb]:[0,127];for(let r=s[0];r<=s[1];r++){let n=r<<7;for(let a=i[0];a<=i[1];a++){let l=n+a;for(let c=t[0];c<=t[1];c++)delete this.#t[c][l]}}}init(){this.#t=[];for(let e=0;e<128;e++)this.#t.push([""])}async loadFiles(...e){this.init();let t=this;e.forEach(async function(s,i){try{await fetch(`./data/bank/${s}.tsv`).then(function(r){return r.text()}).then(r=>{t.load(r,!1,s)})}catch{console.error(`Failed loading "${s}.tsv".`)}})}constructor(...e){this.loadFiles(...e)}};var m=["?","gm","gs","xg","g2","mt32","ns5r","ag10","x5d","05rw","krs","k11","sg"],B=[[0,0,0,0,121,0,0,56,82,81,63,0,0],[0,0,4,0,0,127,0,0,0,0,0,0,0]],S=[120,127,120,127,120,127,61,62,62,62,120,122,122],J=[0,3,81,84,88],I={8:"Off",9:"On",10:"Note aftertouch",11:"cc",12:"pc",13:"Channel aftertouch",14:"Pitch"},D={0:0,1:1,2:3,5:4},H=[[0,24],[0,127],[0,127],[40,88],[0,127],[0,127]],L=[36,37];var A=[0,1,2,4,5,6,7,8,10,11,32,38,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,84,91,92,93,94,95,98,99,100,101,12,13,16,17,18,19],Z=[33,99,100,32,102,8,9,10];var k={};m.forEach((e,t)=>{k[e]=t});var h={length:A.length};A.forEach((e,t)=>{h[e]=t});var E=function(){return!!self.Bun||self.debugMode||!1},j=function(e){let t=[],s=0;return e?.forEach(function(i,r){i==247?t.push(e.subarray(s,r)):i==240&&(s=r+1)}),t.length||t.push(e.subarray(0)),E(),t},_=function(e,t="",s="",i=2){return e?`${t}${e.toString().padStart(i,"0")}${s}`:""},o={ch:128,cc:A.length,nn:128,pl:512,tr:256,cmt:14,rpn:6},Ve=class extends T{#t=0;#m=0;#p=0;#g=new Array(11);get#h(){return this.#g[this.#m]}set#h(e){this.#g[this.#m]=e}#$=new Uint8Array(o.ch);#I=new Uint8Array(o.ch);#e=new Uint8ClampedArray(o.ch*o.cc);#y=new Uint8ClampedArray(o.ch);#l=new Uint8ClampedArray(o.ch*o.nn);#D=new Uint8Array(o.ch);#n=new Uint16Array(o.pl);#f=new Uint8Array(o.pl);#C=new Int16Array(o.ch);#d=new Uint8Array(o.ch);#x=0;#o=new Uint8Array(o.ch*o.rpn);#A=new Int8Array(o.ch*L.length);#U=new Uint8Array(o.ch);#X=new Uint8Array(128);#H=new Uint8Array(o.cmt*8);#V=new Uint8Array(1024);#L=new Uint8Array(o.cmt*64);#E=0;#u=0;#T=100;#w=0;#_=500;#z=0;#a="";#b=0;#q=0;#Q=!0;#i=!1;#K;#Y=new Uint8Array(2);#s=[];#k=new Uint8Array(o.ch);#S=new Uint8Array(o.tr);baseBank=new x("gm","gm2","xg","gs","ns5r","gmega","plg-150vl","plg-150pf","plg-150dx","plg-150an","plg-150dr","plg-100sg","kross");userBank=new x("gm");initOnReset=!1;chRedir(e,t,s){if(this.#S[t])return(this.#S[t]-1)*16+e;if([k.gs,k.ns5r].indexOf(this.#t)>-1){if(s==1)return e;let i=0,r=!0;for(;r;)this.#k[e+i]==0?(this.#k[e+i]=t,console.debug(`Assign track ${t} to channel ${e+i+1}.`),r=!1):this.#k[e+i]==t?r=!1:(i+=16,i>=128&&(i=0,r=!1));return e+i}else return e}#c=[];#R;#r={nOff:(e,t)=>{let s=e*128+t,i=this.#n.lastIndexOf(s);i>-1&&(this.#e[o.cc*e+h[64]]>63&&!this.config?.disableCc64?this.#f[i]=4:(this.#n[i]=0,this.#l[s]=0,this.#f[i]=0))},nOn:(e,t,s)=>{let i=e*128+t,r=0;for(this.#D[e]&&this.#r.ano(e);this.#f[r]>0&&this.#n[r]!=i;)r++;r{},cAt:(e,t)=>{},hoOf:e=>{this.#f.forEach((t,s)=>{if(t==4){let i=this.#n[s],r=i>>7;e==r&&(this.#f[s]=0,this.#n[s]=0,this.#l[i]=0)}})},soOf:e=>{},ano:e=>{this.#n.forEach((t,s,i)=>{let r=t>>7,n=t&127;t==0&&this.#l[0]==0||r==e&&this.#r.nOff(r,n)})}};#F={8:function(e){let t=e.channel,s=e.data[0];this.#r.nOff(t,s)},9:function(e){let t=e.channel;this.#$[t]=1;let s=e.data[0],i=e.data[1];i>0?this.#r.nOn(t,s,i):this.#r.nOff(t,s)},10:function(e){let s=e.channel*128+e.data[0];this.#n.indexOf(s)>-1&&(this.#l[s]=data[1])},11:function(e){let t=e.channel;this.#$[t]=1;let s=t*o.cc;switch(e.data[0]){case 96:return;case 97:return;case 120:return;case 121:{this.#r.ano(t),this.#C[t]=0;let i=t*o.cc;this.#e[i+h[1]]=0,this.#e[i+h[5]]=0,this.#e[i+h[64]]=0,this.#e[i+h[65]]=0,this.#e[i+h[66]]=0,this.#e[i+h[67]]=0,this.#e[i+h[11]]=127,this.#e[i+h[101]]=127,this.#e[i+h[100]]=127,this.#e[i+h[99]]=127,this.#e[i+h[98]]=127;return}case 123:{this.#r.ano(t);return}case 124:{this.#r.ano(t);return}case 125:{this.#r.ano(t);return}case 126:{this.#D[t]=1,this.#r.ano(t);return}case 127:{this.#D[t]=0,this.#r.ano(t);return}}if(h[e.data[0]]==null)console.warn(`cc${e.data[0]} is not accepted.`);else{switch(e.data[0]){case 0:{if(E()&&console.debug(`${m[this.#t]}, CH${t+1}: ${e.data[1]}`),this.#t==0)e.data[1]<48?(this.#e[s]>119&&(e.data[1]=this.#e[s],e.data[1]=120,console.debug(`Forced channel ${t+1} to stay drums.`)),e.data[1]>0&&(console.debug(`Roland GS detected with MSB: ${e.data[1]}`),this.switchMode("gs"))):e.data[1]==62?this.switchMode("x5d"):e.data[1]==63?this.switchMode("krs"):(e.data[1]==64||e.data[1]==127)&&this.switchMode("xg");else if(this.#t==k.gs)e.data[1]<56&&this.#e[s]>119&&(e.data[1]=this.#e[s],e.data[1]=120,console.debug(`Forced channel ${t+1} to stay drums.`));else if(this.#t==k.gm)e.data[1]<48?this.#e[s]>119&&(e.data[1]=120,this.switchMode("gs",!0),console.debug(`Forced channel ${t+1} to stay drums.`)):(e.data[1]==64||e.data[1]==127)&&this.switchMode("xg",!0);else if(this.#t==k.x5d){if(e.data[1]>0&&e.data[1]<8)this.switchMode("05rw",!0);else if(e.data[1]==56){let i=0;for(let r=0;r<16;r++){let n=this.#e[o.cc*r];(n==56||n==62)&&i++}i>14&&this.switchMode("ag10",!0)}}break}case 6:{if(this.#x){let i=this.#e[s+h[99]],r=this.#e[s+h[98]];if(i==1){let n=Z.indexOf(r);if(n>-1)this.#e[s+h[71+n]]=e.data[1],E()&&console.debug(`Redirected NRPN 1 ${r} to cc${71+n}.`);else{let a=L.indexOf(r);a>-1&&(this.#A[t*10+a]=e.data[1]-64),E()&&console.debug(`CH${t+1} voice NRPN ${r} commit`)}}}else{let i=D[this.#e[s+h[100]]];this.#e[s+h[101]]==0&&i!=null&&(E()&&console.debug(`CH${t+1} RPN 0 ${this.#e[s+h[100]]} commit: ${e.data[1]}`),e.data[1]=Math.min(Math.max(e.data[1],H[i][0]),H[i][1]),this.#o[t*o.rpn+i]=e.data[1])}break}case 38:{this.#x||this.#e[s+101]==0&&D[this.#e[s+100]]!=null&&(this.#o[t*o.rpn+D[this.#e[s+100]]+1]=e.data[1]);break}case 64:{e.data[1]<64&&this.#r.hoOf(t);break}case 66:{console.debug(`Sostenuto pedal: ${e.data[1]}`);break}case 98:case 99:{this.#x=1;break}case 100:case 101:{this.#x=0;break}}this.#e[s+h[e.data[0]]]=e.data[1]}},12:function(e){let t=e.channel;this.#$[t]=1,this.#y[t]=e.data,this.#U[t]=0,E()&&console.debug(`T:${e.track} C:${t} P:${e.data}`)},13:function(e){let t=this,s=e.channel;this.#n.forEach(function(i){let r=i>>7;s==r&&(t.#l[i]=e.data)})},14:function(e){let t=e.channel;this.#C[t]=e.data[1]*128+e.data[0]-8192},15:function(e){j(e.data).forEach(t=>{let s=t[0],i=t[1];(this.#W[s]||function(){console.debug(`Unknown manufacturer ${s}.`)})(i,t.subarray(2),e.track)})},248:function(e){},250:function(e){},251:function(e){},252:function(e){},254:function(e){},255:function(e){if((this.#c[e.meta]||function(s,i,r){}).call(this,e.data,e.track,e.meta),e.meta!=32&&(this.#w=0),J.indexOf(e.meta)>-1)return e.reply="meta",e;E()&&console.debug(e)}};#W={64:(e,t,s)=>{this.#G.run(t,s,e)},65:(e,t,s)=>{if(t[0]<16)this.#M.run(t,s,e),console.warn("Unknown device SysEx!");else{let i=t[t.length-1],r=gsChecksum(t.subarray(2,t.length-1));i==r?this.#M.run(t.subarray(0,t.length-1),s,e):console.warn(`Bad GS checksum ${i}. Should be ${r}.`)}},66:(e,t,s)=>{this.#O.run(t,s,e)},67:(e,t,s)=>{this.#v.run(t,s,e)},68:(e,t,s)=>{this.#J.run(t,s,e)},71:(e,t,s)=>{this.#B.run(t,s,e)},126:(e,t,s)=>{this.#P.run(t,s,e)},127:(e,t,s)=>{this.switchMode("gm"),this.#N.run(t,s,e)}};#P;#N;#v;#M;#O;#G;#B;#J;buildRchTree(){let e=[];this.#I.forEach((t,s)=>{e[t]?.constructor||(e[t]=[]),e[t].push(s)}),this.#K=e}getActive(){let e=this.#$.slice();return this.#t==k.mt32,e}getCc(e){let t=e*o.cc,s=this.#e.slice(t,t+o.cc);return s[h[0]]=s[h[0]]||this.#E,s[h[32]]=s[h[32]]||this.#u,s}getCcAll(){let e=this.#e.slice();for(let t=0;t0&&t.set(a,{v:s.#l[i],s:s.#f[r]})}),t}getBitmap(){return{bitmap:this.#h,expire:this.#p}}getLetter(){return{text:this.#a,expire:this.#b}}getMode(){return m[this.#t]}getMaster(){return{volume:this.#T}}getRawStrength(){let e=this;return this.#n.forEach(function(t){let s=Math.floor(t/128);e.#l[t]>e.#d[s]&&(e.#d[s]=e.#l[t])}),this.#d}getStrength(){let e=[],t=this;return this.getRawStrength().forEach(function(s,i){e[i]=Math.floor(s*t.#e[i*o.cc+h[7]]*t.#e[i*o.cc+h[11]]*t.#T/803288)}),e}getRpn(){return this.#o}getNrpn(){return this.#A}getVoice(e,t,s,i){let r=e||this.#E,n=t,a=s||this.#u;m[this.#t]=="ns5r"&&r>0&&r<56&&(a=3);let l=this.userBank.get(r,n,a,i);if(m[this.#t]=="mt32"&&l.name.indexOf("MT-m:")==0){let c=parseInt(l.name.slice(5)),u=c*o.cmt,f="";this.#L.subarray(u,u+10).forEach(b=>{b>31&&(f+=String.fromCharCode(b))}),this.userBank.load(`MSB LSB PRG
+0 127 ${n} ${f}`,!0),l.name=f,l.ending=" "}return(l.ending!=" "||!l.name.length)&&(l=this.baseBank.get(r,n,a,i)),l}getChVoice(e){let t=this.getVoice(this.#e[e*o.cc+h[0]],this.#y[e],this.#e[e*o.cc+h[32]],m[this.#t]);if(this.#U[e])switch(this.#t){case k.mt32:t.ending="~",t.name="",this.#H.subarray(14*(e-1),14*(e-1)+10).forEach(s=>{s>31&&(t.name+=String.fromCharCode(s))})}return t}init(e=0){this.dispatchEvent("mode","?"),this.#t=0,this.#E=0,this.#u=0,this.#w=0,this.#$.fill(0),this.#e.fill(0),this.#y.fill(0),this.#l.fill(0),this.#n.fill(0),this.#d.fill(0),this.#C.fill(0),this.#A.fill(0),this.#T=100,this.#s=[],this.#_=500,this.#z=0,this.#b=0,this.#a="",this.#p=0,this.#m=0,this.#h.fill(0),this.#i=!1,this.#q=0,this.#Q=!0,this.#I.forEach(function(t,s,i){i[s]=s}),this.buildRchTree(),e==0&&(this.#k.fill(0),this.#S.fill(0)),this.#e[o.cc*9]=S[0],this.#e[o.cc*25]=S[0],this.#e[o.cc*41]=S[0],this.#e[o.cc*57]=S[0],this.#Y.fill(0),this.#V.fill(0),this.#L.fill(0),this.#X.fill(0),this.#H.fill(0),this.#U.fill(0),this.userBank.clearRange({msb:0,lsb:127,prg:[0,127]});for(let t=0;t-1){if(this.#t==0||t){this.#t=s,this.#m=0,this.#E=B[0][s],this.#u=B[1][s];for(let i=0;i-1&&(this.#e[i*o.cc]=S[s]);switch(this.initOnReset,s){case k.mt32:{mt32DefProg.forEach((i,r)=>{let n=r+1;this.#$[n]||(this.#y[n]=i,this.#e[n*o.cc+h[91]]=127)});break}}this.dispatchEvent("mode",e)}}else throw new Error(`Unknown mode ${e}`)}newStrength(){this.#d.fill(0)}runJson(e){if(e.type>14)return e.type==15&&e.data.constructor!=Uint8Array&&(e.data=Uint8Array.from(e.data)),this.#F[e.type].call(this,e);{let t=this.chRedir(e.part,e.track),s=!1;this.#K[t]?.forEach(i=>{e.channel=i,s=!0,this.#F[e.type].call(this,e)}),s||console.warn(`${I[e.type]?I[e.type]:e.type}${[11,12].includes(e.type)?(e.data[0]!=null?e.data[0]:e.data).toString():""} event sent to CH${t+1} without any recipient.`)}this.#s.length>100&&this.#s.splice(100,this.#s.length-99)}runRaw(e){}constructor(){super();let e=this;this.#h=new Uint8Array(256),this.#g[10]=new Uint8Array(512),this.#R=new w,this.userBank.strictMode=!0,this.userBank.load(`MSB PRG LSB NME
+062 000 000
+122 000 000
+122 001 000
+122 002 000
+122 003 000
+122 004 000
+122 005 000
+122 006 000 `),this.#c[1]=function(t){switch(t.slice(0,2)){case"@I":{this.#i=!0,this.#s.unshift(`Kar.Info: ${t.slice(2)}`);break}case"@K":{this.#i=!0,this.#s.unshift("Karaoke mode active."),console.debug(`Karaoke mode active: ${t.slice(2)}`);break}case"@L":{this.#i=!0,this.#s.unshift(`Language: ${t.slice(2)}`);break}case"@T":{this.#i=!0,this.#s.unshift(`Ka.Title: ${t.slice(2)}`);break}case"@V":{this.#i=!0,this.#s.unshift(`Kara.Ver: ${t.slice(2)}`);break}case"XF":{let s=t.slice(2).split(":");switch(s[0]){case"hd":{s.slice(1).forEach((i,r)=>{i.length&&this.#s.unshift(`${["SongDate","SnRegion","SongCat.","SongBeat","SongInst","Sn.Vocal","SongCmp.","SongLrc.","SongArr.","SongPerf","SongPrg.","SongTags"][r]}: ${i}`)});break}case"ln":{s.slice(1).forEach((i,r)=>{i.length&&this.#s.unshift(`${["Kar.Lang","Kar.Name","Kar.Cmp.","Kar.Lrc.","kar.Arr.","Kar.Perf","Kar.Prg."][r]}: ${i}`)});break}default:this.#s.unshift(`XGF_Data: ${t}`)}break}default:this.#i?t[0]=="\\"?this.#s.unshift(`@ ${t.slice(1)}`):t[0]=="/"?this.#s.unshift(t.slice(1)):this.#s[0]+=t:(this.#s[0]=t,this.#s.unshift(""))}},this.#c[2]=function(t){this.#s.unshift(`Copyrite: ${t}`)},this.#c[3]=function(t,s){s<1&&this.#w<1&&this.#s.unshift(`TrkTitle: ${t}`)},this.#c[4]=function(t,s){this.#s.unshift(`${_(this.#w,""," ")}Instrmnt: ${t}`)},this.#c[5]=function(t){t.trim()==""?this.#s.unshift(""):this.#s[0]+=`${t}`},this.#c[6]=function(t){this.#s.unshift(`${_(this.#w,""," ")}C.Marker: ${t}`)},this.#c[7]=function(t){this.#s.unshift(`CuePoint: ${t}`)},this.#c[32]=function(t){this.#w=t[0]+1},this.#c[33]=function(t,s){console.debug(`Track ${s} requests to get assigned to output ${t}.`),e.#S[s]=t+1},this.#c[81]=function(t,s){e.#_=t/1e3},this.#c[127]=function(t,s){e.#R.run(t,s)},this.#R.default=function(t){console.warn(`Unrecognized sequencer-specific byte sequence: ${t}`)},this.#R.add([67,0,1],function(t,s){e.#S[s]=t[0]+1}),this.#P=new w,this.#N=new w,this.#v=new w,this.#M=new w,this.#O=new w,this.#G=new w,this.#B=new w,this.#P.add([9],t=>{e.switchMode(["gm","?","g2"][t[0]-1],!0),e.#i=e.#i||!1,console.info(`MIDI reset: ${["GM","Init","GM2"][t[0]-1]}`),t[0]==2&&e.init()}),this.#N.add([4,1],t=>{e.#T=((t[1]<<7)+t[0])/16383*100}).add([4,3],t=>((t[1]<<7)+t[0]-8192)/8192).add([4,4],t=>t[1]-64),this.#v.add([76,0,0],t=>{switch(t[0]){case 126:{e.switchMode("xg",!0),e.#i=!1,console.info("MIDI reset: XG");break}}}).add([76,6,0],t=>{let s=t[0];s<64?(e.#a=" ".repeat(s),e.#b=Date.now()+3200,t.subarray(1).forEach(function(i){e.#a+=String.fromCharCode(i)}),e.#a=e.#a.padEnd(32," ")):e.#b=Date.now()}).add([76,7,0],t=>{let s=t[0];e.#p=Date.now()+3200,e.#h.fill(0);let i=t.subarray(1);for(let r=0;r>6-f&1,f++})}),this.#v.add([43,7,0],(t,s,i)=>{e.#a=" ".repeat(offset),e.#b=Date.now()+3200,t.subarray(1).forEach(function(r){e.#a+=String.fromCharCode(r)}),e.#a=e.#a.padEnd(32," ")}).add([43,7,1],(t,s,i)=>{e.#p=Date.now()+3200,e.#h.fill(0),t.forEach(function(r,n){let a=Math.floor(n/16),l=n%16,c=(l*3+a)*7,u=7,f=0;for(c-=l*5,a==2&&(u=2);f>6-f&1,f++})}),this.#M.add([66,18,0,0,127],(t,s,i)=>{e.switchMode("gs",!0),e.#e[o.cc*9]=120,e.#e[o.cc*25]=120,e.#e[o.cc*41]=120,e.#e[o.cc*57]=120,e.#u=3,e.#i=!1,e.#k.fill(0),console.info(`GS system to ${["single","dual"][t[0]]} mode.`)}).add([66,18,64,0],(t,s,i)=>{switch(t[0]){case 127:{e.switchMode("gs",!0),e.#e[o.cc*9]=120,e.#e[o.cc*25]=120,e.#e[o.cc*41]=120,e.#e[o.cc*57]=120,e.#i=!1,e.#k.fill(0),console.info("MIDI reset: GS");break}}}).add([69,18,16],t=>{switch(t[0]){case 0:{e.#b=Date.now()+3200;let s=t[1];e.#a=" ".repeat(s),t.subarray(2).forEach(function(i){i<128&&(e.#a+=String.fromCharCode(i))});break}case 32:{e.#p=Date.now()+3200,t[1]==0&&(e.#m=Math.max(Math.min(t[2]-1,9),0));break}default:if(t[0]<11){e.#p=Date.now()+3200,e.#g[t[0]-1]?.length||(e.#g[t[0]-1]=new Uint8Array(256));let s=e.#g[t[0]-1],i=t[1];s.fill(0);let r=t.subarray(2);for(let n=0;n>4-b&1,b++})}else console.warn(`Unknown GS display section: ${t[0]}`)}}),this.#M.add([22,18,127],t=>{e.switchMode("mt32",!0),e.#i=!1,e.userBank.clearRange({msb:0,lsb:127,prg:[0,127]}),console.info("MIDI reset: MT-32")}).add([22,18,32],t=>{e.switchMode("mt32");let s=t[1],i=" ".repeat(s);t.subarray(2).forEach(r=>{r>31&&(i+=String.fromCharCode(r))}),e.#a=i.padStart(20," "),e.#b=Date.now()+3200}).add([22,18,82],(t,s)=>{let i=e.chRedir(0,s,!0);for(let r=0;r<16;r++)e.#r.ano(i+r),r&&r<10&&(e.#y[i+r]=mt32DefProg[r-1]);console.info("MT-32 alt reset complete.")}),this.#O.add([66,0],(t,s)=>{e.switchMode("ns5r",!0),e.#i=!1,console.debug(`NS5R mode switch requested: ${["global","multi","prog edit","comb edit","drum edit","effect edit"][t[0]]} mode.`)}).add([66,1],(t,s)=>{e.switchMode(["ns5r","05rw"][t[0]],!0),e.#i=!1}).add([66,18,0,0],(t,s)=>{switch(t[0]){case 124:case 126:case 127:{e.switchMode("ns5r",!0),e.#i=!1;break}}}).add([66,18,8,0],(t,s)=>{}).add([66,125],t=>{e.dispatchEvent("backlight",["green","orange","red",!1,"yellow","blue","purple"][t[0]]||"white")}).add([66,127],t=>{let s=new Uint8Array(5760);korgFilter(t,(i,r,n)=>{if(r<720)for(let a=0;a<8;a++)s[r*8+a]=i>>7-a&1}),e.dispatchEvent("screen",{type:"ns5r",data:s})}).add([76],(t,s,i)=>{e.#O.run([66,...t],s,i)}),this.#G.add([16,0,8,0],(t,s,i)=>{let r=(t[2]<<4)+t[3],n="K11 ";([()=>{e.switchMode("k11",!0),e.#i=!1,e.#u=r?4:0,console.info("MIDI reset: GMega/K11")}][t[0]]||(()=>{}))()}),this.#B.add([66,93,64],(t,s,i)=>{let r=t[2];switch(t[0]){case 0:{switch(t[1]){case 127:{e.switchMode("sg",!0);break}}break}}})}};export{Ve as OctaviaDevice,o as allocated,h as ccToPos};
diff --git a/dist/xp_basic.mjs b/dist/xp_basic.mjs
new file mode 100644
index 00000000..cc5d32dc
--- /dev/null
+++ b/dist/xp_basic.mjs
@@ -0,0 +1,156 @@
+var ir=Object.create;var ht=Object.defineProperty;var nr=Object.getOwnPropertyDescriptor;var or=Object.getOwnPropertyNames;var cr=Object.getPrototypeOf,lr=Object.prototype.hasOwnProperty;var hr=(u,e,n)=>e in u?ht(u,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):u[e]=n;var St=(u,e)=>()=>(u&&(e=u(u=0)),e);var dr=(u,e)=>()=>(e||u((e={exports:{}}).exports,e),e.exports);var fr=(u,e,n,h)=>{if(e&&typeof e=="object"||typeof e=="function")for(let c of or(e))!lr.call(u,c)&&c!==n&&ht(u,c,{get:()=>e[c],enumerable:!(h=nr(e,c))||h.enumerable});return u};var ur=(u,e,n)=>(n=u!=null?ir(cr(u)):{},fr(e||!u||!u.__esModule?ht(n,"default",{value:u,enumerable:!0}):n,u));var C=(u,e,n)=>(hr(u,typeof e!="symbol"?e+"":e,n),n),xt=(u,e,n)=>{if(!e.has(u))throw TypeError("Cannot "+n)};var t=(u,e,n)=>(xt(u,e,"read from private field"),n?n.call(u):e.get(u)),E=(u,e,n)=>{if(e.has(u))throw TypeError("Cannot add the same private member more than once");e instanceof WeakSet?e.add(u):e.set(u,n)},w=(u,e,n,h)=>(xt(u,e,"write to private field"),h?h.call(u,n):e.set(u,n),n);var Mt=St(()=>{"use strict";R();(function(){var u=function(o,i,s){var f,l;if(self.MessageEvent)switch(o){case"message":{l=new MessageEvent(o,{data:i,ports:s==null?void 0:s.ports}),Object.defineProperty(l,"source",{value:s==null?void 0:s.source});break}default:l=new Event(o)}else l=document.createEvent("Event"),l.initEvent(o,!1,!1),s&&o=="message"&&(l.data=i,s.source&&Object.defineProperty(l,"source",{value:s.source}),(f=s.ports)!=null&&f.length&&Object.defineProperty(l,"ports",{value:s.ports}));return l};self.BroadcastChannel?console.info("[Snowy] Snowy is disabled."):(console.info("[Snowy] Snowy is enabled. Path: ".concat(self.SNOWY_PATH||"/snowy.js")),n=[],h={},c=function(o){var i,s=this;if((this==null?void 0:this.constructor)!=c)throw new TypeError("Illegal constructor");n.push(this),(i=h[o])!=null&&i.constructor||(h[o]=[]),h[o].push(this);var f=Math.floor(Math.random()*281474976710656),l=[],d=0,b=[],y=!0,k=!1;Object.defineProperty(this,"id",{get:function(){return f}}),Object.defineProperty(this,"name",{value:o}),this.close=function(){var m,x=n.indexOf(s);x>-1?(e.postMessage({t:"d",c:o,i:f}),n.splice(x,1),(m=h[o])!=null&&m.constructor&&(x=h[o].indexOf(s),x>-1&&h[o].splice(x,1)),h[o].length||delete h[o],console.debug("[Snowy] BroadcastChannel closed."),k=!0):console.debug("[Snowy] BroadcastChannel already closed.")},this.postMessage=function(m){if(e){if(k)throw new Error("Channel already closed");e.postMessage({t:"m",c:o,i:f,m:d,d:m}),d++,d>4294967295&&(d=0)}else b.push(m),console.debug("[Snowy] Message is cached.")},this.flush=function(){if(e){if(y){for(e.postMessage({t:"r",c:o,i:f}),console.debug("[Snowy] ".concat(b.length," message(s) in cache."));b.length;){var m=b.shift();s.postMessage(m)}y=!1,console.debug("[Snowy] All cached messages are flushed away.")}}else throw new Error("Tried to flush when the ports are not ready")},this.receiveMessage=function(m){m.c==o?m.i!=f&&s.dispatchEvent(u("message",m.d,{source:s})):console.debug("[Snowy] Channel ID mismatch. Instance ".concat(f," receives from ").concat(o,", not ").concat(m.c,"."))};var v={};this.dispatchEvent=function(m){var x,A;if(Object.defineProperty(m,"target",{value:s}),Object.defineProperty(m,"currentTarget",{value:s}),(x=v[m.type])!=null&&x.length)for(var V=v[m.type],ae=0;ae-1&&v[m].splice(ae,1)}!((V=v[m])!=null&&V.length)&&v[m].constructor&&delete v[m]}},self.BroadcastChannel=c,r=function(){if(e){e.addEventListener("message",function(i){var s=i.data,f=!1;switch(s.t){case"k":{f=!1,e.postMessage({t:"k"});break}case"m":{var l=h[s.c];if(l!=null&&l.length)for(var d=0;d{"use strict";Mt();{let u=function(e,n){let h=new FileReader;return new Promise((c,r)=>{switch(h.addEventListener("abort",()=>{r(new Error("Blob read aborted"))}),h.addEventListener("error",a=>{r(h.error||a.data||new Error("Blob read error"))}),h.addEventListener("load",()=>{c(h.result)}),n.toLowerCase()){case"arraybuffer":case"buffer":{h.readAsArrayBuffer(e);break}case"string":case"text":{h.readAsText(e);break}default:r(new Error(`Unknown target ${n}`))}})};Blob.prototype.arrayBuffer=Blob.prototype.arrayBuffer||function(){return u(this,"buffer")},Blob.prototype.text=Blob.prototype.text||function(){return u(this,"text")}}String.prototype.replaceAll=String.prototype.replaceAll||function(u,e){let n=0,h=16,c=this,r=[];for(;n-1;){let a=c.lastIndexOf(u);r.unshift(c.slice(a+u.length)),c=c.slice(0,a),a==0&&r.unshift(""),n++}return c.length&&r.unshift(c),r.join(e)||""},String.prototype.padStart=String.prototype.padStart||function(u,e){if(e){let n=this;for(;n.length{R();(function(){"use strict";let u={fatal:!0},e=[new TextDecoder("iso-8859-15",u),new TextDecoder("sjis",u),new TextDecoder("euc-jp",u),new TextDecoder("utf-8",u),new TextDecoder("utf-16",u),new TextDecoder("ascii")],n={debug:!1,parse:function(h,c){if(h instanceof Uint8Array)return n.Uint8(h);if(typeof h=="string")return n.Base64(h);if(h instanceof HTMLElement&&h.type==="file")return n.addListener(h,c);throw new Error("MidiParser.parse() : Invalid input provided")},addListener:function(h,c){if(!File||!FileReader)throw new Error("The File|FileReader APIs are not supported in this browser. Use instead MidiParser.Base64() or MidiParser.Uint8()");if(h===void 0||!(h instanceof HTMLElement)||h.tagName!=="INPUT"||h.type.toLowerCase()!=="file")return console.warn("MidiParser.addListener() : Provided element is not a valid FILE INPUT element"),!1;c=c||function(){},h.addEventListener("change",function(r){if(!r.target.files.length)return!1;console.log("MidiParser.addListener() : File detected in INPUT ELEMENT processing data..");let a=new FileReader;a.readAsArrayBuffer(r.target.files[0]),a.onload=function(o){c(n.Uint8(new Uint8Array(o.target.result)))}})},Base64:function(h){let c=function(o){var i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";if(o=o.replace(/^.*?base64,/,""),o=String(o).replace(/[\t\n\f\r ]+/g,""),!/^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/.test(o))throw new TypeError("Failed to execute _atob() : The string to be decoded is not correctly encoded.");o+="==".slice(2-(3&o.length));let s,f="",l,d,b=0;for(;b>16&255):d===64?String.fromCharCode(s>>16&255,s>>8&255):String.fromCharCode(s>>16&255,s>>8&255,255&s);return f}(h=String(h));var r=c.length;let a=new Uint8Array(new ArrayBuffer(r));for(let o=0;o{d[v]=this.readInt(1)});for(let k=0;k191||m>127&&m<160)throw new RangeError(`Invalid code point: ${m}`)}b=!0,console.debug(`String byte sequence in ${e[k].encoding}`)}catch(v){console.debug(`SMF string ${v}`)}return y||"String byte sequence read failed."},backOne:function(){this.pointer--},readIntVLV:function(){let l=0;if(this.pointer>=this.data.byteLength)return-1;if(this.data.getUint8(this.pointer)<128)l=this.readInt(1);else{let b=[];for(;128<=this.data.getUint8(this.pointer);)b.push(this.readInt(1)-128);var d=this.readInt(1);for(let y=1;y<=b.length;y++)l+=b[b.length-y]*Math.pow(128,y);l+=d}return l}};if(c.data=new DataView(a.buffer,a.byteOffset,a.byteLength),c.readInt(4)!==1297377380)return console.warn("Header validation failed (not MIDI standard or file corrupt.)"),!1;c.readInt(4);let r={};r.formatType=c.readInt(2),r.tracks=c.readInt(2),r.track=[];var a=c.readInt(1),o=c.readInt(1);128<=a?(r.timeDivision=[],r.timeDivision[0]=a-128,r.timeDivision[1]=o):r.timeDivision=256*a+o;for(let l=1;l<=r.tracks;l++){r.track[l-1]={event:[]};var i,s=c.readInt(4);if(s===-1)break;if(s!==1297379947)return!1;c.readInt(4);let d=0,b=!1,y,k;for(;!b&&(d++,r.track[l-1].event[d-1]={},r.track[l-1].event[d-1].deltaTime=c.readIntVLV(),(y=c.readInt(1))!==-1);)if(128<=y?k=y:(y=k,c.movePointer(-1)),y===255){r.track[l-1].event[d-1].type=255,r.track[l-1].event[d-1].metaType=c.readInt(1);var f=c.readIntVLV();switch(r.track[l-1].event[d-1].metaType){case 47:case-1:b=!0;break;case 1:case 2:case 3:case 4:case 5:case 7:case 6:r.track[l-1].event[d-1].data=c.readStr(f);break;case 33:case 89:case 81:r.track[l-1].event[d-1].data=c.readInt(f);break;case 84:r.track[l-1].event[d-1].data=[],r.track[l-1].event[d-1].data[0]=c.readInt(1),r.track[l-1].event[d-1].data[1]=c.readInt(1),r.track[l-1].event[d-1].data[2]=c.readInt(1),r.track[l-1].event[d-1].data[3]=c.readInt(1),r.track[l-1].event[d-1].data[4]=c.readInt(1);break;case 88:r.track[l-1].event[d-1].data=[],r.track[l-1].event[d-1].data[0]=c.readInt(1),r.track[l-1].event[d-1].data[1]=c.readInt(1),r.track[l-1].event[d-1].data[2]=c.readInt(1),r.track[l-1].event[d-1].data[3]=c.readInt(1);break;default:this.customInterpreter!==null&&(r.track[l-1].event[d-1].data=this.customInterpreter(r.track[l-1].event[d-1].metaType,c,f)),this.customInterpreter!==null&&r.track[l-1].event[d-1].data!==!1||(c.readInt(f),r.track[l-1].event[d-1].data=c.readInt(f),this.debug&&console.info("Unimplemented 0xFF meta event! data block readed as Integer"))}}else switch((y=y.toString(16).split(""))[1]||y.unshift("0"),r.track[l-1].event[d-1].type=parseInt(y[0],16),r.track[l-1].event[d-1].channel=parseInt(y[1],16),r.track[l-1].event[d-1].type){case 15:this.customInterpreter!==null&&(r.track[l-1].event[d-1].data=this.customInterpreter(r.track[l-1].event[d-1].type,c,!1)),this.customInterpreter!==null&&r.track[l-1].event[d-1].data!==!1||(i=c.readIntVLV(),r.track[l-1].event[d-1].data=c.readInt(i),this.debug&&console.info("Unimplemented 0xF exclusive events! data block readed as Integer"));break;case 10:case 11:case 14:case 8:case 9:r.track[l-1].event[d-1].data=[],r.track[l-1].event[d-1].data[0]=c.readInt(1),r.track[l-1].event[d-1].data[1]=c.readInt(1);break;case 12:case 13:r.track[l-1].event[d-1].data=c.readInt(1);break;case-1:b=!0;break;default:if(this.customInterpreter!==null&&(r.track[l-1].event[d-1].data=this.customInterpreter(r.track[l-1].event[d-1].metaType,c,!1)),this.customInterpreter===null||r.track[l-1].event[d-1].data===!1)return console.log("Unknown EVENT detected... reading cancelled!"),!1}}return r},customInterpreter:null};if(typeof Et<"u")Et.exports=n;else{let h=typeof window=="object"&&window.self===window&&window||typeof self=="object"&&self.self===self&&self||typeof global=="object"&&global.global===global&&global;h.MidiParser=n}})()});R();R();var z,Ct,it=(Ct=class{constructor(){E(this,z,{})}addEventListener(u,e){t(this,z)[u]||(t(this,z)[u]=[]),t(this,z)[u].unshift(e)}removeEventListener(u,e){if(t(this,z)[u]){let n=t(this,z)[u].indexOf(e);n>-1&&t(this,z)[u].splice(n,1),t(this,z)[u].length<1&&delete t(this,z)[u]}}dispatchEvent(u,e){var c;let n=new Event(u),h=this;n.data=e,((c=t(this,z)[u])==null?void 0:c.length)>0&&t(this,z)[u].forEach(function(r){try{r==null||r.call(h,n)}catch(a){console.error(a)}}),this[`on${u}`]&&this[`on${u}`](n)}},z=new WeakMap,Ct);R();R();var Tt=function(u,e){let n=Math.min(u.length,e.length),h=u.slice(0,n),c=e.slice(0,n),r=0,a=0;for(;a0){let h=this.pool.length,c=1<=1&&a>=0;){if(a<=0)throw new Error("TTL reached.");if(r==h)r-=c;else{let i=Tt(e,this.pool[r]);switch(i){case 0:{a=0;break}case 1:{r+c<=h&&(r+=c);break}case-1:{r!=0&&(r-=c);break}default:console.warn(`Unexpected result ${i}.`)}}c=c>>1,a--}let o=!0;if(r>=this.pool.length)o=!1;else{let i=this;this.pool[r].forEach(function(s,f,l){o&&s!=e[f]&&(o=!1)}),!o&&Tt(e,this.pool[r])>0&&r++}return o||n?r:-1}else return n?0:-1},this.add=function(e,n){return e.data=n,this.pool.splice(this.point(e,!0),0,e),this},this.default=function(e){console.warn(`No match in "${this.name||"(unknown)"}" for "${e}". Default action not defined.`)},this.get=function(e){let n=this.point(e);if(n>-1)return this.pool[n].data;this.default(e)},this.run=function(e,...n){let h=this.point(e);h>-1?e.subarray?this.pool[h].data(e.subarray(this.pool[h].length),...n):this.pool[h].data(e.slice(this.pool[h].length),...n):this.default(e,...n)}};R();var pr=["MSB","PRG","LSB"],dt=function(u){let e=Math.floor(u/10),n=u%10;return`${e.toString(16)}${n}`},K,Rt,ft=(Rt=class{constructor(...u){E(this,K,void 0);C(this,"strictMode",!1);this.loadFiles(...u)}get(u=0,e=0,n=0,h){let c=[u,e,n],r,a=Array.from(arguments);switch(h){case"xg":{u==32?a[2]+=4:u==33||u==35||u==36?a[2]+=5:u==79?a[0]=95:u==80?a[0]=96:u==81?a[0]=97:u==82?a[0]=98:u==83?a[0]=99:u==84&&(a[0]=100);break}case"gs":{u==0&&n<5?a[2]=0:u>125&&n<5&&n!=2&&(a[2]=u,a[0]=0);break}case"sg":{u==8&&n==0&&(a[2]=5);break}case"s90es":{n<8?a[2]+=17:n<32?a[2]+=13:a[2]=(a[2]>>3)+19;break}case"motif":{n<8?a[2]+=28:n<32?a[2]+=13:a[2]=(a[2]>>3)+19;break}}let o=" ",i="M",s=!1,f=0;switch(a[0]){case 0:{a[2]==127?i="MT-a":a[2]==126?i="MT-b":a[2]==7?i="GM-k":a[2]==5?i="SG-a":a[2]==4?i="SP-l":a[2]==0||h=="gs"&&a[2]<5?i="GM-a":(i="y",s=!0);break}case 8:{h=="sg"?i="GM-s":i="r:";break}case 48:{i=`yM${(a[2]>>3).toString().padStart(2,"0")}`,s=!0;break}case 56:{i="GM-b";break}case 61:case 120:{i="rDrm";break}case 62:{i="kDrm";break}case 63:{if(a[2]<17){let y=a[2];i=y<10?"kP:":"kC:",i+=y%10}else a[2]<34?i=["Pre1","Pre2","Pre3","Pre4","Usr1","Usr2","DrmP","DrmU","Plg1","Plg2","Plg3","Pre1","Pre2","Pre3","Pre4","Pre5","Pre6"][a[2]-17]:i="Ds";break}case 64:{i="ySFX";break}case 67:{i="DX:S";break}case 80:case 81:case 82:case 83:{i=`Prg${"UABC"[a[0]-80]}`;break}case 88:case 89:case 90:case 91:{i=`Cmb${"UABC"[a[0]-88]}`;break}case 95:{i=`${["DR","PC"][a[2]]}-d`;break}case 96:{i=a[2]==106?"AP-a":"PF",a[2]>63&&(f=63),s=!0;break}case 97:{i="VL:",s=!0,f=112;break}case 98:{i="SG-a";break}case 99:{i="DX",a[2]>63&&(f=63),s=!0;break}case 100:{i="AN",a[2]>63&&(f=63),s=!0;break}case 121:{i=`GM-${a[2]?"":"a"}`,s=!0;break}case 122:{i="lDrm";break}case 126:{i="yDrS";break}case 127:{a[2]==127?i="rDrm":i="yDrm";break}default:a[0]<48?i="r:":i="M"}i.length<4&&(i+=`${(s?n:u)-f}`.padStart(4-i.length,"0")),h=="xg"&&u==16&&(r=`Voice${(n*128+e+1).toString().padStart(3,"0")}`,o=" ");let l=[a[0],a[1],a[2]];for(;!((r==null?void 0:r.length)>=0);)r=t(this,K)[a[1]||0][(a[0]<<7)+a[2]],r||(this.strictMode?(r="",o="?"):t(this,K)[a[1]||0][a[0]<<7]?a[0]==0?(a[2]=0,o="^"):a[2]<1?(a[0]=0,o="*"):(a[2]--,o="^"):u==48?(a[0]=0,a[2]=0,o="!"):u==62?(a[1]--,o=" ",a[1]<1&&!(r!=null&&r.length)&&(a[0]=0,o="!")):u<63?a[0]==0?(a[2]=0,o="^"):a[2]<1?(a[0]=0,o="*"):a[2]--:u==80?(r=`PrgU:${e.toString().padStart(3,"0")}`,o="!"):u==88?(r=`CmbU:${e.toString().padStart(3,"0")}`,o="!"):u==121?(r=`GM2Vox0${n}`,o="#"):u==122?(a[1]==32?a[1]==0:a[1]%=7,r=t(this,K)[a[1]||0][(a[0]<<7)+a[2]],r?o=" ":(r="",o="*")):a[1]==0?(r=`${u.toString().padStart(3,"0")} ${e.toString().padStart(3,"0")} ${n.toString().padStart(3,"0")}`,o="!"):a[0]==0?(a[2]=0,o="^"):a[2]>0?a[2]--:a[1]>0?(a[1]=0,o="!"):(a[0]=0,o="?"));let d=[a[0],a[1],a[2]];(h=="gs"||h=="ns5r")&&o=="^"&&(o=" "),u==127&&o=="^"&&(o=" "),o!=" "&&self.debugMode&&(r="");let b="??";switch(a[0]){case 0:{a[2]==0?b="GM":a[2]==5||a[2]==7?b="KG":a[2]<120?b="XG":a[2]==127&&(b="MT");break}case 48:{b="MU";break}case 56:{b="AG";break}case 61:case 80:case 83:case 88:case 89:case 91:{b="AI";break}case 62:case 82:case 90:{b="XD";break}case 63:{a[2]<17?b="KR":a[2]<34?b="ES":b="DS";break}case 64:case 126:{b="XG";break}case 67:case 99:{b="DX";break}case 81:{b="RW";break}case 95:{b=["DR","PC"][a[2]];break}case 96:{b=a[2]==106?"AP":"PF";break}case 97:{b="VL";break}case 98:{b="SG";break}case 100:{b="AN";break}case 120:{b="GS";break}case 121:{b=a[2]?"G2":"GM";break}case 122:{b="KG";break}case 127:{b=a[2]==127?"MT":e==0?"GM":"XG";break}default:a[0]<48&&(a[0]==16&&h=="xg"?b="XG":b="GS")}return{name:r||`${dt(u||0)} ${dt(e||0)} ${dt(n||0)}`,iid:l,eid:d,sid:c,ending:o,sect:i,standard:b}}async load(u,e,n){let h=this,c=[],r=0,a=0;u.split(`
+`).forEach(function(o,i){let s=o.split(" "),f=[];i==0?s.forEach(function(l,d){c[pr.indexOf(l)]=d}):s.forEach(async function(l,d){var b;d>2?(t(h,K)[f[c[1]]]=t(h,K)[f[c[1]]]||[],(!((b=t(h,K)[f[c[1]]][(f[c[0]]<<7)+f[c[2]]])!=null&&b.length)||e)&&(t(h,K)[f[c[1]]][(f[c[0]]<<7)+f[c[2]]]=s[3],r++),a++):f.push(parseInt(s[d]))})}),e||console.debug(`Map "${n||"(internal)"}": ${a} total, ${r} loaded.`)}clearRange(u){let e=u.prg!=null?u.prg.constructor==Array?u.prg:[u.prg,u.prg]:[0,127],n=u.msb!=null?u.msb.constructor==Array?u.msb:[u.msb,u.msb]:[0,127],h=u.lsb!=null?u.lsb.constructor==Array?u.lsb:[u.lsb,u.lsb]:[0,127];for(let c=n[0];c<=n[1];c++){let r=c<<7;for(let a=h[0];a<=h[1];a++){let o=r+a;for(let i=e[0];i<=e[1];i++)delete t(this,K)[i][o]}}}init(){w(this,K,[]);for(let u=0;u<128;u++)t(this,K).push([""])}async loadFiles(...u){this.init();let e=this;u.forEach(async function(n,h){try{await fetch(`./data/bank/${n}.tsv`).then(function(c){return c.text()}).then(c=>{e.load(c,!1,n)})}catch(c){console.error(`Failed loading "${n}.tsv".`)}})}},K=new WeakMap,Rt);R();R();var Ge,Ot,Pt=(Ot=class{constructor(){E(this,Ge,{});C(this,"context")}set(u,e){t(this,Ge)[u]=e}has(u){return!!t(this,Ge)[u]}async read(u,e){if(!this.has(u))throw new Error(`No decoder registered for "${u}"`);return await t(this,Ge)[u].call(this.context||this,e)}},Ge=new WeakMap,Ot);var br=function(u,e){let n=!0;return e.forEach((h,c)=>{n=n&&u[c]==h}),n},Dt=function(u){let e=0;return u.forEach(n=>{e*=256,e+=n}),e},Qe=new TextDecoder,nt=new Pt;nt.set("s7e",async function(u){let e=new Uint8Array(await u.slice(0,65536).arrayBuffer()),n="MSB LSB PRG NME",h=[0,0,0,0],c=32,r=0,a=0,o=!0,i=[],s=0;for(;o;){let f=e.subarray(r);([()=>{Qe.decode(f.subarray(0,4))=="YSFC"?(r+=80,a=1):r++},()=>{if(br(f.subarray(0,4),h))i.forEach((l,d,b)=>{let y=Dt(e.subarray(l.start+4,l.start+8));l.length=y}),a=2;else{let l=Qe.decode(f.subarray(0,4)),d=Dt(f.subarray(4,8));i.push({type:l,start:d}),r+=8}},()=>{let l=i[s],d=e.subarray(l.start,l.start+l.length),b=32;switch(l.type){case"ENVC":{let y=c;for(;y=i.length&&(a=3,o=!1)}][a]||(()=>{o=!1}))()}return n});R();var We=["off","hall","room","stage","plate","delay LCR","delay LR","echo","cross delay","early reflections","gate reverb","reverse gate"].concat(new Array(4),["white room","tunnel","canyon","basement","karaoke"],new Array(43),["pass through","chorus","celeste","flanger","symphonic","rotary speaker","tremelo","auto pan","phaser","distortion","overdrive","amplifier","3-band EQ","2-band EQ","auto wah"],new Array(1),["pitch change","harmonic","touch wah","compressor","noise gate","voice channel","2-way rotary speaker","ensemble detune","ambience"],new Array(4),["talking mod","Lo-Fi","dist + delay","comp + dist + delay","wah + dist + delay","V dist","dual rotor speaker"]),Ye=["melodic","drums","drum set 1","drum set 2","drum set 3","drum set 4","drum set 5","drum set 6","drum set 7","drum set 8"],gr=[17.1,18.6,20.2,21.8,23.3,24.9,26.5,28,29.6,31.2,32.8,34.3,35.9,37.5,39,40.6,42.2,43.7,45.3,46.9,48.4,50],_e=[20,22,25,28,32,36,40,45,50,56,63,70,80,90,100,110,125,140,160,180,200,225,250,280,315,355,400,450,500,560,630,700,800,900,1e3,1100,1200,1400,1600,1800,2e3,2200,2500,2800,3200,3600,4e3,4500,5e3,5600,6300,7e3,8e3,9e3,1e4,11e3,12e3,14e3,16e3,18e3,2e4],It=[0,.04,.08,.13,.17,.21,.25,.29,.34,.38,.42,.46,.51,.55,.59,.63,.67,.72,.76,.8,.84,.88,.93,.97,1.01,1.05,1.09,1.14,1.18,1.22,1.26,1.3,1.35,1.39,1.43,1.47,1.51,1.56,1.6,1.64,1.68,1.72,1.77,1.81,1.85,1.89,1.94,1.98,2.02,2.06,2.1,2.15,2.19,2.23,2.27,2.31,2.36,2.4,2.44,2.48,2.52,2.57,2.61,2.65,2.69,2.78,2.86,2.94,3.03,3.11,3.2,3.28,3.37,3.45,3.53,3.62,3.7,3.87,4.04,4.21,4,37,4.54,4.71,4.88,5.05,5.22,5.38,5.55,5.72,6.06,6.39,6.73,7.07,7.4,7.74,8.08,8.41,8.75,9.08,9.42,9.76,10.1,10.8,11.4,12.1,12.8,13.5,14.1,14.8,15.5,16.2,16.8,17.5,18.2,19.5,20.9,22.2,23.6,24.9,26.2,27.6,28.9,30.3,31.6,33,34.3,37,39.7],At=function(u){let e=.1,n=-.3;return u>66?(e=5,n=315):u>56?(e=1,n=47):u>46&&(e=.5,n=18.5),e*u-n},Ut=function(u){return u>105?gr[u-106]:u>100?u*1.1-100:u/10},Lt=",a,i,u,e,o,ka,ki,ku,ke,ko,ky,kw,sa,si,su,se,so,sh,ta,ti,tu,te,to,t,ch,t,s,na,ni,nu,ne,no,ny,nn,ha,hi,hu,he,ho,hy,fa,fi,fu,fe,fo,ma,mi,mu,me,mo,my,mm,ya,yu,ye,yo,ra,ri,ru,re,ro,ry,wa,wi,we,wo,ga,gi,gu,ge,go,gy,gw,za,zi,zu,ze,zo,ja,ji,ju,je,jo,jy,da,di,du,de,do,dy,ba,bi,bu,be,bo,by,va,vi,vu,ve,vo,pa,pi,pu,pe,po,py,nga,ngi,ngu,nge,ngo,ngy,ng,hha,hhi,hhu,hhe,hho,hhy,hhw,*,_,,,~,.".split(","),ut={};`hi*,
+ka,か
+ki,き
+ku,く
+ke,け
+ko,こ
+ky,き!
+kw,くl
+tsu,つ
+ts,つl
+sa,さ
+si,すぃ
+su,す
+se,せ
+so,そ
+shi,し
+sh,し!
+ta,た
+ti,てぃ
+tu,とぅ
+te,て
+to,と
+tchy,ち!
+tchi,ち
+na,な
+ni,に
+nu,ぬ
+ne,ね
+no,の
+ny,に!
+nn,ん
+ha,は
+hi,ひ
+hu,ほぅ
+he,へ
+ho,ほ
+hy,ひ!
+fa,ふぁ
+fi,ふぃ
+fu,ふ
+fe,ふぇ
+fo,ふぉ
+ma,ま
+mi,み
+mu,む
+me,め
+mo,も
+my,み!
+mm,
+ra,ら
+ri,り
+ru,る
+re,れ
+ro,ろ
+ry,り!
+wa,わ
+wi,うぃ
+we,うぇ
+wo,を
+nga,ガ
+ngi,ギ
+ngu,グ
+nge,ゲ
+ngo,ゴ
+ngy,ギ!
+ng,
+ga,が
+gi,ぎ
+gu,ぐ
+ge,げ
+go,ご
+gy,ぎ!
+gw,ぐl
+za,ざ
+zi,ずぃ
+zu,ず
+ze,ぜ
+zo,ぞ
+ja,じゃ
+ji,じ
+ju,じゅ
+je,じぇ
+jo,じょ
+jy,じ!
+da,だ
+di,でぃ
+du,どぅ
+de,で
+do,ど
+dy,で!
+ba,ば
+bi,び
+bu,ぶ
+be,べ
+bo,ぼ
+by,び!
+va,ゔぁ
+vi,ゔぃ
+vu,ゔ
+ve,ゔぇ
+vo,ゔぉ
+pa,ぱ
+pi,ぴ
+pu,ぷ
+pe,ペ
+po,ぽ
+py,ぴ!
+!ya,ゃ
+!yu,ゅ
+!ye,ぇ
+!yo,ょ
+ya,や
+yu,ゆ
+ye,いぇ
+yo,よ
+!a,ゃ
+!u,ゅ
+!e,ぇ
+!o,ょ
+!a,ゃ
+!u,ゅ
+!e,ぇ
+!o,ょ
+la,ぁ
+li,ぃ
+lu,ぅ
+le,ぇ
+lo,ぉ
+a,あ
+i,い
+u,う
+e,え
+o,お
+*,っ
+~,
+^,
+_,`.split(`
+`).forEach(u=>{let e=u.split(",");ut[e[0]]=e[1]});var Bt=function(u){let e=u;u[0]=="*"&&(e=e.slice(1)),["aa","ii","uu","ee","oo"].forEach(h=>{for(;e.indexOf(h)>-1;)e=e.replace(h,h[0])});for(let h in ut)e=e.replaceAll(h,ut[h]);e.indexOf("ん")==0&&e.length>1&&(e=e.slice(1));let n=e.indexOf("!");return n>-1&&e.length>1&&(e=e.slice(n+1)),e},Nt=function(u){return u?u<96?`cc${u}`:["aftertouch","velocity","pitch bend"][u-96]:"off"};R();var pt=["room 1","room 2","room 3","hall 1","hall 2","plate","delay","panning delay"],Ht=["chorus 1","chorus 2","chorus 3","chorus 4","feedback","flanger","short delay","short delay feedback"],Gt=["delay 1","delay 2","delay 3","delay 4","pan delay 1","pan delay 2","pan delay 3","pan delay 4","delay to reverb","pan repeat"];var yr={0:"thru",256:"stereo EQ",257:"spectrum",258:"enhancer",259:"humanizer",272:"overdrive",273:"distortion",288:"phaser",289:"auto wah",290:"rotary",291:"stereo flanger",292:"step flanger",293:"tremelo",294:"auto pan",304:"compressor",305:"limiter",320:"hexa chorus",321:"tremelo chorus",322:"stereo chorus",323:"space D",324:"3D chorus",336:"stereo delay",337:"modulated delay",338:"3-tap delay",339:"4-tap delay",340:"tremelo control delay",341:"reverb",342:"gate reverb",343:"3D delay",352:"2-pitch shifter",353:"feedback pitch shifter",368:"3D auto",369:"3D manual",370:"Lo-Fi 1",371:"Lo-Fi 2",512:"overdrive - chorus",513:"overdrive - flanger",514:"overdrive - delay",515:"distortion - chorus",516:"distortion - flanger",517:"distortion - delay",518:"enhancer - chorus",519:"enhancer - flanger",520:"enhancer - delay",521:"chorus - delay",522:"flanger - delay",523:"chorus - flanger",524:"rotary multi",1024:"guitar multi 1",1025:"guitar multi 2",1026:"guitar multi 3",1027:"clean guitar multi 1",1028:"clean guitar multi 2",1029:"bass multi",1030:"rhodes multi",1280:"keyboard multi",4352:"chorus / delay",4353:"flanger / delay",4354:"chorus / flanger",4355:"overdrive / distortion",4356:"overdrive / rotary",4357:"overdrive / phaser",4358:"overdrive / auto wah",4359:"phaser / rotary",4360:"phaser / auto wah"},$r={66307:["drive"],66309:["vowel",u=>"aiueo"[u]],94723:["pre-filter"],94724:["Lo-Fi type"],94725:["post-filter"],94979:["Lo-Fi type"],94980:["fill type",u=>["off","LPF","HPF"][u]],94984:["noise type",u=>["white","pink"][u]],94987:["disc type",u=>["LP","SP","EP","RND"]],94990:["hum type",u=>`${u+5}0Hz`],94993:["M/S",u=>["mono","stereo"][u]]},bt=function(u){return yr[(u[0]-32<<8)+u[1]]||`0x${u[0].toString(16).padStart(2,"0")}${u[1].toString(16).padStart(2,"0")}`},_t=function(u,e,n){let h=(u[0]-32<<16)+(u[1]<<8)+e,c=$r[h]||{},r=c[0];if(r!=null&&r.length)return r+=`: ${(c[1]||function(){})(n)||n}`,r},gt=[68,48,95,78,41,3,110,122,0];R();var q=function(u=64){return Math.round(2e3*Math.log10(u/64))/100},Ft=function(u,e,n){let h=[],c=n==!1?e.readIntVLV():n;u==0||u==127;for(let r=0;r127)return console.debug(`Early termination: ${h}`),h.pop(),e.backOne(),e.backOne(),new Uint8Array(h)}}}return new Uint8Array(h)},Vt=function(u){let e=0;return u.forEach(n=>{e+=n,e=e&127}),~e+1&127},ie=function(u,e){let n=0,h=0;for(let c=0;c>r&1)<<7,o=u[c];o+=a,c%8!=0?(e(o,n,u),n++):h=u[c]}},Ze=function(u){let e=Math.floor(u*14.2);return e<128?e:0};var $e=["?","gm","gs","xg","g2","mt32","ns5r","ag10","x5d","05rw","k11","sg","krs","s90es","motif"],Xt=[[0,0,0,0,121,0,0,56,82,81,0,0,63,63,63],[0,0,4,0,0,127,0,0,0,0,0,0,0,0,0]],Me=[120,127,120,127,120,127,61,62,62,62,120,122,122,127],wr=[0,3,81,84,88],zt={8:"Off",9:"On",10:"Note aftertouch",11:"cc",12:"pc",13:"Channel aftertouch",14:"Pitch"},yt={0:0,1:1,2:3,5:4},Kt=[[0,24],[0,127],[0,127],[40,88],[0,127],[0,127]],qt=[36,37],ct=[20,21,22,23,24,25,26,28,29,30,31,36,37,64,65],Je=[0,1,2,4,5,6,7,8,10,11,32,38,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,84,91,92,93,94,95,98,99,100,101,128,12,13,16,17,18,19],Er=[12,13,16,17,18,19],mr=[33,99,100,32,102,8,9,10],jt=[0,16,25,40,32,64,26,48],M={};$e.forEach((u,e)=>{M[u]=e});var g={length:Je.length};Je.forEach((u,e)=>{g[u]=e});var wt={length:ct.length};ct.forEach((u,e)=>{wt[u]=e});var Y=function(){return!!self.Bun||self.debugMode||!1},vr=function(u){let e=[],n=0;return u==null||u.forEach(function(h,c){h==247?e.push(u.subarray(n,c)):h==240&&(n=c+1)}),e.length||e.push(u.subarray(0)),Y()&&console.debug(e),e},Qt=function(u,e="",n="",h=2){return u?`${e}${u.toString().padStart(h,"0")}${n}`:""},$={ch:128,cc:Je.length,nn:128,pl:512,tr:256,cmt:14,rpn:6,ace:8,drm:8,dpn:ct.length,dnc:128,efx:7},P,j,ne,fe,W,de,Yt,U,H,O,p,ue,D,L,J,B,G,we,oe,Ce,S,Fe,et,ce,Ee,ee,Ve,me,Q,ve,te,X,pe,Xe,ze,le,ke,Ke,re,I,tt,$t,T,be,Se,_,Te,N,rt,ot,Re,Oe,Z,he,ge,Pe,De,Ie,Wt,oa=(Wt=class extends it{constructor(){super();E(this,W);C(this,"NOTE_IDLE",0);C(this,"NOTE_ATTACK",1);C(this,"NOTE_DECAY",2);C(this,"NOTE_SUSTAIN",3);C(this,"NOTE_HELD",4);C(this,"NOTE_RELEASE",5);C(this,"NOTE_SOSTENUTO_ATTACK",8);C(this,"NOTE_SOSTENUTO_DECAY",9);C(this,"NOTE_SOSTENUTO_SUSTAIN",10);C(this,"NOTE_SOSTENUTO_HELD",11);C(this,"CH_MELODIC",0);C(this,"CH_DRUMS",1);C(this,"CH_DRUM1",2);C(this,"CH_DRUM2",3);C(this,"CH_DRUM3",4);C(this,"CH_DRUM4",5);C(this,"CH_DRUM5",6);C(this,"CH_DRUM6",7);C(this,"CH_DRUM7",8);C(this,"CH_DRUM8",9);E(this,P,0);E(this,j,0);E(this,ne,0);E(this,fe,new Array(11));E(this,U,new Uint8Array($.ch));E(this,H,new Uint8Array($.ch));E(this,O,new Uint8Array($.ch));E(this,p,new Uint8Array($.ch*$.cc));E(this,ue,new Uint8Array($.ace));E(this,D,new Uint8Array($.ch));E(this,L,new Uint8Array($.ch*$.nn));E(this,J,new Uint8Array($.ch));E(this,B,new Uint16Array($.pl));E(this,G,new Uint8Array($.pl));E(this,we,new Int16Array($.ch));E(this,oe,new Uint8Array($.ch));E(this,Ce,0);E(this,S,new Uint8Array($.ch*$.rpn));E(this,Fe,new Int8Array($.ch*qt.length));E(this,et,new Uint8Array($.drm*$.dpn*$.dnc));E(this,ce,new Uint8Array($.ch));E(this,Ee,new Uint8Array(128));E(this,ee,new Uint8Array($.cmt*8));E(this,Ve,new Uint8Array(1024));E(this,me,new Uint8Array($.cmt*64));E(this,Q,new Uint8Array($.efx*3));E(this,ve,0);E(this,te,0);E(this,X,100);E(this,pe,0);E(this,Xe,500);E(this,ze,0);E(this,le,"");E(this,ke,0);E(this,Ke,0);E(this,re,!0);E(this,I,!1);E(this,tt,void 0);E(this,$t,new Uint8Array(2));E(this,T,[]);E(this,be,new Uint8Array($.ch));E(this,Se,new Uint8Array($.tr));C(this,"baseBank",new ft("gm","gm2","xg","gs","ns5r","gmega","plg-150vl","plg-150pf","plg-150dx","plg-150an","plg-150dr","plg-100sg","kross","s90es"));C(this,"userBank",new ft("gm"));C(this,"initOnReset",!1);C(this,"aiEfxName","");E(this,_,[]);E(this,Te,void 0);E(this,N,{nOff:(e,n)=>{let h=e*128+n,c=t(this,B).lastIndexOf(h);c>-1&&(t(this,p)[$.cc*e+g[64]]>63?(t(this,G)[c]=this.NOTE_HELD,this.dispatchEvent("note",{part:e,note:n,velo:t(this,L)[h],state:this.NOTE_HELD})):t(this,p)[$.cc*e+g[66]]>63&&t(this,G)[c]==this.NOTE_SOSTENUTO_SUSTAIN?(t(this,G)[c]=this.NOTE_SOSTENUTO_HELD,this.dispatchEvent("note",{part:e,note:n,velo:t(this,L)[h],state:this.NOTE_SOSTENUTO_HELD})):(t(this,B)[c]=0,t(this,L)[h]=0,t(this,G)[c]=this.NOTE_IDLE,this.dispatchEvent("note",{part:e,note:n,velo:0,state:this.NOTE_IDLE})))},nOn:(e,n,h)=>{let c=e*128+n,r=0;for(t(this,J)[e]&&t(this,N).ano(e);t(this,G)[r]>0&&t(this,B)[r]!=c;)r++;r<$.pl?(t(this,B)[r]=c,t(this,L)[c]=h,t(this,G)[r]=this.NOTE_SUSTAIN,t(this,oe)[e]{},cAt:(e,n)=>{},hoOf:e=>{t(this,G).forEach((n,h)=>{if(n==this.NOTE_HELD){let c=t(this,B)[h],r=c>>7;e==r&&(t(this,G)[h]=this.NOTE_IDLE,t(this,B)[h]=0,t(this,L)[c]=0,this.dispatchEvent("note",{part:e,note:c&127,velo:0,state:this.NOTE_IDLE}))}})},soOn:e=>{t(this,G).forEach((n,h)=>{let c;switch(n){case this.NOTE_ATTACK:{c=this.NOTE_SOSTENUTO_ATTACK;break}case this.NOTE_DECAY:{c=this.NOTE_SOSTENUTO_DECAY;break}case this.NOTE_SUSTAIN:{c=this.NOTE_SOSTENUTO_SUSTAIN;break}}if(c){t(this,G)[h]=c;let r=t(this,B)[h];this.dispatchEvent("note",{part:e,note:r&127,velo:t(this,L)[r],state:c})}})},soOf:e=>{t(this,G).forEach((n,h)=>{if(n==this.NOTE_SOSTENUTO_HELD){let c=t(this,B)[h],r=c>>7;e==r&&(t(this,G)[h]=this.NOTE_IDLE,t(this,B)[h]=0,t(this,L)[c]=0,this.dispatchEvent("note",{part:e,note:c&127,velo:0,state:this.NOTE_IDLE}))}})},ano:e=>{t(this,B).forEach((n,h,c)=>{let r=n>>7,a=n&127;n==0&&t(this,L)[0]==0||r==e&&t(this,N).nOff(r,a)})}});E(this,rt,{8:function(e){let n=e.channel,h=e.data[0];t(this,N).nOff(n,h)},9:function(e){let n=e.channel;t(this,U)[n]=1;let h=e.data[0],c=e.data[1];c>0?t(this,N).nOn(n,h,c):t(this,N).nOff(n,h)},10:function(e){let n=e.channel,h=n*128+e.data[0];t(this,B).indexOf(h)>-1&&(t(this,L)[h]=data[1],this.dispatchEvent("note",{part:n,note:e.data[0],velo:e.data[1],state:this.NOTE_SUSTAIN}))},11:function(e){let n=e.channel;[0,32].indexOf(e.data[0])>-1&&(()=>{switch(t(this,P)){case M.s90es:case M.motif:{if(e.data[0]==0){[0,63].indexOf(e.data[1])>-1&&(t(this,U)[n]=1);break}e.data[1]&&(t(this,U)[n]=1);break}default:{t(this,U)[n]=1;break}}})();let h=n*$.cc;switch(e.data[0]){case 96:return;case 97:return;case 120:return;case 121:{t(this,N).ano(n),t(this,we)[n]=0;let c=n*$.cc;t(this,p)[c+g[1]]=0,t(this,p)[c+g[5]]=0,t(this,p)[c+g[64]]=0,t(this,p)[c+g[65]]=0,t(this,p)[c+g[66]]=0,t(this,p)[c+g[67]]=0,t(this,p)[c+g[11]]=127,t(this,p)[c+g[101]]=127,t(this,p)[c+g[100]]=127,t(this,p)[c+g[99]]=127,t(this,p)[c+g[98]]=127;return}case 123:{t(this,N).ano(n);return}case 124:{t(this,N).ano(n);return}case 125:{t(this,N).ano(n);return}case 126:{t(this,J)[n]=1,t(this,N).ano(n);return}case 127:{t(this,J)[n]=0,t(this,N).ano(n);return}}if(g[e.data[0]]==null)console.warn(`cc${e.data[0]} is not accepted.`);else{switch(Er.indexOf(e.data[0])>-1&&this.allocateAce(e.data[0]),e.data[0]){case 0:{if(Y()&&console.debug(`${$e[t(this,P)]}, CH${n+1}: ${e.data[1]}`),t(this,P)==0)e.data[1]<48?(t(this,O)[n]>0&&(e.data[1]=t(this,p)[h],e.data[1]=120,console.debug(`Forced channel ${n+1} to stay drums.`)),e.data[1]>0&&(console.debug(`Roland GS detected with MSB: ${e.data[1]}`),this.switchMode("gs"))):e.data[1]==62?this.switchMode("x5d"):e.data[1]==63?this.switchMode("krs"):(e.data[1]==64||e.data[1]==127)&&this.switchMode("xg");else if(t(this,P)==M.gs)e.data[1]<56&&t(this,O)[n]>0&&(e.data[1]=t(this,p)[h],e.data[1]=120,console.debug(`Forced channel ${n+1} to stay drums.`));else if(t(this,P)==M.gm)e.data[1]<48?t(this,O)[n]>0&&(e.data[1]=120,this.switchMode("gs",!0),console.debug(`Forced channel ${n+1} to stay drums.`)):(e.data[1]==64||e.data[1]==127)&&this.switchMode("xg",!0);else if(t(this,P)==M.x5d){if(e.data[1]>0&&e.data[1]<8)this.switchMode("05rw",!0);else if(e.data[1]==56){let c=0;for(let r=0;r<16;r++){let a=t(this,p)[$.cc*r];(a==56||a==62)&&c++}c>14&&this.switchMode("ag10",!0)}}switch(t(this,P)){case M.xg:{[126,127].indexOf(e.data[1])>-1?t(this,O)[n]==0&&(this.setChType(n,this.CH_DRUM2),console.debug(`CH${n+1} set to drums by MSB.`)):t(this,O)[n]>0&&(this.setChType(n,this.CH_MELODIC),console.debug(`CH${n+1} set to melodic by MSB.`));break}case M["05rw"]:case M.x5d:case M.ns5r:{[61,62,126,127].indexOf(e.data[1])>-1?t(this,O)[n]==0&&(this.setChType(n,this.CH_DRUM2),console.debug(`CH${n+1} set to drums by MSB.`)):t(this,O)[n]>0&&(this.setChType(n,this.CH_MELODIC),console.debug(`CH${n+1} set to melodic by MSB.`));break}case M.g2:{e.data[1]==120?t(this,O)[n]==0&&(this.setChType(n,this.CH_DRUMS),console.debug(`CH${n+1} set to drums by MSB.`)):t(this,O)[n]>0&&(this.setChType(n,this.CH_MELODIC),console.debug(`CH${n+1} set to melodic by MSB.`));break}}this.dispatchEvent("voice",{part:n});break}case 6:{if(t(this,Ce)){[M.xg,M.gs,M.ns5r].indexOf(t(this,P))<0&&console.warn(`NRPN commits are not available under "${$e[t(this,P)]}" mode, even when they are supported in Octavia.`);let c=t(this,p)[h+g[99]],r=t(this,p)[h+g[98]];if(c==1){let a=mr.indexOf(r);if(a>-1)t(this,p)[h+g[71+a]]=e.data[1],Y()&&console.debug(`Redirected NRPN 1 ${r} to cc${71+a}.`),this.dispatchEvent("cc",{part:n,cc:71+a,data:e.data[1]});else{let o=qt.indexOf(r);o>-1?t(this,Fe)[n*10+o]=e.data[1]-64:console.warn(`NRPN 0x01${r.toString(16).padStart(2,"0")} is not supported.`),Y()&&console.debug(`CH${n+1} voice NRPN ${r} commit`)}}else{if(ct.indexOf(c)<0){let o=`NRPN 0x${c.toString(16).padStart(2,"0")}${r.toString(16).padStart(2,"0")} `;c==127?console.warn(`${o}is not necessary. Consider removing it.`):console.warn(`${o}is not supported.`)}else{let o=t(this,O)[n]-2;o<0?console.warn(`CH${n+1} cannot accept drum NRPN as type ${Ye[t(this,O)[n]]}.`):t(this,et)[(o*$.dpn+wt[c])*$.dnc+r]=e.data[1]-64}Y()&&console.debug(`CH${n+1} (${Ye[t(this,O)[n]]}) drum NRPN ${c} commit`)}}else{let c=yt[t(this,p)[h+g[100]]];t(this,p)[h+g[101]]==0&&c!=null&&(Y()&&console.debug(`CH${n+1} RPN 0 ${t(this,p)[h+g[100]]} commit: ${e.data[1]}`),e.data[1]=Math.min(Math.max(e.data[1],Kt[c][0]),Kt[c][1]),t(this,S)[n*$.rpn+c]=e.data[1])}break}case 32:{switch(t(this,P)){case M.s90es:case M.motif:{t(this,O)[n]=+([32,40].indexOf(e.data[1])>-1)<<1;break}}this.dispatchEvent("voice",{part:n});break}case 38:{t(this,Ce)||t(this,p)[h+101]==0&&yt[t(this,p)[h+100]]!=null&&(t(this,S)[n*$.rpn+yt[t(this,p)[h+100]]+1]=e.data[1]);break}case 64:{e.data[1]<64&&t(this,N).hoOf(n);break}case 66:{e.data[1]>>6?t(this,N).soOn(n):t(this,N).soOf(n);break}case 98:case 99:{w(this,Ce,1);break}case 100:case 101:{w(this,Ce,0);break}}t(this,p)[h+g[e.data[0]]]=e.data[1],this.dispatchEvent("cc",{part:n,cc:e.data[0],data:e.data[1]})}},12:function(e){let n=e.channel;switch(t(this,P)){case M.s90es:case M.motif:{e.data&&(t(this,U)[n]=1);break}default:t(this,U)[n]=1}t(this,D)[n]=e.data,t(this,ce)[n]=0,Y()&&console.debug(`T:${e.track} C:${n} P:${e.data}`),this.dispatchEvent("voice",{part:n})},13:function(e){let n=this,h=e.channel;t(this,B).forEach(function(c){let r=c>>7;h==r&&(t(n,L)[c]=e.data,n.dispatchEvent("note",{part:h,note:c&127,velo:e.data,state:n.NOTE_SUSTAIN}))})},14:function(e){let n=e.channel;t(this,we)[n]=e.data[1]*128+e.data[0]-8192,this.dispatchEvent("pitch",{part:n,pitch:this.getPitchShift(n)})},15:function(e){vr(e.data).forEach(n=>{let h=n[0],c=n[1];(t(this,ot)[h]||function(){console.debug(`Unknown manufacturer ${h}.`)})(c,n.subarray(2),e.track)})},248:function(e){},250:function(e){},251:function(e){},252:function(e){},254:function(e){},255:function(e){(t(this,_)[e.meta]||function(h,c,r){}).call(this,e.data,e.track,e.meta),e.meta!=32&&w(this,pe,0);let n=wr.indexOf(e.meta)>-1;if(Y()&&console.debug(e),n)return e.reply="meta",e}});E(this,ot,{64:(e,n,h)=>{t(this,Pe).run(n,h,e)},65:(e,n,h)=>{if(n[0]<16)t(this,he).run(n,h,e),console.warn("Unknown device SysEx!");else{let c=n[n.length-1],r=Vt(n.subarray(2,n.length-1));c==r?t(this,he).run(n.subarray(0,n.length-1),h,e):console.warn(`Bad GS checksum ${c}. Should be ${r}.`)}},66:(e,n,h)=>{t(this,ge).run(n,h,e)},67:(e,n,h)=>{t(this,Z).run(n,h,e)},68:(e,n,h)=>{t(this,Ie).run(n,h,e)},71:(e,n,h)=>{t(this,De).run(n,h,e)},126:(e,n,h)=>{t(this,Re).run(n,h,e)},127:(e,n,h)=>{this.switchMode("gm"),t(this,Oe).run(n,h,e)}});E(this,Re,void 0);E(this,Oe,void 0);E(this,Z,void 0);E(this,he,void 0);E(this,ge,void 0);E(this,Pe,void 0);E(this,De,void 0);E(this,Ie,void 0);let e=this;w(this,W,new Uint8Array(256),Yt),t(this,fe)[10]=new Uint8Array(512),w(this,Te,new se),this.userBank.strictMode=!0,this.userBank.load(`MSB PRG LSB NME
+062 000 000
+122 000 000
+122 001 000
+122 002 000
+122 003 000
+122 004 000
+122 005 000
+122 006 000 `),t(this,_)[1]=function(r){switch(r.slice(0,2)){case"@I":{w(this,I,!0),t(this,T).unshift(`Kar.Info: ${r.slice(2)}`);break}case"@K":{w(this,I,!0),t(this,T).unshift("Karaoke mode active."),console.debug(`Karaoke mode active: ${r.slice(2)}`);break}case"@L":{w(this,I,!0),t(this,T).unshift(`Language: ${r.slice(2)}`);break}case"@T":{w(this,I,!0),t(this,T).unshift(`Ka.Title: ${r.slice(2)}`);break}case"@V":{w(this,I,!0),t(this,T).unshift(`Kara.Ver: ${r.slice(2)}`);break}case"XF":{let a=r.slice(2).split(":");switch(a[0]){case"hd":{a.slice(1).forEach((o,i)=>{o.length&&t(this,T).unshift(`${["SongDate","SnRegion","SongCat.","SongBeat","SongInst","Sn.Vocal","SongCmp.","SongLrc.","SongArr.","SongPerf","SongPrg.","SongTags"][i]}: ${o}`)});break}case"ln":{a.slice(1).forEach((o,i)=>{o.length&&t(this,T).unshift(`${["Kar.Lang","Kar.Name","Kar.Cmp.","Kar.Lrc.","kar.Arr.","Kar.Perf","Kar.Prg."][i]}: ${o}`)});break}default:t(this,T).unshift(`XGF_Data: ${r}`)}break}default:t(this,I)?r[0]=="\\"?t(this,T).unshift(`@ ${r.slice(1)}`):r[0]=="/"?t(this,T).unshift(r.slice(1)):t(this,T)[0]+=r:(t(this,T)[0]=r,t(this,T).unshift(""))}},t(this,_)[2]=function(r){t(this,T).unshift(`Copyrite: ${r}`)},t(this,_)[3]=function(r,a){a<1&&t(this,pe)<1&&t(this,T).unshift(`TrkTitle: ${r}`)},t(this,_)[4]=function(r,a){t(this,T).unshift(`${Qt(t(this,pe),""," ")}Instrmnt: ${r}`)},t(this,_)[5]=function(r){r.trim()==""?t(this,T).unshift(""):t(this,T)[0]+=`${r}`},t(this,_)[6]=function(r){t(this,T).unshift(`${Qt(t(this,pe),""," ")}C.Marker: ${r}`)},t(this,_)[7]=function(r){t(this,T).unshift(`CuePoint: ${r}`)},t(this,_)[32]=function(r){w(this,pe,r[0]+1)},t(this,_)[33]=function(r,a){console.debug(`Track ${a} requests to get assigned to output ${r}.`),t(e,Se)[a]=r+1},t(this,_)[81]=function(r,a){w(e,Xe,r/1e3)},t(this,_)[127]=function(r,a){t(e,Te).run(r,a)},t(this,Te).default=function(r){console.warn(`Unrecognized sequencer-specific byte sequence: ${r}`)},t(this,Te).add([67,0,1],function(r,a){t(e,Se)[a]=r[0]+1}),w(this,Re,new se("universal non-realtime")),w(this,Oe,new se("universal realtime")),w(this,Z,new se("Yamaha")),w(this,he,new se("Roland")),w(this,ge,new se("Korg")),w(this,Pe,new se("Kawai")),w(this,De,new se("Akai")),w(this,Ie,new se("Casio"));let n=function(r){console.info(`Unrecognized SysEx in "${this.name}" set.`,r)};t(this,Re).default=n,t(this,Oe).default=n,t(this,Z).default=n,t(this,he).default=n,t(this,ge).default=n,t(this,Pe).default=n,t(this,De).default=n,t(this,Ie).default=n,t(this,Re).add([9],r=>{e.switchMode(["gm","?","g2"][r[0]-1],!0),w(e,I,t(e,I)||!1),console.info(`MIDI reset: ${["GM","Init","GM2"][r[0]-1]}`),r[0]==2&&e.init()}),t(this,Oe).add([4,1],r=>{w(e,X,((r[1]<<7)+r[0])/16383*100)}).add([4,3],r=>((r[1]<<7)+r[0]-8192)/8192).add([4,4],r=>r[1]-64),t(this,Z).add([76,0,0],r=>{switch(r[0]){case 125:{console.info(`XG drum setup reset: ${r}`);break}case 126:{e.switchMode("xg",!0),w(e,I,!1),console.info("MIDI reset: XG");break}default:{let a=[0,0,0,0],o=(i,s)=>{a[s]=i};if(r.subarray(1).forEach((i,s)=>{let f=s+r[0];([o,o,o,o,l=>{w(this,X,l*129/16383*100)},l=>{},l=>{}][f]||(()=>{}))(i,s)}),r[0]<4){let i=0;a.forEach(s=>{i=i<<4,i+=s}),i-=1024}}}}).add([76,2,1],r=>{let a="XG ";r[0]<32?(a+="reverb ",r.subarray(1).forEach((o,i)=>{([s=>{e.setEffectTypeRaw(0,!1,s),console.info(`${a}main type: ${We[s]}`)},s=>{e.setEffectTypeRaw(0,!0,s),console.debug(`${a}sub type: ${s+1}`)},s=>{console.debug(`${a}time: ${At(s)}s`)},s=>{console.debug(`${a}diffusion: ${s}`)},s=>{console.debug(`${a}initial delay: ${s}`)},s=>{console.debug(`${a}HPF cutoff: ${_e[s]}Hz`)},s=>{console.debug(`${a}LPF cutoff: ${_e[s]}Hz`)},s=>{console.debug(`${a}width: ${s}`)},s=>{console.debug(`${a}height: ${s}`)},s=>{console.debug(`${a}depth: ${s}`)},s=>{console.debug(`${a}wall type: ${s}`)},s=>{console.debug(`${a}dry/wet: ${s}`)},s=>{console.debug(`${a}send: ${q(s)}dB`)},s=>{console.debug(`${a}pan: ${s-64}`)},!1,!1,s=>{console.debug(`${a}delay: ${s}`)},s=>{console.debug(`${a}density: ${s}`)},s=>{console.debug(`${a}balance: ${s}`)},s=>{},s=>{console.debug(`${a}feedback: ${s}`)},s=>{}][r[0]+i]||function(){console.warn(`Unknown XG reverb address: ${r[0]}.`)})(o)})):r[0]<64?(a+="chorus ",r.subarray(1).forEach((o,i)=>{([s=>{e.setEffectTypeRaw(1,!1,s),console.info(`${a}main type: ${We[s]}`)},s=>{e.setEffectTypeRaw(1,!0,s),console.debug(`${a}sub type: ${s+1}`)},s=>{console.debug(`${a}LFO: ${It[s]}Hz`)},s=>{},s=>{console.debug(`${a}feedback: ${s}`)},s=>{console.debug(`${a}delay offset: ${Ut(s)}ms`)},s=>{},s=>{console.debug(`${a}low: ${_e[s]}Hz`)},s=>{console.debug(`${a}low: ${s-64}dB`)},s=>{console.debug(`${a}high: ${_e[s]}Hz`)},s=>{console.debug(`${a}high: ${s-64}dB`)},s=>{console.debug(`${a}dry/wet: ${s}`)},s=>{console.debug(`${a}send: ${q(s)}dB`)},s=>{console.debug(`${a}pan: ${s-64}`)},s=>{console.debug(`${a}to reverb: ${q(s)}dB`)},!1,s=>{},s=>{},s=>{},s=>{console.debug(`${a}LFO phase diff: ${(s-64)*3}deg`)},s=>{console.debug(`${a}input mode: ${s?"stereo":"mono"}`)},s=>{}][r[0]-32+i]||function(){console.warn(`Unknown XG chorus address: ${r[0]}.`)})(o)})):r[0]<86?(a+="variation ",r.subarray(1).forEach((o,i)=>{([s=>{e.setEffectTypeRaw(2,!1,s),console.info(`${a}main type: ${We[s]}`)},s=>{e.setEffectTypeRaw(2,!0,s),console.debug(`${a}sub type: ${s+1}`)}][r[0]-64+i]||function(){})(o)})):r[0]<97?(a+="variation ",r.subarray(1).forEach((o,i)=>{[s=>{console.debug(`${a}send: ${q(s)}dB`)},s=>{console.debug(`${a}pan: ${s-64}`)},s=>{console.debug(`${a}to reverb: ${q(s)}dB`)},s=>{console.debug(`${a}to chorus: ${q(s)}dB`)},s=>{console.debug(`${a}connection: ${s?"system":"insertion"}`)},s=>{console.debug(`${a}channel: CH${s+1}`)},s=>{console.debug(`${a}mod wheel: ${s-64}`)},s=>{console.debug(`${a}bend wheel: ${s-64}`)},s=>{console.debug(`${a}channel after touch: ${s-64}`)},s=>{console.debug(`${a}AC1: ${s-64}`)},s=>{console.debug(`${a}AC2: ${s-64}`)}][r[0]-86+i](o)})):r[0]>111&&r[0]<118?a+="variation ":console.warn(`Unknown XG variation address: ${r[0]}`)}).add([76,2,64],r=>{r.subarray(1).forEach((a,o)=>{let i=o+r[0];if(i==0)console.debug(`XG EQ preset: ${["flat","jazz","pop","rock","classic"][a]}`);else{let s=i-1>>2,f=i-1&3,l=`XG EQ ${s} ${["gain","freq","Q","shape"][f]}: `;[()=>{console.debug(`${l}${a-64}dB`)},()=>{console.debug(`${l}${a} (raw)`)},()=>{console.debug(`${l}${a/10}`)},()=>{console.debug(`${l}${["shelf","peak"][+!!a]}`)}][f]()}})}).add([76,3],r=>{let a=r[0],o=r[1],i=`XG Insertion ${r[0]+1} `;r.subarray(2).forEach((s,f)=>{([l=>{e.setEffectTypeRaw(3+a,!1,l),console.info(`${i}main type: ${We[l]}`)},l=>{e.setEffectTypeRaw(3+a,!0,l),console.debug(`${i}sub type: ${l+1}`)}][o+f]||function(){})(s)})}).add([76,6,0],r=>{let a=r[0];a<64?e.setLetterDisplay(r.subarray(1),"XG letter display",a):w(e,ke,Date.now())}).add([76,7,0],r=>{let a=r[0];w(e,j,0),w(e,ne,Date.now()+3200),t(e,W,de).fill(0);let o=r.subarray(1);for(let i=0;i>6-y&1,y++})}).add([76,8],(r,a)=>{let o=e.chRedir(r[0],a,!0),i=r[1],s=$.cc*o,f=`XG CH${o+1} `,l=`Unknown XG part address ${i}.`;r.subarray(2).forEach((d,b)=>{i<1?console.debug(l):i<41?([()=>{t(e,p)[s+g[0]]=d},()=>{t(e,p)[s+g[32]]=d},()=>{t(e,D)[o]=d},()=>{let y=e.chRedir(d,a,!0);t(e,H)[o]=y,o!=y&&(e.buildRchTree(),console.info(`${f}receives from CH${y+1}`))},()=>{t(e,J)[o]=+!d},()=>{},()=>{e.setChType(o,d,M.xg),console.debug(`${f}type: ${Ye[d]||d}`)},()=>{t(e,S)[$.rpn*o+3]=d},!1,!1,()=>{t(e,p)[s+g[7]]=d},!1,!1,()=>{t(e,p)[s+g[10]]=d||128},!1,!1,()=>{t(e,p)[s+g[128]]=d},()=>{t(e,p)[s+g[93]]=d},()=>{t(e,p)[s+g[91]]=d},()=>{t(e,p)[s+g[94]]=d},()=>{t(e,p)[s+g[76]]=d},()=>{t(e,p)[s+g[77]]=d},()=>{t(e,p)[s+g[78]]=d},()=>{t(e,p)[s+g[74]]=d},()=>{t(e,p)[s+g[71]]=d},()=>{t(e,p)[s+g[73]]=d},()=>{t(e,p)[s+g[75]]=d},()=>{t(e,p)[s+g[72]]=d}][i+b-1]||(()=>{}))():i<48?console.debug(l):i<111?i>102&&i<105&&(t(e,p)[s+g[[5,65][i&1]]]=d):i<114?console.debug(l):i<116?console.debug(`${f}EQ ${["bass","treble"][i&1]} gain: ${d-64}dB`):i<118?console.debug(l):i<120?console.debug(`${f}EQ ${["bass","treble"][i&1]} freq: ${d}`):console.debug(l)})}).add([76,9],(r,a)=>{let o=e.chRedir(r[0],a,!0),i=r[1],s=`PLG-150VL CH${o+1} `;r.subarray(2).forEach((f,l)=>{let d=l+i;switch(d){case 1:{console.info(`${s}breath mode: ${["system","breath","velocity","touch EG"][f]}`);break}case 0:case 27:case 28:break;default:if(d<27){let b=["pressure","embouchure","tonguing","scream","breath noise","growl","throat formant","harmonic enhancer","damping","absorption","amplification","brightness"][d-3>>1];d&1?d<23?(console.debug(`${s}${b} control source: ${Nt(f)}`),f&&f<96&&e.allocateAce(f)):console.debug(`${s}${b} scale break point: ${f}`):console.debug(`${s}${b} depth: ${f-64}`)}}})}).add([76,10],r=>{}).add([76,16],r=>{}).add([76,17,0,0],r=>{}).add([76,112],r=>{console.debug(`XG enable PLG-1${["50VL","00SG","50DX"][r[0]]} for CH${r[2]+1}.`)}).add([73,0,0],(r,a)=>{let o=r[0];r.subarray(1).forEach((i,s)=>{let f=o+s;f==8?console.debug(`MU1000 set LCD contrast to ${i}.`):f>9&&f<16&&[()=>{e.dispatchEvent("channelactive",i)},()=>{i<8?(e.dispatchEvent("channelmin",i<<4),console.info(`Octavia System: Minimum CH${(i<<4)+1}`)):(e.dispatchEvent("channelreset"),console.info("Octavia System: Clear channel ranges"))},()=>{i<8?(e.dispatchEvent("channelmax",(i<<4)+15),console.info(`Octavia System: Maximum CH${(i<<4)+16}`)):(e.dispatchEvent("channelreset"),console.info("Octavia System: Clear channel ranges"))},()=>{e.dispatchEvent("channelreset"),console.info("Octavia System: Clear channel ranges")},()=>{w(e,re,!!i),console.info(`Octavia System: RS receiving ${["dis","en"][i]}abled.`)}][f-10]()})}).add([73,10,0],(r,a)=>{let o=r[0],i=`MU1000 RS${t(e,re)?"":" (ignored)"}: `;if(o<16)switch(o){case 2:{let s=e.chRedir(0,a,!0);t(e,re)&&(e.dispatchEvent("channelmin",s),e.dispatchEvent("channelmax",s+63)),console.info(`${i}Show CH1~64`);break}case 3:{let s=e.chRedir(r[1]<<5,a,!0);t(e,re)&&e.dispatchEvent("channelmin",s),t(e,re)&&e.dispatchEvent("channelmax",s+31),console.info(`${i}Show CH${s+1}~CH${s+32}`);break}default:console.debug(`${i}unknown switch ${o} invoked.`)}else if(o<32){if(t(e,re)){let s=e.chRedir(o-16+(t(e,Ke)<<4),a,!0);e.dispatchEvent("channelactive",s)}}else if(o<36){let s=e.chRedir(o-32<<4,a,!0);t(e,re)&&(e.dispatchEvent("channelmin",s),e.dispatchEvent("channelmax",s+15),w(e,Ke,o-32)),console.info(`${i}Show CH${s+1}~CH${s+16}`)}}).add([93,3],(r,a)=>{let o=e.chRedir(r[0],a,!0),i=`PLG-100SG CH${o+1} `,s=Date.now();if(r[1]==0){let f="",l=0;r.subarray(2).forEach((d,b)=>{b%2==0?f+=Lt[d]||d.toString().padStart("0"):l+=d*13}),s>=t(e,ze)&&t(e,T).unshift("SG Lyric: "),t(e,T)[0]+=`${Bt(f)}`,w(e,ze,s+Math.ceil(l/2)+t(e,Xe)),Y()&&console.debug(`${i}vocals: ${f}`)}else console.warn(`Unknown PLG-100SG data: ${r}`)}),t(this,Z).add([76,48],r=>{}).add([76,49],r=>{}).add([76,50],r=>{}).add([76,51],r=>{}),t(this,Z).add([89,0],(r,a,o)=>{if(e.eprom){let i=r[0],s=(r[1]<<14)+(r[2]<<7)+r[3]+(e.eprom.offset||0);Y()&&console.debug(`MU1000 EPROM trail to 0x${s.toString(16).padStart(6,"0")}, ${i} bytes.`);let f=e.eprom.data;r.subarray(4).forEach((l,d)=>{let b=d>>3,y=d&7;if(y==7)for(let k=0;k<7;k++)f[s+7*b+k]+=(l>>6-k&1)<<7;else f[s+7*b+y]=l})}}).add([89,1],(r,a,o)=>{let i=(r[0]<<21)+(r[1]<<14)+(r[2]<<7)+r[3];Y()&&console.debug(`MU1000 EPROM jump to 0x${i.toString(16).padStart(6,"0")}.`),e.eprom&&(e.eprom.offset=i)}).add([89,2],(r,a,o)=>{if(e.eprom){let i=(r[0]<<21)+(r[1]<<14)+(r[2]<<7)+r[3]+(e.eprom.offset||0);Y()&&console.debug(`MU1000 EPROM write to 0x${i.toString(16).padStart(6,"0")}.`);let s=e.eprom.data;r.subarray(4).forEach((f,l)=>{let d=l>>3,b=l&7;if(b==7)for(let y=0;y<7;y++)s[i+7*d+y]+=(f>>6-y&1)<<7;else s[i+7*d+b]=f})}}).add([89,3],(r,a,o)=>{}),t(this,Z).add([39,48],(r,a,o)=>{}).add([43,0,0],(r,a,o)=>{let i=[0,0,0,0],s=(f,l)=>{i[l]=f};if(r.subarray(1).forEach((f,l)=>{let d=l+r[0];[s,s,s,s,()=>{w(this,X,f*129/16383*100)},()=>f-64,()=>f||128,()=>f,()=>f,()=>{console.debug(`TG300 variation on cc${f}.`)}][d](f,d)}),r[0]<4){let f=0;i.forEach(l=>{f=f<<4,f+=l}),f-=1024}}).add([43,1,0],(r,a,o)=>{}).add([43,2],(r,a,o)=>{let i=e.chRedir(r[0],a,!0),s=r[1],f=$.cc*i,l=`TG300 CH${i+1} `;r.subarray(2).forEach((d,b)=>{b<5?([()=>{},()=>{t(e,p)[f+g[0]]=d},()=>{t(e,p)[f+g[32]]=d},()=>{t(e,D)[i]=d},()=>{let y=e.chRedir(d,a,!0);t(e,H)[i]=y,i!=y&&(e.buildRchTree(),console.info(`${l}receives from CH${y+1}`))}][b+s]||(()=>{}))(d,b+s):b<21||(b<47?([()=>{t(e,J)[i]=+!d},()=>{},()=>{},()=>{t(e,S)[$.rpn*i+3]=d},()=>{},()=>{t(e,p)[f+g[7]]=d},!1,!1,()=>{t(e,p)[f+g[10]]=d||128},!1,!1,()=>{console.debug(`${l} AC1 at cc${d}`)},()=>{console.debug(`${l} AC2 at cc${d}`)},()=>{t(e,p)[f+g[128]]=d},()=>{t(e,p)[f+g[93]]=d},()=>{t(e,p)[f+g[91]]=d},()=>{t(e,p)[f+g[94]]=d},()=>{t(e,p)[f+g[76]]=d},()=>{t(e,p)[f+g[77]]=d},()=>{t(e,p)[f+g[74]]=d},()=>{t(e,p)[f+g[71]]=d},()=>{t(e,p)[f+g[73]]=d},()=>{t(e,p)[f+g[75]]=d},()=>{t(e,p)[f+g[72]]=d},()=>{t(e,p)[f+g[78]]=d}][b+s-21]||(()=>{}))(d,b+s):b<95||([()=>{t(e,p)[f+g[65]]=d},()=>{t(e,p)[f+g[5]]=d}][b+s-95]||(()=>{}))(d,b+s))})}).add([43,7,0],(r,a,o)=>{let i=r[0];e.setLetterDisplay(r.subarray(1),"TG300 letter display",i)}).add([43,7,1],(r,a,o)=>{w(e,j,0),w(e,ne,Date.now()+3200),t(e,W,de).fill(0),r.forEach(function(i,s){let f=Math.floor(s/16),l=s%16,d=(l*3+f)*7,b=7,y=0;for(d-=l*5,f==2&&(b=2);y>6-y&1,y++})}),t(this,he).add([66,18,0,0,127],(r,a,o)=>{e.switchMode("gs",!0),t(e,p)[$.cc*9]=120,t(e,p)[$.cc*25]=120,t(e,p)[$.cc*41]=120,t(e,p)[$.cc*57]=120,w(e,te,3),w(e,I,!1),t(e,be).fill(0),console.info(`GS system to ${["single","dual"][r[0]]} mode.`)}).add([66,18,64,0],(r,a,o)=>{switch(r[0]){case 127:{e.switchMode("gs",!0),t(e,p)[$.cc*9]=120,t(e,p)[$.cc*25]=120,t(e,p)[$.cc*41]=120,t(e,p)[$.cc*57]=120,w(e,I,!1),t(e,be).fill(0),console.info("MIDI reset: GS");break}default:{let i=[0,0,0,0],s=(f,l)=>{i[l]=f};if(r.subarray(1).forEach((f,l)=>{let d=l+r[0];[s,s,s,s,b=>{w(this,X,b*129/16383*100)},b=>{},b=>{}][d](f,l)}),r[0]<4){let f=0;i.forEach(l=>{f=f<<4,f+=l}),f-=1024}}}}).add([66,18,64,1],r=>{let a=r[0];if(a<16){let o="".padStart(a," ");r.subarray(1).forEach((i,s)=>{o+=String.fromCharCode(Math.max(32,i))}),o=o.padEnd(16," "),console.debug(`GS patch name: ${o}`)}else a<48||(a<65?r.subarray(1).forEach((o,i)=>{let s=`GS ${a+i>55?"chorus":"reverb"} `;([()=>{console.info(`${s}type: ${pt[o]}`),e.setEffectType(0,40,o)},()=>{},()=>{},()=>{},()=>{},()=>{},!1,()=>{console.debug(`${s}predelay: ${o}ms`)},()=>{console.info(`${s}type: ${Ht[o]}`),e.setEffectType(1,40,16+o)},()=>{},()=>{},()=>{},()=>{},()=>{},()=>{},()=>{console.debug(`${s}to reverb: ${q(o)}`)},()=>{console.debug(`${s}to delay: ${q(o)}`)}][a+i-48]||(()=>{}))()}):a<80?console.debug(`Unknown GS patch address: ${a}`):a<91?r.subarray(1).forEach((o,i)=>{let s="GS delay ";([()=>{console.info(`${s}type: ${Gt[o]}`),e.setEffectType(2,40,32+o)},()=>{},()=>{},()=>{},()=>{},()=>{},()=>{},()=>{},()=>{},()=>{},()=>{console.debug(`${s}to reverb: ${q(o)}`)}][a+i-80]||(()=>{}))()}):console.debug(`Unknown GS patch address: ${a}`))}).add([66,18,64,2],r=>{let a="GS EQ ";r.subarray(1).forEach((o,i)=>{([()=>{console.debug(`${a}low freq: ${[200,400][o]}Hz`)},()=>{console.debug(`${a}low gain: ${o-64}dB`)},()=>{console.debug(`${a}high freq: ${[3e3,6e3][o]}Hz`)},()=>{console.debug(`${a}high gain: ${o-64}dB`)}][r[0]+i]||function(){console.warn(`Unknown GS EQ address: ${r[0]+i}`)})()})}).add([66,18,64,3],r=>{let a="GS EFX ",o=function(i,s){let f=_t(t(e,Q).subarray(10,12),s,i);f&&console.debug(`${a}${bt(t(e,Q).subarray(10,12))} ${f}`)};r.subarray(1).forEach((i,s)=>{([()=>{e.setEffectTypeRaw(3,!1,32+i)},()=>{e.setEffectTypeRaw(3,!0,i),console.info(`${a}type: ${bt(t(e,Q).subarray(10,12))}`)},!1,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,()=>{console.debug(`${a}to reverb: ${q(i)}dB`)},()=>{console.debug(`${a}to chorus: ${q(i)}dB`)},()=>{console.debug(`${a}to delay: ${q(i)}dB`)},!1,()=>{console.debug(`${a}1 source: ${i}`),i&&i<96&&e.allocateAce(i)},()=>{console.debug(`${a}1 depth: ${i-64}`)},()=>{console.debug(`${a}2 source: ${i}`),i&&i<96&&e.allocateAce(i)},()=>{console.debug(`${a}2 depth: ${i-64}`)},()=>{console.debug(`${a}to EQ: ${i?"ON":"OFF"}`)}][r[0]+s]||function(f,l){console.warn(`Unknown GS EFX address: ${l}`)})(i,r[0]+s)})}).add([66,18,65],r=>{}).add([69,18,16],r=>{var a;switch(r[0]){case 0:{let o=r[1];e.setLetterDisplay(r.subarray(2),"GS display text",o);break}case 32:{w(e,ne,Date.now()+3200),r[1]==0&&w(e,j,Math.max(Math.min(r[2]-1,9),0));break}default:if(r[0]<11){t(e,j)>9&&w(e,j,0),w(e,ne,Date.now()+3200),(a=t(e,fe)[r[0]-1])!=null&&a.length||(t(e,fe)[r[0]-1]=new Uint8Array(256));let o=t(e,fe)[r[0]-1],i=r[1];o.fill(0);let s=r.subarray(2);for(let f=0;f>4-v&1,v++})}else console.warn(`Unknown GS display section: ${r[0]}`)}});let h=function(r,a,o){let i=r[0],s=$.cc*a,f=$.rpn*a,l=`GS CH${a+1} `;i<3?r.subarray(1).forEach((d,b)=>{[()=>{t(e,p)[s+g[0]]=d},()=>{t(e,D)[a]=d},()=>{let y=e.chRedir(d,o,!0);t(e,H)[a]=y,a!=y&&(e.buildRchTree(),console.info(`${l}receives from CH${y+1}`))}][i+b]()}):i<19||(i<44?r.subarray(1).forEach((d,b)=>{([()=>{t(e,J)[a]=+!d},!1,()=>{e.setChType(a,d<<1,M.gs),console.debug(`${l}type: ${d?"drum ":"melodic"}${d||""}`)},()=>{t(e,S)[f+3]=d},!1,()=>{t(e,p)[s+g[7]]=d},!1,!1,()=>{t(e,p)[s+g[10]]=d||128},!1,!1,()=>{console.debug(`${l}CC 1: cc${d}`)},()=>{console.debug(`${l}CC 2: cc${d}`)},()=>{t(e,p)[s+g[93]]=d},()=>{t(e,p)[s+g[91]]=d},!1,!1,()=>{t(e,S)[f+1]=d},()=>{t(e,S)[f+2]=d},()=>{t(e,p)[s+g[94]]=d}][i+b-19]||(()=>{}))()}):i<76||console.debug(`Unknown GS part address: ${i}`))},c=function(r,a){let o=r[0],i=`GS CH${a+1} `;o<2?r.subarray(1).forEach((s,f)=>{[()=>{t(e,p)[$.cc*a+g[32]]=s},()=>{}][o+f]()}):o<32?console.warn(`Unknown GS misc address: ${o}`):o<35?r.subarray(1).forEach((s,f)=>{[()=>{console.debug(`${i}EQ: o${["ff","n"][s]}`)},()=>{},()=>{console.debug(`${i}EFX: o${["ff","n"][s]}`)}][o+f-32]()}):console.warn(`Unknown GS misc address: ${o}`)};t(this,he).add([66,18,64,16],(r,a)=>{h(r,e.chRedir(9,a,!0),a)}).add([66,18,64,17],(r,a)=>{h(r,e.chRedir(0,a,!0),a)}).add([66,18,64,18],(r,a)=>{h(r,e.chRedir(1,a,!0),a)}).add([66,18,64,19],(r,a)=>{h(r,e.chRedir(2,a,!0),a)}).add([66,18,64,20],(r,a)=>{h(r,e.chRedir(3,a,!0),a)}).add([66,18,64,21],(r,a)=>{h(r,e.chRedir(4,a,!0),a)}).add([66,18,64,22],(r,a)=>{h(r,e.chRedir(5,a,!0),a)}).add([66,18,64,23],(r,a)=>{h(r,e.chRedir(6,a,!0),a)}).add([66,18,64,24],(r,a)=>{h(r,e.chRedir(7,a,!0),a)}).add([66,18,64,25],(r,a)=>{h(r,e.chRedir(8,a,!0),a)}).add([66,18,64,26],(r,a)=>{h(r,e.chRedir(10,a,!0),a)}).add([66,18,64,27],(r,a)=>{h(r,e.chRedir(11,a,!0),a)}).add([66,18,64,28],(r,a)=>{h(r,e.chRedir(12,a,!0),a)}).add([66,18,64,29],(r,a)=>{h(r,e.chRedir(13,a,!0),a)}).add([66,18,64,30],(r,a)=>{h(r,e.chRedir(14,a,!0),a)}).add([66,18,64,31],(r,a)=>{h(r,e.chRedir(15,a,!0),a)}).add([66,18,64,64],(r,a)=>{c(r,e.chRedir(9,a,!0))}).add([66,18,64,65],(r,a)=>{c(r,e.chRedir(0,a,!0))}).add([66,18,64,66],(r,a)=>{c(r,e.chRedir(1,a,!0))}).add([66,18,64,67],(r,a)=>{c(r,e.chRedir(2,a,!0))}).add([66,18,64,68],(r,a)=>{c(r,e.chRedir(3,a,!0))}).add([66,18,64,69],(r,a)=>{c(r,e.chRedir(4,a,!0))}).add([66,18,64,70],(r,a)=>{c(r,e.chRedir(5,a,!0))}).add([66,18,64,71],(r,a)=>{c(r,e.chRedir(6,a,!0))}).add([66,18,64,72],(r,a)=>{c(r,e.chRedir(7,a,!0))}).add([66,18,64,73],(r,a)=>{c(r,e.chRedir(8,a,!0))}).add([66,18,64,74],(r,a)=>{c(r,e.chRedir(10,a,!0))}).add([66,18,64,75],(r,a)=>{c(r,e.chRedir(11,a,!0))}).add([66,18,64,76],(r,a)=>{c(r,e.chRedir(12,a,!0))}).add([66,18,64,77],(r,a)=>{c(r,e.chRedir(13,a,!0))}).add([66,18,64,78],(r,a)=>{c(r,e.chRedir(14,a,!0))}).add([66,18,64,79],(r,a)=>{c(r,e.chRedir(15,a,!0))}),t(this,ge).add([54,65],(r,a)=>{e.switchMode("x5d");let o=(r[1]<<7)+r[0],i=(r[3]<<7)+r[2],s=e.chRedir(o&15,a,!0),f=$.cc*s;[()=>{i<1||(i<101?(e.setChType(s,e.CH_MELODIC,M.x5d),t(e,D)[s]=i-1,t(e,p)[f+g[0]]=82):i<229?(e.setChType(s,e.CH_MELODIC,M.x5d),t(e,D)[s]=i-101,t(e,p)[f+g[0]]=56):(e.setChType(s,e.CH_DRUMS,M.x5d),t(e,D)[s]=jt[i-229]||0,t(e,p)[f+g[0]]=62))},()=>{t(e,p)[f+g[7]]=i},()=>{i<31&&(t(e,p)[f+g[10]]=Math.round((i-15)*4.2+64))},()=>{t(e,p)[f+g[93]]=Ze(i)},()=>{t(e,p)[f+g[91]]=Ze(i)},()=>{t(e,S)[s*$.rpn+3]=i>8191?i-16320:64+i},()=>{t(e,S)[s*$.rpn+1]=i>8191?i-16320:64+i},()=>{i>0&&(t(e,S)[s*$.rpn]=i)},()=>{}][o>>4]()}).add([54,76,0],(r,a)=>{e.switchMode("x5d",!0);let o="",i=82,s=0,f=0,l="MSB PRG LSB NME";ie(r,function(d,b){if(b<16400){let y=b%164;switch(!0){case y<10:{d>31&&(o+=String.fromCharCode(d));break}case y==11:{l+=`
+${i} ${s} ${f} ${o.trim().replace("Init Voice","")}`,s++,o="";break}}s>99&&(i=90,s=0)}}),e.userBank.clearRange({msb:82,prg:[0,99],lsb:0}),e.userBank.load(l)}).add([54,77,0],(r,a)=>{e.switchMode("x5d",!0);let o="",i=90,s=0,f=0,l="MSB PRG LSB NME";ie(r,function(d,b){if(b<13600){let y=b%136;switch(!0){case y<10:{d>31&&(o+=String.fromCharCode(d));break}case y==11:{l+=`
+${i} ${s} ${f} ${o.trim().replace("Init Combi","")}`,s++,o="";break}}}}),e.userBank.clearRange({msb:90,prg:[0,99],lsb:0}),e.userBank.load(l)}).add([54,78],(r,a)=>{e.switchMode("x5d",!0),console.debug(`X5D mode switch requested: ${["combi","combi edit","prog","prog edit","multi","global"][r[0]]} mode.`)}).add([54,85],(r,a)=>{e.switchMode("x5d",!0),ie(r,(o,i)=>{i>0&&i<3&&e.setEffectType(i-1,44,o)})}).add([54,104],(r,a)=>{e.switchMode("x5d",!0),ie(r,function(o,i,s,f){if(i<192){let l=e.chRedir(Math.floor(i/12),a,!0),d=l*$.cc;switch(i%12){case 0:{o<128?(e.setChType(l,e.CH_MELODIC,M.x5d),t(e,p)[d+g[0]]=82,t(e,D)[l]=o):(e.setChType(l,e.CH_DRUMS,M.x5d),t(e,p)[d+g[0]]=62,t(e,D)[l]=jt[o-128]),o>0&&(t(e,U)[l]=1);break}case 1:{t(e,p)[d+g[7]]=o;break}case 2:{t(e,S)[l*$.rpn+3]=o>127?o-192:64+o;break}case 3:{t(e,S)[l*$.rpn+1]=o>127?o-192:64+o;break}case 4:{o<31&&(t(e,p)[d+g[10]]=Math.round((o-15)*4.2+64));break}case 5:{let b=o>>4,y=o&15;t(e,p)[d+g[91]]=Ze(y),t(e,p)[d+g[93]]=Ze(b);break}case 10:break;case 11:{let b=e.chRedir(o&15,a,!0),y=o>>4;t(e,H)[l]=o,(b!=l||y)&&(console.info(`X5D Part CH${l+1} receives from CH${b+1}.`),e.buildRchTree())}}}else{let l=e.chRedir(i-192,a,!0)}})}),t(this,he).add([22,18,127],r=>{e.switchMode("mt32",!0),w(e,I,!1),e.userBank.clearRange({msb:0,lsb:127,prg:[0,127]}),console.info("MIDI reset: MT-32")}).add([22,18,0],(r,a,o)=>{e.switchMode("mt32");let i=e.chRedir(o,a,!0),s=r[1];r.subarray(2).forEach((f,l)=>{let d=l+s;t(e,Ee)[d+(i-1)*16]=f,([!1,()=>{let b=t(e,Ee)[i-1<<4];if(b<3)if(t(e,ce)[i]=1,b==2)for(let y=0;y{t(e,S)[i*$.rpn+3]=f+40},()=>{t(e,S)[i*$.rpn+1]=f+14},()=>{t(e,S)[i*$.rpn]=f},!1,()=>{t(e,p)[$.cc*i+g[91]]=f?127:0},!1,()=>{t(e,p)[$.cc*i+g[7]]=f},()=>{t(e,p)[$.cc*i+g[10]]=Math.ceil(f*9.05)}][d]||(()=>{}))()})}).add([22,18,1],(r,a,o)=>{e.switchMode("mt32");let i=e.chRedir(o,a,!0)}).add([22,18,2],(r,a,o)=>{e.switchMode("mt32");let i=e.chRedir(o,a,!0),s=r[1]+(r[0]<<7);s<10&&(t(e,ce)[i]=1),r.subarray(2).forEach((f,l)=>{let d=l+s;d<14&&(t(e,ee)[(i-1)*$.cmt+d]=f)})}).add([22,18,3],(r,a,o)=>{if(e.switchMode("mt32"),r[0]){let i=r[1]-16}else{let i=r[1];r.subarray(2).forEach((s,f)=>{let l=f+i;t(e,Ee)[l]=s;let d=e.chRedir(1+l>>4,a,!0),b=l&15;([!1,()=>{let y=t(e,Ee)[d-1<<4];if(y<3)if(t(e,ce)[d]=1,y==2)for(let k=0;k{t(e,S)[d*$.rpn+3]=s+40},()=>{t(e,S)[d*$.rpn+1]=s+14},()=>{t(e,S)[d*$.rpn]=s},!1,()=>{t(e,p)[$.cc*d+g[91]]=s?127:0},!1,()=>{t(e,p)[$.cc*d+g[7]]=s},()=>{t(e,p)[$.cc*d+g[10]]=Math.ceil(s*9.05)}][b]||(()=>{}))()})}}).add([22,18,4],(r,a,o)=>{e.switchMode("mt32");let i=r[1]+(r[0]<<7);r.subarray(2).forEach((s,f)=>{let l=f+i,d=e.chRedir(Math.floor(l/246+1),a,!0),b=l%246;b<14&&(t(e,ee)[(d-1)*$.cmt+b]=s),b<10&&(t(e,ce)[d]=1)})}).add([22,18,5],(r,a,o)=>{e.switchMode("mt32");let i=(r[0]<<7)+r[1];r.subarray(2).forEach((s,f)=>{let l=i+f,d=Math.floor(l/8),b=l&7,y=d*8;t(e,Ve)[l]=s,([!1,()=>{let k=t(e,Ve)[y];if(k<3){let v="";if(k==2){let m=$.cmt*d;v=`MT-m:${s.toString().padStart(3,"0")}`}else v=e.baseBank.get(0,s+(k<<6),127,"mt32").name;e.userBank.clearRange({msb:0,lsb:127,prg:d}),e.userBank.load(`MSB LSB PRG NME
+000 127 ${d} ${v}`,!0)}}][b]||(()=>{}))()})}).add([22,18,8],(r,a,o)=>{e.switchMode("mt32");let i=((r[0]&1)<<7)+r[1];r.subarray(2).forEach((s,f)=>{let l=i+f;l<$.cmt&&(t(e,me)[(r[0]>>1)*$.cmt+l]=s)})}).add([22,18,16],(r,a,o)=>{e.switchMode("mt32");let i=r[1],s=!1,f=function(l,d){t(e,H)[d-12]=l,s=!0};r.subarray(2).forEach((l,d)=>{let b=d+i;([!1,!1,!1,!1,!1,!1,!1,!1,!1,!1,!1,!1,!1,f,f,f,f,f,f,f,f,f,()=>{w(e,X,l)}][b]||(()=>{}))(l,d)}),s&&e.buildRchTree()}).add([22,18,32],r=>{e.switchMode("mt32");let a=r[1],o=" ".repeat(a);r.subarray(2).forEach(i=>{i>31&&(o+=String.fromCharCode(i))}),w(e,le,o.padStart(20," ")),w(e,ke,Date.now()+3200)}).add([22,18,82],(r,a)=>{let o=e.chRedir(0,a,!0);for(let i=0;i<16;i++)t(e,N).ano(o+i),i&&i<10&&(t(e,D)[o+i]=gt[i-1]);console.info("MT-32 alt reset complete.")}),t(this,ge).add([66,0],(r,a)=>{e.switchMode("ns5r",!0),w(e,I,!1),console.debug(`NS5R mode switch requested: ${["global","multi","prog edit","comb edit","drum edit","effect edit"][r[0]]} mode.`)}).add([66,1],(r,a)=>{e.switchMode(["ns5r","05rw"][r[0]],!0),w(e,I,!1)}).add([66,18,0,0],(r,a)=>{let o=r[0];switch(o){case 124:case 126:case 127:{e.switchMode("ns5r",!0),w(e,I,!1);break}case 125:{console.info(`NS5R drum setup reset: ${r}`);break}default:if(o<10){let i=[0,0,0,0],s=(f,l)=>{i[l]=f};if(r.subarray(1).forEach((f,l)=>{[s,s,s,s,()=>{w(e,X,f*129/16383*100)},()=>f-64,()=>f-64,()=>{},()=>{},()=>{}][o+l]()}),r[0]<4){let f=0;i.forEach(l=>{f=f<<4,f+=l}),f-=1024}}}}).add([66,18,0,1],(r,a)=>{}).add([66,18,0,2],(r,a)=>{}).add([66,18,1],(r,a)=>{let o=e.chRedir(r[0],a,!0),i=o*$.cc,s=r[1],f=`NS5R CH${o+1} `;r.subarray(2).forEach((l,d)=>{let b=s+d;b<3?[()=>{t(e,p)[i+g[0]]=l||121},()=>{t(e,p)[i+g[32]]=l},()=>{t(e,D)[o]=l}][b]():b<8||(b<14?[()=>{let y=e.chRedir(l,a,!0);t(e,H)[o]=y,o!=y&&(e.buildRchTree(),console.info(`${f}receives from CH${y+1}`))},()=>{t(e,J)[o]=+!l},()=>{e.setChType(o,l,M.ns5r),console.debug(`${f}type: ${Ye[l]}`)},()=>{t(e,S)[$.rpn*o+3]=l},()=>{},()=>{}][b-8]():b<16||(b<33?[()=>{t(e,p)[i+g[7]]=l},()=>{t(e,p)[i+g[11]]=l},()=>{},()=>{},()=>{t(e,p)[i+g[10]]=l||128},()=>{},()=>{},()=>{t(e,p)[i+g[93]]=l},()=>{t(e,p)[i+g[91]]=l},()=>{t(e,p)[i+g[76]]=l},()=>{t(e,p)[i+g[77]]=l},()=>{t(e,p)[i+g[78]]=l},()=>{t(e,p)[i+g[74]]=l},()=>{t(e,p)[i+g[71]]=l},()=>{t(e,p)[i+g[73]]=l},()=>{t(e,p)[i+g[75]]=l},()=>{t(e,p)[i+g[72]]=l}][b-16]():b<112||b<114&&[()=>{t(e,p)[i+g[5]]=l},()=>{t(e,p)[i+g[65]]=l}][b-112]()))})}).add([66,18,8,0],(r,a)=>{let o=r[0];if(o<32)e.setLetterDisplay(r.subarray(1,33),"NS5R letter display");else{let i=o-32;w(e,ne,Date.now()+3200),w(e,j,10),t(e,W,de).fill(0);let s=r.subarray(1),f=4;s.forEach(function(l,d){let b=d+i,y=b>>4,k=b&15;if(b<80){let v=y>3,m=0,x=y0;)t(e,W,de)[k*32+y*7+(x-m)]=v&1,v=v>>1,m++}})}}).add([66,52],(r,a)=>{e.switchMode("ns5r",!0),w(e,I,!1);let o="";ie(r,(i,s)=>{s<8?(i>31&&(o+=String.fromCharCode(i)),s==7&&(e.aiEfxName=o)):s<10&&e.setEffectType(s-8,44,i)})}).add([66,53],(r,a)=>{e.switchMode("ns5r",!0),w(e,I,!1),ie(r,function(o,i){switch(!0){case i<2944:{let s=e.chRedir(Math.floor(i/92),a,!0),f=s*$.cc;switch(i%92){case 0:{t(e,p)[f+g[0]]=o||121;break}case 1:{t(e,p)[f+g[32]]=o;break}case 2:{t(e,D)[s]=o,o>0&&(t(e,U)[s]=1);break}case 3:{let l=e.chRedir(o,a,!0);t(e,H)[s]=l,s!=l&&(console.info(`NS5R CH${s+1} receives from CH${l+1}.`),e.buildRchTree())}case 7:break;case 8:{t(e,S)[s*$.rpn+3]=o<40||o>88?o+(o>63?-192:64):o;break}case 9:case 10:{t(e,p)[f+g[7]]=o;break}case 11:{t(e,p)[f+g[11]]=o;break}case 14:{t(e,p)[f+g[10]]=o||128;break}case 19:{t(e,p)[f+g[93]]=o;break}case 20:{t(e,p)[f+g[91]]=o;break}case 84:{t(e,p)[f+g[65]]=o;break}case 85:{t(e,p)[f+g[5]]=o;break}}break}case i<3096:break;case i<3134:break;case i<8566:break}})}).add([66,54],(r,a)=>{e.switchMode("ns5r",!0);let o="",i=80,s=0,f=0,l="MSB PRG LSB NME";ie(r,function(d,b){let y=b%158;switch(!0){case y<10:{d>31&&(o+=String.fromCharCode(d));break}case y==11:{i=d&127;break}case y==12:{f=d&127;break}case y==13:{l+=`
+${i} ${s} ${f} ${o.trim().replace("Init Voice","")}`,s++,o="";break}}}),e.userBank.clearRange({msb:80,lsb:0}),e.userBank.load(l)}).add([66,55],(r,a)=>{e.switchMode("ns5r",!0);let o="",i=88,s=0,f=0,l="MSB PRG LSB NME";ie(r,function(d,b){let y=b%126;switch(!0){case y<10:{d>31&&(o+=String.fromCharCode(d));break}case y==11:break;case y==12:break;case y==13:{l+=`
+${i} ${s} ${f} ${o.trim().replace("Init Combi","")}`,s++,o="";break}}}),e.userBank.clearRange({msb:88,lsb:0}),e.userBank.load(l)}).add([66,125],r=>{e.dispatchEvent("backlight",["green","orange","red",!1,"yellow","blue","purple"][r[0]]||"white")}).add([66,127],r=>{let a=new Uint8Array(5760);ie(r,(o,i,s)=>{if(i<720)for(let f=0;f<8;f++)a[i*8+f]=o>>7-f&1}),e.dispatchEvent("screen",{type:"ns5r",data:a})}).add([76],(r,a,o)=>{t(e,ge).run([66,...r],a,o)}),t(this,Pe).add([16,0,8,0],(r,a,o)=>{let i=(r[2]<<4)+r[3],s="K11 ";([()=>{e.switchMode("k11",!0),w(e,I,!1),w(e,te,i?4:0),console.info("MIDI reset: GMega/K11")},()=>{console.debug(`${s}reverb type: ${i}`)},()=>{console.debug(`${s}reverb time: ${i}`)},()=>{console.debug(`${s}reverb time: ${i}`)},()=>{console.debug(`${s}reverb predelay: ${i}`)},()=>{console.debug(`${s}reverb predelay: ${i}`)},()=>{console.debug(`${s}depth high: ${i}`)},()=>{console.debug(`${s}depth high: ${i}`)},()=>{console.debug(`${s}depth low: ${i}`)},()=>{console.debug(`${s}depth low: ${i}`)}][r[0]]||(()=>{}))()}).add([16,0,8,1],(r,a,o)=>{let i=e.chRedir(r[1],a,!0),s=$.cc*i,f=$.rpn*i,l=(r[3]<<4)+r[4],d=`K11 CH${i+1} `;([()=>{l<128?(e.setChType(i,e.CH_MELODIC,M.k11),t(e,p)[s+g[0]]=0,t(e,D)[i]=l):(e.setChType(i,e.CH_DRUMS,M.k11),t(e,D)[i]=l-128)},()=>{let b=e.chRedir(l,a,!0);t(e,H)[i]=b,i!=b&&(e.buildRchTree(),console.info(`${d}receives from CH${b+1}`))},()=>{t(e,p)[s+g[7]]=l},()=>{t(e,U)[i]=l},()=>{t(e,p)[s+g[10]]=l},()=>{t(e,S)[f+3]=l+40},()=>{t(e,S)[f+1]=l>>1,t(e,S)[f+2]=l&1},()=>{t(e,p)[s+g[91]]=l?127:0},()=>{},()=>{t(e,p)[s+g[74]]=l},()=>{t(e,p)[s+g[73]]=l},()=>{t(e,p)[s+g[72]]=l}][r[0]]||(()=>{}))()}).add([16,0,9,0],(r,a,o)=>{let i=(r[2]<<4)+r[3],s="GMLX ";([()=>{console.debug(`${s}reverb type: ${i}`)},()=>{console.debug(`${s}reverb time: ${i}`)},()=>{console.debug(`${s}reverb predelay: ${i}`)},()=>{console.debug(`${s}depth high: ${i}`)},()=>{console.debug(`${s}depth low: ${i}`)}][r[0]]||(()=>{}))()}).add([16,0,9,3],(r,a,o)=>{let i=(r[2]<<4)+r[3],s=e.chRedir(r[1],a,!0),f=s*$.cc;[()=>{i<128?(e.setChType(s,e.CH_MELODIC,M.k11),t(e,p)[f+g[0]]=0,t(e,p)[f+g[32]]=0,t(e,D)[s]=i):i<160?(e.setChType(s,e.CH_MELODIC,M.k11),t(e,p)[f+g[0]]=0,t(e,p)[f+g[32]]=7,t(e,D)[s]=i-100):(e.setChType(s,e.CH_DRUMS,M.k11),t(e,p)[f+g[0]]=122,t(e,p)[f+g[32]]=0,t(e,D)[s]=i-160)},()=>{let l=e.chRedir(i,a,!0);t(e,H)[s]=l,s!=l&&(e.buildRchTree(),console.info(`GMLX CH${s+1} receives from CH${l+1}`))}][r[0]]()}).add([16,0,9,4],(r,a,o)=>{let i=(r[2]<<4)+r[3],s=e.chRedir(r[1],a,!0),f=s*$.cc,l=s*$.rpn,d=`GMLX CH${s+1} `;[()=>{t(e,U)[s]=i},()=>{t(e,p)[f+g[7]]=i},()=>{t(e,p)[f+g[10]]=i},()=>{t(e,p)[f+g[91]]=i?127:0},()=>{t(e,S)[l+3]=i+40},()=>{t(e,S)[l+1]=i},()=>{t(e,S)[l]=i},()=>{}][r[0]]()}),t(this,De).add([66,93,64],(r,a,o)=>{let i=r[2];switch(r[0]){case 0:{switch(r[1]){case 4:{w(e,X,i*129/16383*100);break}case 5:{i-64;break}case 6:{console.debug(`SG global reverb: ${i?"on":"off"}`);break}case 127:{e.switchMode("sg",!0);break}}break}case 1:{switch(r[1]){case 48:{console.debug(`SG reverb type: ${pt[i]}`);break}}break}default:if(r[0]>>4==1){let s=e.chRedir(r[0]&15,a,!0);if(r[1]==2){let f=e.chRedir(i,a,!0);t(e,H)[s]=f,s!=f&&(e.buildRchTree(),console.info(`SG CH${s+1} receives from CH${f+1}`))}else r[1]==19&&(t(e,p)[$.cc*s+g[7]]=i)}else console.warn(`Unknown AKAI SG SysEx: ${r}`)}}),t(this,Ie).add([9],(r,a,o)=>{console.debug(`GZ set effect: ${["stage reverb","hall reverb","room reverb","chorus","tremelo","phaser","rotary speaker","enhancer","flanger","EQ"][r[0]]||"off"}`)}),t(this,Z).add([127,0],(r,a,o)=>{e.switchMode("motif");let i=new Uint8Array([127,1,...r]);t(e,Z).run(i,a,o)}).add([127,1,0,0],(r,a,o)=>{e.switchMode("s90es");let i="S90/Motif ES system ",s=r[0];r.subarray(1).forEach((f,l)=>{([()=>{w(e,X,f*12900/16383)}][s+l]||(()=>{console.info(`Unrecognized ${i}ID: ${s+l}`)}))()})}).add([127,1,0,0,14],(r,a,o)=>{e.switchMode("s90es");let i="S90/Motif ES bulk header ",s=[];s[95]=(f,l,d)=>{console.debug(`${i}multi edit buffer: ${f[1]}`)},(s[r[0]]||(()=>{console.info(`Unrecognized ${i}ID: ${r[0]}.`)}))(r.subarray(1))}).add([127,1,0,0,15],(r,a,o)=>{e.switchMode("s90es");let i="S90/Motif ES bulk footer ",s=[];s[95]=(f,l,d)=>{console.debug(`${i}multi edit buffer: ${f[1]}`)},(s[r[0]]||(()=>{console.info(`Unrecognized ${i}ID: ${r[0]}.`)}))(r.subarray(1))}).add([127,1,0,58,55],(r,a,o)=>{e.switchMode("s90es");let i=e.chRedir(r[0],a,!0),s=$.cc*i,f=r[1],l=`S90/Motif ES bulk CH${i<16?i+1:"U"+(i-95)} `;console.debug(l,r),!(r[0]>15)&&r.subarray(2).forEach((d,b)=>{([()=>{t(e,p)[s+g[0]]=d},()=>{d&&(t(e,U)[i]=1),t(e,p)[s+g[32]]=d,t(e,O)[i]=+([32,40].indexOf(d)>-1)<<1},()=>{d&&(t(e,U)[i]=1),t(e,D)[i]=d},()=>{let y=e.chRedir(d,a,!0);t(e,H)[i]=y,i!=y&&(e.buildRchTree(),console.info(`${l}receives from CH${y+1}`))},()=>{t(e,J)[i]=d?0:1},!1,!1,!1,!1,!1,!1,!1,!1,()=>{t(e,p)[s+g[7]]=d},()=>{t(e,p)[s+g[10]]=d},!1,!1,!1,()=>{t(e,p)[s+g[91]]=d},()=>{t(e,p)[s+g[93]]=d},()=>{t(e,p)[s+g[94]]=d},()=>{t(e,p)[s+g[128]]=d},()=>{},()=>{t(e,p)[s+g[74]]=d},()=>{t(e,p)[s+g[71]]=d},!1,()=>{t(e,p)[s+g[65]]=d},()=>{t(e,p)[s+g[5]]=d},()=>{}][f+b]||(()=>{}))()})}).add([127,1,54,16],(r,a,o)=>{e.switchMode("s90es");let i=r[0];r.subarray(1).forEach((s,f)=>{let d=`S90/Motif ES EQ${(f>>2)+1} `;([()=>{let b=s-64},()=>{let b=_e[s]},()=>{let b=s/10},()=>{let b=s}][i+f&3]||(()=>{}))()})})}chRedir(e,n,h){if(t(this,Se)[n])return(t(this,Se)[n]-1)*16+e;if([2,3].indexOf(t(this,te))>-1){if(h==1)return e;let c=0,r=!0;for(;r;)t(this,be)[e+c]==0?(t(this,be)[e+c]=n,console.debug(`Assign track ${n} to channel ${e+c+1}.`),r=!1):t(this,be)[e+c]==n?r=!1:(c+=16,c>=128&&(c=0,r=!1));return e+c}else return e}buildRchTree(){let e=[];t(this,H).forEach((n,h)=>{var c;(c=e[n])!=null&&c.constructor||(e[n]=[]),e[n].push(h)}),w(this,tt,e)}getActive(){let e=t(this,U).slice();return t(this,P)==M.mt32,e}getCc(e){let n=e*$.cc,h=t(this,p).subarray(n,n+$.cc);return h[g[0]]=h[g[0]]||t(this,ve),h[g[32]]=h[g[32]]||t(this,te),h}getCcCh(e,n){if(Je.indexOf(n)<0)throw new Error("CC number not accepted");return t(this,p)[$.cc*e+g[n]]}getCcAll(){let e=t(this,p).slice();for(let n=0;n<$.ch;n++){let h=n*$.cc;e[h+g[0]]=e[h+g[0]]||t(this,ve),e[h+g[32]]=e[h+g[32]]||t(this,te)}return e}getChType(){return t(this,O)}setChType(e,n,h=t(this,P)){n&=15,t(this,O)[e]=n,n>0&&(t(this,p)[e*$.cc+g[0]]=Me[h])}getPitch(){return t(this,we)}getProgram(){return t(this,D)}getTexts(){return t(this,T).slice()}getVel(e){let n=new Map,h=this;return t(h,B).forEach(function(c,r){let a=Math.floor(c/128),o=c%128;e==a&&t(h,L)[c]>0&&n.set(o,{v:t(h,L)[c],s:t(h,G)[r]})}),n}getBitmap(){return{bitmap:t(this,W,de),expire:t(this,ne)}}getLetter(){return{text:t(this,le),expire:t(this,ke)}}getMode(){return $e[t(this,P)]}getMaster(){return{volume:t(this,X)}}getRawStrength(){let e=this;return t(this,B).forEach(function(n){let h=Math.floor(n/128);t(e,L)[n]>t(e,oe)[h]&&(t(e,oe)[h]=t(e,L)[n])}),t(this,oe)}getStrength(){let e=[],n=this;return this.getRawStrength().forEach(function(h,c){e[c]=Math.floor(h*t(n,p)[c*$.cc+g[7]]*t(n,p)[c*$.cc+g[11]]*t(n,X)/803288)}),e}getRpn(){return t(this,S)}getNrpn(){return t(this,Fe)}getVoice(e,n,h,c){let r=e||t(this,ve),a=n,o=h||t(this,te);$e[t(this,P)]=="ns5r"&&r>0&&r<56&&(o=3);let i=this.userBank.get(r,a,o,c);if($e[t(this,P)]=="mt32"&&i.name.indexOf("MT-m:")==0){let s=parseInt(i.name.slice(5)),f=s*$.cmt,l="";t(this,me).subarray(f,f+10).forEach(d=>{d>31&&(l+=String.fromCharCode(d))}),this.userBank.load(`MSB LSB PRG
+0 127 ${a} ${l}`,!0),i.name=l,i.ending=" "}return(i.ending!=" "||!i.name.length)&&(i=this.baseBank.get(r,a,o,c)),i}getChVoice(e){let n=this.getVoice(t(this,p)[e*$.cc+g[0]],t(this,D)[e],t(this,p)[e*$.cc+g[32]],$e[t(this,P)]);if(t(this,ce)[e])switch(t(this,P)){case M.mt32:n.ending="~",n.name="",t(this,ee).subarray(14*(e-1),14*(e-1)+10).forEach(h=>{h>31&&(n.name+=String.fromCharCode(h))})}return n}getPitchShift(e){let n=e*$.rpn;return t(this,we)[e]/8192*t(this,S)[n]+(t(this,S)[n+3]-64)+((t(this,S)[n+1]<<7)+t(this,S)[n+2]-8192)/8192}getEffectType(e=0){let n=3*e+1;return t(this,Q).subarray(n,n+2)}setEffectTypeRaw(e=0,n,h){let c=3*e;t(this,Q)[c]=1,t(this,Q)[c+1+ +n]=h}setEffectType(e=0,n,h){this.setEffectTypeRaw(e,!1,n),this.setEffectTypeRaw(e,!0,h)}setLetterDisplay(e,n,h=0,c=3200){let r=this,a;w(r,le," ".repeat(h)),e.forEach(o=>{w(r,le,t(r,le)+String.fromCharCode(o>31?o:32)),o<32&&(a=a||new Set,a.add(o))}),w(r,ke,Date.now()+3200),w(r,le,t(r,le).padEnd(32," ")),a&&(a=Array.from(a),a.forEach((o,i,s)=>{s[i]=o.toString(16).padStart(2,"0")}),console.warn(`${n}${n?" ":""}invalid code point${a.length>1?"s":""}: 0x${a.join(", 0x")}`))}allocateAce(e){if(!e||e>95){console.warn(`cc${e} cannot be allocated as an active custom effect.`);return}let n=!0,h=0;for(;n&&h<$.ace;)t(this,ue)[h]==e?n=!1:t(this,ue)[h]||(n=!1,t(this,ue)[h]=e,console.info(`Allocated cc${e} to ACE slot ${h}.`)),h++;h>=$.ace&&console.warn("ACE slots are full.")}getAce(){return t(this,ue)}getChAce(e,n){if(n<0||n>=$.ace)throw new RangeError("No such ACE slot");let h=t(this,ue)[n];if(h){if(Je.indexOf(h)>=0)return t(this,p)[e*$.cc+g[h]];throw new Error(`Invalid ACE source: ${h}`)}else return 0}init(e=0){this.dispatchEvent("mode","?"),w(this,P,0),w(this,ve,0),w(this,te,0),w(this,pe,0),t(this,U).fill(0),t(this,p).fill(0),t(this,ue).fill(0),t(this,D).fill(0),t(this,L).fill(0),t(this,B).fill(0),t(this,oe).fill(0),t(this,we).fill(0),t(this,Fe).fill(0),t(this,et).fill(0),w(this,X,100),w(this,T,[]),w(this,Xe,500),w(this,ze,0),w(this,ke,0),w(this,le,""),w(this,ne,0),w(this,j,0),t(this,W,de).fill(0),w(this,I,!1),w(this,Ke,0),w(this,re,!0),t(this,H).forEach(function(n,h,c){c[h]=h}),this.buildRchTree(),e==0&&(t(this,be).fill(0),t(this,Se).fill(0)),t(this,p)[$.cc*9]=Me[0],t(this,p)[$.cc*25]=Me[0],t(this,p)[$.cc*41]=Me[0],t(this,p)[$.cc*57]=Me[0],t(this,O).fill(this.CH_MELODIC),t(this,O)[9]=this.CH_DRUM1,t(this,O)[25]=this.CH_DRUM3,t(this,O)[41]=this.CH_DRUMS,t(this,O)[57]=this.CH_DRUMS,t(this,O)[73]=this.CH_DRUM5,t(this,O)[89]=this.CH_DRUM7,t(this,O)[105]=this.CH_DRUMS,t(this,O)[121]=this.CH_DRUMS,t(this,Ve).fill(0),t(this,me).fill(0),t(this,Ee).fill(0),t(this,ee).fill(0),t(this,ce).fill(0),t(this,Q).fill(0),this.aiEfxName="",this.userBank.clearRange({msb:0,lsb:127,prg:[0,127]});for(let n=0;n<$.ch;n++){let h=n*$.cc;t(this,p)[h+g[7]]=100,t(this,p)[h+g[11]]=127,t(this,p)[h+g[10]]=64,t(this,p)[h+g[71]]=64,t(this,p)[h+g[72]]=64,t(this,p)[h+g[73]]=64,t(this,p)[h+g[74]]=64,t(this,p)[h+g[75]]=64,t(this,p)[h+g[76]]=64,t(this,p)[h+g[77]]=64,t(this,p)[h+g[78]]=64,t(this,p)[h+g[91]]=40,t(this,p)[h+g[101]]=127,t(this,p)[h+g[100]]=127,t(this,p)[h+g[99]]=127,t(this,p)[h+g[98]]=127;let c=n*$.rpn;t(this,S)[c]=2,t(this,S)[c+1]=64,t(this,S)[c+2]=0,t(this,S)[c+3]=64,t(this,S)[c+4]=0,t(this,S)[c+5]=0}}switchMode(e,n=!1){let h=$e.indexOf(e);if(h>-1){if(t(this,P)==0||n){let c=t(this,P);w(this,P,h),w(this,j,0),w(this,ve,Xt[0][h]),w(this,te,Xt[1][h]);for(let a=0;a<$.ch;a++)t(this,O)[a]>0&&t(this,p)[a*$.cc+g[0]]==Me[c]&&(t(this,p)[a*$.cc]=Me[h]);switch(this.initOnReset,h){case M.mt32:{gt.forEach((a,o)=>{let i=o+1;t(this,U)[i]||(t(this,D)[i]=a,t(this,p)[i*$.cc+g[91]]=127)});break}}let r;switch(h){case M.gs:{r=[40,4,40,18,40,32,32,0,0,0,0,0,0,0];break}case M.x5d:case M.ns5r:{r=[44,1,44,19,44,0,44,0,0,0,0,0,0,0];break}default:r=[1,0,65,0,5,0,0,0,0,0,0,0,0,0]}for(let a=0;a<$.efx;a++)t(this,Q)[3*a]||(t(this,Q)[3*a+1]=r[2*a],t(this,Q)[3*a+2]=r[2*a+1]);this.dispatchEvent("mode",e)}}else throw new Error(`Unknown mode ${e}`)}newStrength(){t(this,oe).fill(0)}runJson(e){var n;if(e.type>14)return e.type==15&&e.data.constructor!=Uint8Array&&(e.data=Uint8Array.from(e.data)),t(this,rt)[e.type].call(this,e);{let h=this.chRedir(e.part,e.track),c=!1;(n=t(this,tt)[h])==null||n.forEach(r=>{e.channel=r,c=!0,t(this,rt)[e.type].call(this,e)}),c||console.warn(`${zt[e.type]?zt[e.type]:e.type}${[11,12].includes(e.type)?(e.data[0]!=null?e.data[0]:e.data).toString():""} event sent to CH${h+1} without any recipient.`)}t(this,T).length>100&&t(this,T).splice(100,t(this,T).length-99)}runRaw(e){}async loadBank(e,n){switch(e=e.toLowerCase(),e){case"s7e":{this.userBank.clearRange({msb:63,lsb:[21,22]}),this.userBank.clearRange({msb:63,lsb:[24,27]});break}default:throw new Error(`Unknown bank format ${e}`)}switch(e){case"s7e":{nt.context=this,this.userBank.load(await nt.read(e,n));break}}}},P=new WeakMap,j=new WeakMap,ne=new WeakMap,fe=new WeakMap,W=new WeakSet,de=function(){return t(this,fe)[t(this,j)]},Yt=function(e){t(this,fe)[t(this,j)]=e},U=new WeakMap,H=new WeakMap,O=new WeakMap,p=new WeakMap,ue=new WeakMap,D=new WeakMap,L=new WeakMap,J=new WeakMap,B=new WeakMap,G=new WeakMap,we=new WeakMap,oe=new WeakMap,Ce=new WeakMap,S=new WeakMap,Fe=new WeakMap,et=new WeakMap,ce=new WeakMap,Ee=new WeakMap,ee=new WeakMap,Ve=new WeakMap,me=new WeakMap,Q=new WeakMap,ve=new WeakMap,te=new WeakMap,X=new WeakMap,pe=new WeakMap,Xe=new WeakMap,ze=new WeakMap,le=new WeakMap,ke=new WeakMap,Ke=new WeakMap,re=new WeakMap,I=new WeakMap,tt=new WeakMap,$t=new WeakMap,T=new WeakMap,be=new WeakMap,Se=new WeakMap,_=new WeakMap,Te=new WeakMap,N=new WeakMap,rt=new WeakMap,ot=new WeakMap,Re=new WeakMap,Oe=new WeakMap,Z=new WeakMap,he=new WeakMap,ge=new WeakMap,Pe=new WeakMap,De=new WeakMap,Ie=new WeakMap,Wt);var kt=ur(Zt(),1);R();R();var at,Jt,tr=(Jt=class{constructor(u,e,n,h){E(this,at,!1);w(this,at,u),this.start=e,this.end=n,this.data=h}get duration(){return this.ranged?this.end-this.start:0}get ranged(){return t(this,at)}},at=new WeakMap,Jt),mt=class extends tr{constructor(u,e,n){super(!0,u,e,n)}},rr=class extends tr{constructor(u,e){super(!1,u,u,e)}},Ae,er,vt=(er=class extends Array{constructor(){super(...arguments);E(this,Ae,-1)}resetIndex(e){w(this,Ae,-1)}fresh(){this.sort(function(e,n){return e.start==n.start?0:(+(e.start>n.start)<<1)-1}),this.forEach(function(e,n){e.index=n})}step(e,n=!1){let h=[];if(n)for(let c=0;ce);c++){if(this[c].endt(r,Ae)&&(h.push(a),w(r,Ae,a.index))})}return h}getRange(e,n){var o;e>n&&([e,n]=[n,e]);let h=[],c=-1,r=Math.ceil(Math.sqrt(this.length)),a=!0;for(let i=0;i=e&&(c=i):c=c<0?i:c;for(;a;)((o=this[c])==null?void 0:o.end)=e&&h.push(this[c]):a=!1,c++;return h}},Ae=new WeakMap,er);var kr=0xffffffffffff,ar=function(u){let e=new vt,n=this,h=u.timeDivision,c=120,r=new vt,a=0,o=0;r.push(new mt(0,kr,[120,0])),u.track.forEach(function(l){a=0,l.event.forEach(function(d){a+=d.deltaTime,d.type==255&&(d==null?void 0:d.metaType)==81&&(c=6e7/d.data,r[r.length-1]&&r.push(new mt(a,0xffffffffffff,[c,0])))})}),r.fresh(),r.forEach(function(l,d,b){d>0&&(b[d-1].end=l.start)});let i=120;r.forEach(function(l,d,b){d>0&&(l.end==l.start?b.splice(b.indexOf(l),1):i==l.data[0]&&(b[d-1].end=l.end,b.splice(b.indexOf(l),1)),i=l.data[0])});let s=0,f=120;return r.forEach(function(l){let d=l.start,b=d/f/h*60+s;f=l.data[0],s=b-d/f/h*60,l.data[1]=s}),console.debug("All tempo changes: ",r),c=120,a=0,o=0,u.track.forEach(function(l,d){a=0,o=0;let b=d+1;l.event.forEach(function(y,k){a+=y.deltaTime;let v=r.step(a,!0)[0];v&&(c=v.data[0],o=v.data[1]);let m={type:y.type,data:y.data,track:b,part:0};y.type>14?m.meta=y.metaType:m.part=y.channel,e.push(new rr(a/c/h*60+o,m))})}),e.fresh(),self.midiEvents=e,console.debug(`Parsed a type ${u.formatType} MIDI sequence.`),e};kt.default.customInterpreter=Ft;var qe,Ue,Le,Be,st,xe,je,F,Ne,ye,He,sr,Ta=(sr=class extends it{constructor(e,n=.5,h=.5){super();C(this,"device");E(this,qe,void 0);E(this,Ue,"");E(this,Le,[]);E(this,Be,new Uint8ClampedArray(128));E(this,st,new Uint8ClampedArray(128));E(this,xe,.5);E(this,je,120);E(this,F,4);E(this,Ne,4);E(this,ye,0);E(this,He,0);C(this,"smoothingAtk",0);C(this,"smoothingDcy",0);let c=this;this.smoothingAtk=n,this.smoothingDcy=h,this.device=e,this.addEventListener("meta",function(r){var a;(a=r==null?void 0:r.data)==null||a.forEach(function(o){(t(c,Le)[o.meta]||console.debug).call(c,o.meta,o.data)})}),this.device.addEventListener("mode",function(r){c.dispatchEvent("mode",r.data)}),this.device.addEventListener("channelactive",function(r){c.dispatchEvent("channelactive",r.data)}),this.device.addEventListener("channelmin",function(r){c.dispatchEvent("channelmin",r.data)}),this.device.addEventListener("channelmax",function(r){c.dispatchEvent("channelmax",r.data)}),this.device.addEventListener("channelreset",function(r){c.dispatchEvent("channelreset")}),this.device.addEventListener("screen",function(r){c.dispatchEvent("screen",r.data)}),t(this,Le)[3]=function(r,a){var o;((o=t(c,Ue))==null?void 0:o.length)<1&&w(c,Ue,a)},t(this,Le)[81]=function(r,a){let o=c.noteProgress,i=t(c,xe)||.5;w(c,je,6e7/a),w(c,xe,a/1e6),w(c,ye,t(c,ye)+(o*(i/t(c,xe))-o))},t(this,Le)[88]=function(r,a){let o=c.noteProgress,i=c.noteOverall,s=c.noteBar,f=c.noteBeat,l=t(c,F),d=t(c,Ne);w(c,F,a[0]),w(c,Ne,1<=l&&(lt(this,He)&&w(this,He,e);let n=((v=t(this,qe))==null?void 0:v.step(e))||[],h=0,c=new Set,r=this,a=[];this.device.getStrength().forEach((m,x)=>{t(this,st)[x]=m}),r.device.newStrength(),n.forEach(function(m){let x=m.data;x.type==9&&(x.data[1]>0?c.add(x.part*128+x.data[0]):c.has(x.part*128+x.data[0])&&h++),m.data.type==8&&c.has(x.part*128+x.data[0])&&h++;let A=r.device.runJson(x);switch(A==null?void 0:A.reply){case"meta":{a.push(A);break}}A!=null&&A.reply&&delete A.reply}),(a==null?void 0:a.length)>0&&this.dispatchEvent("meta",a);let o=this.device.getActive(),i=[],s=r.device.getPitch(),f=r.device.getCcAll(),l=r.device.getProgram(),d=r.device.getChType(),b=this.device.getStrength();b.forEach(function(m,x,A){A[x]=Math.max(t(r,st)[x],m);let V=A[x]-t(r,Be)[x],ae=g.length*x;if(V>=0){let lt=4*.25**(f[ae+g[73]]/64);t(r,Be)[x]+=Math.ceil(V-V*r.smoothingAtk**lt)}else{let lt=4*.25**(f[ae+g[72]]/64);t(r,Be)[x]+=Math.floor(V-V*r.smoothingDcy**lt)}});let y=0;return o.forEach(function(m,x){m&&(i[x]=r.device.getVel(x),y+=i[x].size)}),{extraPoly:h,curPoly:y,chInUse:o,chKeyPr:i,chPitch:s,chProgr:l,chContr:f,chType:d,eventCount:n.length,title:t(this,Ue),bitmap:this.device.getBitmap(),letter:this.device.getLetter(),texts:this.device.getTexts(),master:this.device.getMaster(),mode:this.device.getMode(),strength:t(this,Be).slice(),velo:b,rpn:this.device.getRpn(),tSig:this.getTimeSig(),tempo:this.getTempo(),noteBar:this.noteBar,noteBeat:this.noteBeat,ace:this.device.getAce()}}},qe=new WeakMap,Ue=new WeakMap,Le=new WeakMap,Be=new WeakMap,st=new WeakMap,xe=new WeakMap,je=new WeakMap,F=new WeakMap,Ne=new WeakMap,ye=new WeakMap,He=new WeakMap,sr);export{Ta as RootDisplay,g as ccToPos,wt as dnToPos};
diff --git a/dist/xp_state.mjs b/dist/xp_state.mjs
new file mode 100644
index 00000000..3f85d320
--- /dev/null
+++ b/dist/xp_state.mjs
@@ -0,0 +1,156 @@
+var Rt=Object.defineProperty;var Ot=(u,e,n)=>e in u?Rt(u,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):u[e]=n;var C=(u,e,n)=>(Ot(u,typeof e!="symbol"?e+"":e,n),n),st=(u,e,n)=>{if(!e.has(u))throw TypeError("Cannot "+n)};var t=(u,e,n)=>(st(u,e,"read from private field"),n?n.call(u):e.get(u)),E=(u,e,n)=>{if(e.has(u))throw TypeError("Cannot add the same private member more than once");e instanceof WeakSet?e.add(u):e.set(u,n)},w=(u,e,n,c)=>(st(u,e,"write to private field"),c?c.call(u,n):e.set(u,n),n);(function(){var u=function(o,i,a){var l,h;if(self.MessageEvent)switch(o){case"message":{h=new MessageEvent(o,{data:i,ports:a==null?void 0:a.ports}),Object.defineProperty(h,"source",{value:a==null?void 0:a.source});break}default:h=new Event(o)}else h=document.createEvent("Event"),h.initEvent(o,!1,!1),a&&o=="message"&&(h.data=i,a.source&&Object.defineProperty(h,"source",{value:a.source}),(l=a.ports)!=null&&l.length&&Object.defineProperty(h,"ports",{value:a.ports}));return h};self.BroadcastChannel?console.info("[Snowy] Snowy is disabled."):(console.info("[Snowy] Snowy is enabled. Path: ".concat(self.SNOWY_PATH||"/snowy.js")),n=[],c={},d=function(o){var i,a=this;if((this==null?void 0:this.constructor)!=d)throw new TypeError("Illegal constructor");n.push(this),(i=c[o])!=null&&i.constructor||(c[o]=[]),c[o].push(this);var l=Math.floor(Math.random()*281474976710656),h=[],f=0,g=[],y=!0,S=!1;Object.defineProperty(this,"id",{get:function(){return l}}),Object.defineProperty(this,"name",{value:o}),this.close=function(){var m,B=n.indexOf(a);B>-1?(e.postMessage({t:"d",c:o,i:l}),n.splice(B,1),(m=c[o])!=null&&m.constructor&&(B=c[o].indexOf(a),B>-1&&c[o].splice(B,1)),c[o].length||delete c[o],console.debug("[Snowy] BroadcastChannel closed."),S=!0):console.debug("[Snowy] BroadcastChannel already closed.")},this.postMessage=function(m){if(e){if(S)throw new Error("Channel already closed");e.postMessage({t:"m",c:o,i:l,m:f,d:m}),f++,f>4294967295&&(f=0)}else g.push(m),console.debug("[Snowy] Message is cached.")},this.flush=function(){if(e){if(y){for(e.postMessage({t:"r",c:o,i:l}),console.debug("[Snowy] ".concat(g.length," message(s) in cache."));g.length;){var m=g.shift();a.postMessage(m)}y=!1,console.debug("[Snowy] All cached messages are flushed away.")}}else throw new Error("Tried to flush when the ports are not ready")},this.receiveMessage=function(m){m.c==o?m.i!=l&&a.dispatchEvent(u("message",m.d,{source:a})):console.debug("[Snowy] Channel ID mismatch. Instance ".concat(l," receives from ").concat(o,", not ").concat(m.c,"."))};var k={};this.dispatchEvent=function(m){var B,de;if(Object.defineProperty(m,"target",{value:a}),Object.defineProperty(m,"currentTarget",{value:a}),(B=k[m.type])!=null&&B.length)for(var ue=k[m.type],ke=0;ke-1&&k[m].splice(ke,1)}!((ue=k[m])!=null&&ue.length)&&k[m].constructor&&delete k[m]}},self.BroadcastChannel=d,s=function(){if(e){e.addEventListener("message",function(i){var a=i.data,l=!1;switch(a.t){case"k":{l=!1,e.postMessage({t:"k"});break}case"m":{var h=c[a.c];if(h!=null&&h.length)for(var f=0;f{switch(c.addEventListener("abort",()=>{s(new Error("Blob read aborted"))}),c.addEventListener("error",r=>{s(c.error||r.data||new Error("Blob read error"))}),c.addEventListener("load",()=>{d(c.result)}),n.toLowerCase()){case"arraybuffer":case"buffer":{c.readAsArrayBuffer(e);break}case"string":case"text":{c.readAsText(e);break}default:s(new Error(`Unknown target ${n}`))}})};Blob.prototype.arrayBuffer=Blob.prototype.arrayBuffer||function(){return u(this,"buffer")},Blob.prototype.text=Blob.prototype.text||function(){return u(this,"text")}}String.prototype.replaceAll=String.prototype.replaceAll||function(u,e){let n=0,c=16,d=this,s=[];for(;n-1;){let r=d.lastIndexOf(u);s.unshift(d.slice(r+u.length)),d=d.slice(0,r),r==0&&s.unshift(""),n++}return d.length&&s.unshift(d),s.join(e)||""},String.prototype.padStart=String.prototype.padStart||function(u,e){if(e){let n=this;for(;n.length0){let c=this.pool.length,d=1<=1&&r>=0;){if(r<=0)throw new Error("TTL reached.");if(s==c)s-=d;else{let i=rt(e,this.pool[s]);switch(i){case 0:{r=0;break}case 1:{s+d<=c&&(s+=d);break}case-1:{s!=0&&(s-=d);break}default:console.warn(`Unexpected result ${i}.`)}}d=d>>1,r--}let o=!0;if(s>=this.pool.length)o=!1;else{let i=this;this.pool[s].forEach(function(a,l,h){o&&a!=e[l]&&(o=!1)}),!o&&rt(e,this.pool[s])>0&&s++}return o||n?s:-1}else return n?0:-1},this.add=function(e,n){return e.data=n,this.pool.splice(this.point(e,!0),0,e),this},this.default=function(e){console.warn(`No match in "${this.name||"(unknown)"}" for "${e}". Default action not defined.`)},this.get=function(e){let n=this.point(e);if(n>-1)return this.pool[n].data;this.default(e)},this.run=function(e,...n){let c=this.point(e);c>-1?e.subarray?this.pool[c].data(e.subarray(this.pool[c].length),...n):this.pool[c].data(e.slice(this.pool[c].length),...n):this.default(e,...n)}};var _,at,it=(at=class{constructor(){E(this,_,{})}addEventListener(u,e){t(this,_)[u]||(t(this,_)[u]=[]),t(this,_)[u].unshift(e)}removeEventListener(u,e){if(t(this,_)[u]){let n=t(this,_)[u].indexOf(e);n>-1&&t(this,_)[u].splice(n,1),t(this,_)[u].length<1&&delete t(this,_)[u]}}dispatchEvent(u,e){var d;let n=new Event(u),c=this;n.data=e,((d=t(this,_)[u])==null?void 0:d.length)>0&&t(this,_)[u].forEach(function(s){try{s==null||s.call(c,n)}catch(r){console.error(r)}}),this[`on${u}`]&&this[`on${u}`](n)}},_=new WeakMap,at);var Dt=["MSB","PRG","LSB"],Qe=function(u){let e=Math.floor(u/10),n=u%10;return`${e.toString(16)}${n}`},F,nt,je=(nt=class{constructor(...u){E(this,F,void 0);C(this,"strictMode",!1);this.loadFiles(...u)}get(u=0,e=0,n=0,c){let d=[u,e,n],s,r=Array.from(arguments);switch(c){case"xg":{u==32?r[2]+=4:u==33||u==35||u==36?r[2]+=5:u==79?r[0]=95:u==80?r[0]=96:u==81?r[0]=97:u==82?r[0]=98:u==83?r[0]=99:u==84&&(r[0]=100);break}case"gs":{u==0&&n<5?r[2]=0:u>125&&n<5&&n!=2&&(r[2]=u,r[0]=0);break}case"sg":{u==8&&n==0&&(r[2]=5);break}case"s90es":{n<8?r[2]+=17:n<32?r[2]+=13:r[2]=(r[2]>>3)+19;break}case"motif":{n<8?r[2]+=28:n<32?r[2]+=13:r[2]=(r[2]>>3)+19;break}}let o=" ",i="M",a=!1,l=0;switch(r[0]){case 0:{r[2]==127?i="MT-a":r[2]==126?i="MT-b":r[2]==7?i="GM-k":r[2]==5?i="SG-a":r[2]==4?i="SP-l":r[2]==0||c=="gs"&&r[2]<5?i="GM-a":(i="y",a=!0);break}case 8:{c=="sg"?i="GM-s":i="r:";break}case 48:{i=`yM${(r[2]>>3).toString().padStart(2,"0")}`,a=!0;break}case 56:{i="GM-b";break}case 61:case 120:{i="rDrm";break}case 62:{i="kDrm";break}case 63:{if(r[2]<17){let y=r[2];i=y<10?"kP:":"kC:",i+=y%10}else r[2]<34?i=["Pre1","Pre2","Pre3","Pre4","Usr1","Usr2","DrmP","DrmU","Plg1","Plg2","Plg3","Pre1","Pre2","Pre3","Pre4","Pre5","Pre6"][r[2]-17]:i="Ds";break}case 64:{i="ySFX";break}case 67:{i="DX:S";break}case 80:case 81:case 82:case 83:{i=`Prg${"UABC"[r[0]-80]}`;break}case 88:case 89:case 90:case 91:{i=`Cmb${"UABC"[r[0]-88]}`;break}case 95:{i=`${["DR","PC"][r[2]]}-d`;break}case 96:{i=r[2]==106?"AP-a":"PF",r[2]>63&&(l=63),a=!0;break}case 97:{i="VL:",a=!0,l=112;break}case 98:{i="SG-a";break}case 99:{i="DX",r[2]>63&&(l=63),a=!0;break}case 100:{i="AN",r[2]>63&&(l=63),a=!0;break}case 121:{i=`GM-${r[2]?"":"a"}`,a=!0;break}case 122:{i="lDrm";break}case 126:{i="yDrS";break}case 127:{r[2]==127?i="rDrm":i="yDrm";break}default:r[0]<48?i="r:":i="M"}i.length<4&&(i+=`${(a?n:u)-l}`.padStart(4-i.length,"0")),c=="xg"&&u==16&&(s=`Voice${(n*128+e+1).toString().padStart(3,"0")}`,o=" ");let h=[r[0],r[1],r[2]];for(;!((s==null?void 0:s.length)>=0);)s=t(this,F)[r[1]||0][(r[0]<<7)+r[2]],s||(this.strictMode?(s="",o="?"):t(this,F)[r[1]||0][r[0]<<7]?r[0]==0?(r[2]=0,o="^"):r[2]<1?(r[0]=0,o="*"):(r[2]--,o="^"):u==48?(r[0]=0,r[2]=0,o="!"):u==62?(r[1]--,o=" ",r[1]<1&&!(s!=null&&s.length)&&(r[0]=0,o="!")):u<63?r[0]==0?(r[2]=0,o="^"):r[2]<1?(r[0]=0,o="*"):r[2]--:u==80?(s=`PrgU:${e.toString().padStart(3,"0")}`,o="!"):u==88?(s=`CmbU:${e.toString().padStart(3,"0")}`,o="!"):u==121?(s=`GM2Vox0${n}`,o="#"):u==122?(r[1]==32?r[1]==0:r[1]%=7,s=t(this,F)[r[1]||0][(r[0]<<7)+r[2]],s?o=" ":(s="",o="*")):r[1]==0?(s=`${u.toString().padStart(3,"0")} ${e.toString().padStart(3,"0")} ${n.toString().padStart(3,"0")}`,o="!"):r[0]==0?(r[2]=0,o="^"):r[2]>0?r[2]--:r[1]>0?(r[1]=0,o="!"):(r[0]=0,o="?"));let f=[r[0],r[1],r[2]];(c=="gs"||c=="ns5r")&&o=="^"&&(o=" "),u==127&&o=="^"&&(o=" "),o!=" "&&self.debugMode&&(s="");let g="??";switch(r[0]){case 0:{r[2]==0?g="GM":r[2]==5||r[2]==7?g="KG":r[2]<120?g="XG":r[2]==127&&(g="MT");break}case 48:{g="MU";break}case 56:{g="AG";break}case 61:case 80:case 83:case 88:case 89:case 91:{g="AI";break}case 62:case 82:case 90:{g="XD";break}case 63:{r[2]<17?g="KR":r[2]<34?g="ES":g="DS";break}case 64:case 126:{g="XG";break}case 67:case 99:{g="DX";break}case 81:{g="RW";break}case 95:{g=["DR","PC"][r[2]];break}case 96:{g=r[2]==106?"AP":"PF";break}case 97:{g="VL";break}case 98:{g="SG";break}case 100:{g="AN";break}case 120:{g="GS";break}case 121:{g=r[2]?"G2":"GM";break}case 122:{g="KG";break}case 127:{g=r[2]==127?"MT":e==0?"GM":"XG";break}default:r[0]<48&&(r[0]==16&&c=="xg"?g="XG":g="GS")}return{name:s||`${Qe(u||0)} ${Qe(e||0)} ${Qe(n||0)}`,iid:h,eid:f,sid:d,ending:o,sect:i,standard:g}}async load(u,e,n){let c=this,d=[],s=0,r=0;u.split(`
+`).forEach(function(o,i){let a=o.split(" "),l=[];i==0?a.forEach(function(h,f){d[Dt.indexOf(h)]=f}):a.forEach(async function(h,f){var g;f>2?(t(c,F)[l[d[1]]]=t(c,F)[l[d[1]]]||[],(!((g=t(c,F)[l[d[1]]][(l[d[0]]<<7)+l[d[2]]])!=null&&g.length)||e)&&(t(c,F)[l[d[1]]][(l[d[0]]<<7)+l[d[2]]]=a[3],s++),r++):l.push(parseInt(a[f]))})}),e||console.debug(`Map "${n||"(internal)"}": ${r} total, ${s} loaded.`)}clearRange(u){let e=u.prg!=null?u.prg.constructor==Array?u.prg:[u.prg,u.prg]:[0,127],n=u.msb!=null?u.msb.constructor==Array?u.msb:[u.msb,u.msb]:[0,127],c=u.lsb!=null?u.lsb.constructor==Array?u.lsb:[u.lsb,u.lsb]:[0,127];for(let d=n[0];d<=n[1];d++){let s=d<<7;for(let r=c[0];r<=c[1];r++){let o=s+r;for(let i=e[0];i<=e[1];i++)delete t(this,F)[i][o]}}}init(){w(this,F,[]);for(let u=0;u<128;u++)t(this,F).push([""])}async loadFiles(...u){this.init();let e=this;u.forEach(async function(n,c){try{await fetch(`./data/bank/${n}.tsv`).then(function(d){return d.text()}).then(d=>{e.load(d,!1,n)})}catch(d){console.error(`Failed loading "${n}.tsv".`)}})}},F=new WeakMap,nt);var Oe,ot,lt=(ot=class{constructor(){E(this,Oe,{});C(this,"context")}set(u,e){t(this,Oe)[u]=e}has(u){return!!t(this,Oe)[u]}async read(u,e){if(!this.has(u))throw new Error(`No decoder registered for "${u}"`);return await t(this,Oe)[u].call(this.context||this,e)}},Oe=new WeakMap,ot);var Pt=function(u,e){let n=!0;return e.forEach((c,d)=>{n=n&&u[d]==c}),n},ct=function(u){let e=0;return u.forEach(n=>{e*=256,e+=n}),e},Le=new TextDecoder,Ve=new lt;Ve.set("s7e",async function(u){let e=new Uint8Array(await u.slice(0,65536).arrayBuffer()),n="MSB LSB PRG NME",c=[0,0,0,0],d=32,s=0,r=0,o=!0,i=[],a=0;for(;o;){let l=e.subarray(s);([()=>{Le.decode(l.subarray(0,4))=="YSFC"?(s+=80,r=1):s++},()=>{if(Pt(l.subarray(0,4),c))i.forEach((h,f,g)=>{let y=ct(e.subarray(h.start+4,h.start+8));h.length=y}),r=2;else{let h=Le.decode(l.subarray(0,4)),f=ct(l.subarray(4,8));i.push({type:h,start:f}),s+=8}},()=>{let h=i[a],f=e.subarray(h.start,h.start+h.length),g=32;switch(h.type){case"ENVC":{let y=d;for(;y=i.length&&(r=3,o=!1)}][r]||(()=>{o=!1}))()}return n});var Be=["off","hall","room","stage","plate","delay LCR","delay LR","echo","cross delay","early reflections","gate reverb","reverse gate"].concat(new Array(4),["white room","tunnel","canyon","basement","karaoke"],new Array(43),["pass through","chorus","celeste","flanger","symphonic","rotary speaker","tremelo","auto pan","phaser","distortion","overdrive","amplifier","3-band EQ","2-band EQ","auto wah"],new Array(1),["pitch change","harmonic","touch wah","compressor","noise gate","voice channel","2-way rotary speaker","ensemble detune","ambience"],new Array(4),["talking mod","Lo-Fi","dist + delay","comp + dist + delay","wah + dist + delay","V dist","dual rotor speaker"]),Ge=["melodic","drums","drum set 1","drum set 2","drum set 3","drum set 4","drum set 5","drum set 6","drum set 7","drum set 8"],At=[17.1,18.6,20.2,21.8,23.3,24.9,26.5,28,29.6,31.2,32.8,34.3,35.9,37.5,39,40.6,42.2,43.7,45.3,46.9,48.4,50],De=[20,22,25,28,32,36,40,45,50,56,63,70,80,90,100,110,125,140,160,180,200,225,250,280,315,355,400,450,500,560,630,700,800,900,1e3,1100,1200,1400,1600,1800,2e3,2200,2500,2800,3200,3600,4e3,4500,5e3,5600,6300,7e3,8e3,9e3,1e4,11e3,12e3,14e3,16e3,18e3,2e4],ht=[0,.04,.08,.13,.17,.21,.25,.29,.34,.38,.42,.46,.51,.55,.59,.63,.67,.72,.76,.8,.84,.88,.93,.97,1.01,1.05,1.09,1.14,1.18,1.22,1.26,1.3,1.35,1.39,1.43,1.47,1.51,1.56,1.6,1.64,1.68,1.72,1.77,1.81,1.85,1.89,1.94,1.98,2.02,2.06,2.1,2.15,2.19,2.23,2.27,2.31,2.36,2.4,2.44,2.48,2.52,2.57,2.61,2.65,2.69,2.78,2.86,2.94,3.03,3.11,3.2,3.28,3.37,3.45,3.53,3.62,3.7,3.87,4.04,4.21,4,37,4.54,4.71,4.88,5.05,5.22,5.38,5.55,5.72,6.06,6.39,6.73,7.07,7.4,7.74,8.08,8.41,8.75,9.08,9.42,9.76,10.1,10.8,11.4,12.1,12.8,13.5,14.1,14.8,15.5,16.2,16.8,17.5,18.2,19.5,20.9,22.2,23.6,24.9,26.2,27.6,28.9,30.3,31.6,33,34.3,37,39.7],ft=function(u){let e=.1,n=-.3;return u>66?(e=5,n=315):u>56?(e=1,n=47):u>46&&(e=.5,n=18.5),e*u-n},dt=function(u){return u>105?At[u-106]:u>100?u*1.1-100:u/10},ut=",a,i,u,e,o,ka,ki,ku,ke,ko,ky,kw,sa,si,su,se,so,sh,ta,ti,tu,te,to,t,ch,t,s,na,ni,nu,ne,no,ny,nn,ha,hi,hu,he,ho,hy,fa,fi,fu,fe,fo,ma,mi,mu,me,mo,my,mm,ya,yu,ye,yo,ra,ri,ru,re,ro,ry,wa,wi,we,wo,ga,gi,gu,ge,go,gy,gw,za,zi,zu,ze,zo,ja,ji,ju,je,jo,jy,da,di,du,de,do,dy,ba,bi,bu,be,bo,by,va,vi,vu,ve,vo,pa,pi,pu,pe,po,py,nga,ngi,ngu,nge,ngo,ngy,ng,hha,hhi,hhu,hhe,hho,hhy,hhw,*,_,,,~,.".split(","),We={};`hi*,
+ka,か
+ki,き
+ku,く
+ke,け
+ko,こ
+ky,き!
+kw,くl
+tsu,つ
+ts,つl
+sa,さ
+si,すぃ
+su,す
+se,せ
+so,そ
+shi,し
+sh,し!
+ta,た
+ti,てぃ
+tu,とぅ
+te,て
+to,と
+tchy,ち!
+tchi,ち
+na,な
+ni,に
+nu,ぬ
+ne,ね
+no,の
+ny,に!
+nn,ん
+ha,は
+hi,ひ
+hu,ほぅ
+he,へ
+ho,ほ
+hy,ひ!
+fa,ふぁ
+fi,ふぃ
+fu,ふ
+fe,ふぇ
+fo,ふぉ
+ma,ま
+mi,み
+mu,む
+me,め
+mo,も
+my,み!
+mm,
+ra,ら
+ri,り
+ru,る
+re,れ
+ro,ろ
+ry,り!
+wa,わ
+wi,うぃ
+we,うぇ
+wo,を
+nga,ガ
+ngi,ギ
+ngu,グ
+nge,ゲ
+ngo,ゴ
+ngy,ギ!
+ng,
+ga,が
+gi,ぎ
+gu,ぐ
+ge,げ
+go,ご
+gy,ぎ!
+gw,ぐl
+za,ざ
+zi,ずぃ
+zu,ず
+ze,ぜ
+zo,ぞ
+ja,じゃ
+ji,じ
+ju,じゅ
+je,じぇ
+jo,じょ
+jy,じ!
+da,だ
+di,でぃ
+du,どぅ
+de,で
+do,ど
+dy,で!
+ba,ば
+bi,び
+bu,ぶ
+be,べ
+bo,ぼ
+by,び!
+va,ゔぁ
+vi,ゔぃ
+vu,ゔ
+ve,ゔぇ
+vo,ゔぉ
+pa,ぱ
+pi,ぴ
+pu,ぷ
+pe,ペ
+po,ぽ
+py,ぴ!
+!ya,ゃ
+!yu,ゅ
+!ye,ぇ
+!yo,ょ
+ya,や
+yu,ゆ
+ye,いぇ
+yo,よ
+!a,ゃ
+!u,ゅ
+!e,ぇ
+!o,ょ
+!a,ゃ
+!u,ゅ
+!e,ぇ
+!o,ょ
+la,ぁ
+li,ぃ
+lu,ぅ
+le,ぇ
+lo,ぉ
+a,あ
+i,い
+u,う
+e,え
+o,お
+*,っ
+~,
+^,
+_,`.split(`
+`).forEach(u=>{let e=u.split(",");We[e[0]]=e[1]});var bt=function(u){let e=u;u[0]=="*"&&(e=e.slice(1)),["aa","ii","uu","ee","oo"].forEach(c=>{for(;e.indexOf(c)>-1;)e=e.replace(c,c[0])});for(let c in We)e=e.replaceAll(c,We[c]);e.indexOf("ん")==0&&e.length>1&&(e=e.slice(1));let n=e.indexOf("!");return n>-1&&e.length>1&&(e=e.slice(n+1)),e},pt=function(u){return u?u<96?`cc${u}`:["aftertouch","velocity","pitch bend"][u-96]:"off"};var Ye=["room 1","room 2","room 3","hall 1","hall 2","plate","delay","panning delay"],gt=["chorus 1","chorus 2","chorus 3","chorus 4","feedback","flanger","short delay","short delay feedback"],$t=["delay 1","delay 2","delay 3","delay 4","pan delay 1","pan delay 2","pan delay 3","pan delay 4","delay to reverb","pan repeat"];var Ut={0:"thru",256:"stereo EQ",257:"spectrum",258:"enhancer",259:"humanizer",272:"overdrive",273:"distortion",288:"phaser",289:"auto wah",290:"rotary",291:"stereo flanger",292:"step flanger",293:"tremelo",294:"auto pan",304:"compressor",305:"limiter",320:"hexa chorus",321:"tremelo chorus",322:"stereo chorus",323:"space D",324:"3D chorus",336:"stereo delay",337:"modulated delay",338:"3-tap delay",339:"4-tap delay",340:"tremelo control delay",341:"reverb",342:"gate reverb",343:"3D delay",352:"2-pitch shifter",353:"feedback pitch shifter",368:"3D auto",369:"3D manual",370:"Lo-Fi 1",371:"Lo-Fi 2",512:"overdrive - chorus",513:"overdrive - flanger",514:"overdrive - delay",515:"distortion - chorus",516:"distortion - flanger",517:"distortion - delay",518:"enhancer - chorus",519:"enhancer - flanger",520:"enhancer - delay",521:"chorus - delay",522:"flanger - delay",523:"chorus - flanger",524:"rotary multi",1024:"guitar multi 1",1025:"guitar multi 2",1026:"guitar multi 3",1027:"clean guitar multi 1",1028:"clean guitar multi 2",1029:"bass multi",1030:"rhodes multi",1280:"keyboard multi",4352:"chorus / delay",4353:"flanger / delay",4354:"chorus / flanger",4355:"overdrive / distortion",4356:"overdrive / rotary",4357:"overdrive / phaser",4358:"overdrive / auto wah",4359:"phaser / rotary",4360:"phaser / auto wah"},Nt={66307:["drive"],66309:["vowel",u=>"aiueo"[u]],94723:["pre-filter"],94724:["Lo-Fi type"],94725:["post-filter"],94979:["Lo-Fi type"],94980:["fill type",u=>["off","LPF","HPF"][u]],94984:["noise type",u=>["white","pink"][u]],94987:["disc type",u=>["LP","SP","EP","RND"]],94990:["hum type",u=>`${u+5}0Hz`],94993:["M/S",u=>["mono","stereo"][u]]},Je=function(u){return Ut[(u[0]-32<<8)+u[1]]||`0x${u[0].toString(16).padStart(2,"0")}${u[1].toString(16).padStart(2,"0")}`},yt=function(u,e,n){let c=(u[0]-32<<16)+(u[1]<<8)+e,d=Nt[c]||{},s=d[0];if(s!=null&&s.length)return s+=`: ${(d[1]||function(){})(n)||n}`,s},Ze=[68,48,95,78,41,3,110,122,0];var X=function(u=64){return Math.round(2e3*Math.log10(u/64))/100};var wt=function(u){let e=0;return u.forEach(n=>{e+=n,e=e&127}),~e+1&127},ee=function(u,e){let n=0,c=0;for(let d=0;d>s&1)<<7,o=u[d];o+=r,d%8!=0?(e(o,n,u),n++):c=u[d]}},Ie=function(u){let e=Math.floor(u*14.2);return e<128?e:0};var be=["?","gm","gs","xg","g2","mt32","ns5r","ag10","x5d","05rw","k11","sg","krs","s90es","motif"],Et=[[0,0,0,0,121,0,0,56,82,81,0,0,63,63,63],[0,0,4,0,0,127,0,0,0,0,0,0,0,0,0]],Se=[120,127,120,127,120,127,61,62,62,62,120,122,122,127],Ht=[0,3,81,84,88],kt={8:"Off",9:"On",10:"Note aftertouch",11:"cc",12:"pc",13:"Channel aftertouch",14:"Pitch"},et={0:0,1:1,2:3,5:4},St=[[0,24],[0,127],[0,127],[40,88],[0,127],[0,127]],mt=[36,37],qe=[20,21,22,23,24,25,26,28,29,30,31,36,37,64,65],_e=[0,1,2,4,5,6,7,8,10,11,32,38,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,84,91,92,93,94,95,98,99,100,101,128,12,13,16,17,18,19],Lt=[12,13,16,17,18,19],Bt=[33,99,100,32,102,8,9,10],vt=[0,16,25,40,32,64,26,48],x={};be.forEach((u,e)=>{x[u]=e});var p={length:_e.length};_e.forEach((u,e)=>{p[u]=e});var Ct={length:qe.length};qe.forEach((u,e)=>{Ct[u]=e});var q=function(){return!!self.Bun||self.debugMode||!1},Gt=function(u){let e=[],n=0;return u==null||u.forEach(function(c,d){c==247?e.push(u.subarray(n,d)):c==240&&(n=d+1)}),e.length||e.push(u.subarray(0)),q()&&console.debug(e),e},xt=function(u,e="",n="",c=2){return u?`${e}${u.toString().padStart(c,"0")}${n}`:""},$={ch:128,cc:_e.length,nn:128,pl:512,tr:256,cmt:14,rpn:6,ace:8,drm:8,dpn:qe.length,dnc:128,efx:7},R,K,te,oe,z,ne,Tt,P,H,T,b,le,O,A,j,U,L,pe,se,me,v,Pe,Fe,re,ge,W,Ae,$e,V,ye,Y,I,ce,Ue,Ne,ae,we,He,J,D,Xe,tt,M,he,Ee,G,ve,N,Ke,ze,xe,Me,Q,ie,fe,Ce,Te,Re,Mt,ms=(Mt=class extends it{constructor(){super();E(this,z);C(this,"NOTE_IDLE",0);C(this,"NOTE_ATTACK",1);C(this,"NOTE_DECAY",2);C(this,"NOTE_SUSTAIN",3);C(this,"NOTE_HELD",4);C(this,"NOTE_RELEASE",5);C(this,"NOTE_SOSTENUTO_ATTACK",8);C(this,"NOTE_SOSTENUTO_DECAY",9);C(this,"NOTE_SOSTENUTO_SUSTAIN",10);C(this,"NOTE_SOSTENUTO_HELD",11);C(this,"CH_MELODIC",0);C(this,"CH_DRUMS",1);C(this,"CH_DRUM1",2);C(this,"CH_DRUM2",3);C(this,"CH_DRUM3",4);C(this,"CH_DRUM4",5);C(this,"CH_DRUM5",6);C(this,"CH_DRUM6",7);C(this,"CH_DRUM7",8);C(this,"CH_DRUM8",9);E(this,R,0);E(this,K,0);E(this,te,0);E(this,oe,new Array(11));E(this,P,new Uint8Array($.ch));E(this,H,new Uint8Array($.ch));E(this,T,new Uint8Array($.ch));E(this,b,new Uint8Array($.ch*$.cc));E(this,le,new Uint8Array($.ace));E(this,O,new Uint8Array($.ch));E(this,A,new Uint8Array($.ch*$.nn));E(this,j,new Uint8Array($.ch));E(this,U,new Uint16Array($.pl));E(this,L,new Uint8Array($.pl));E(this,pe,new Int16Array($.ch));E(this,se,new Uint8Array($.ch));E(this,me,0);E(this,v,new Uint8Array($.ch*$.rpn));E(this,Pe,new Int8Array($.ch*mt.length));E(this,Fe,new Uint8Array($.drm*$.dpn*$.dnc));E(this,re,new Uint8Array($.ch));E(this,ge,new Uint8Array(128));E(this,W,new Uint8Array($.cmt*8));E(this,Ae,new Uint8Array(1024));E(this,$e,new Uint8Array($.cmt*64));E(this,V,new Uint8Array($.efx*3));E(this,ye,0);E(this,Y,0);E(this,I,100);E(this,ce,0);E(this,Ue,500);E(this,Ne,0);E(this,ae,"");E(this,we,0);E(this,He,0);E(this,J,!0);E(this,D,!1);E(this,Xe,void 0);E(this,tt,new Uint8Array(2));E(this,M,[]);E(this,he,new Uint8Array($.ch));E(this,Ee,new Uint8Array($.tr));C(this,"baseBank",new je("gm","gm2","xg","gs","ns5r","gmega","plg-150vl","plg-150pf","plg-150dx","plg-150an","plg-150dr","plg-100sg","kross","s90es"));C(this,"userBank",new je("gm"));C(this,"initOnReset",!1);C(this,"aiEfxName","");E(this,G,[]);E(this,ve,void 0);E(this,N,{nOff:(e,n)=>{let c=e*128+n,d=t(this,U).lastIndexOf(c);d>-1&&(t(this,b)[$.cc*e+p[64]]>63?(t(this,L)[d]=this.NOTE_HELD,this.dispatchEvent("note",{part:e,note:n,velo:t(this,A)[c],state:this.NOTE_HELD})):t(this,b)[$.cc*e+p[66]]>63&&t(this,L)[d]==this.NOTE_SOSTENUTO_SUSTAIN?(t(this,L)[d]=this.NOTE_SOSTENUTO_HELD,this.dispatchEvent("note",{part:e,note:n,velo:t(this,A)[c],state:this.NOTE_SOSTENUTO_HELD})):(t(this,U)[d]=0,t(this,A)[c]=0,t(this,L)[d]=this.NOTE_IDLE,this.dispatchEvent("note",{part:e,note:n,velo:0,state:this.NOTE_IDLE})))},nOn:(e,n,c)=>{let d=e*128+n,s=0;for(t(this,j)[e]&&t(this,N).ano(e);t(this,L)[s]>0&&t(this,U)[s]!=d;)s++;s<$.pl?(t(this,U)[s]=d,t(this,A)[d]=c,t(this,L)[s]=this.NOTE_SUSTAIN,t(this,se)[e]{},cAt:(e,n)=>{},hoOf:e=>{t(this,L).forEach((n,c)=>{if(n==this.NOTE_HELD){let d=t(this,U)[c],s=d>>7;e==s&&(t(this,L)[c]=this.NOTE_IDLE,t(this,U)[c]=0,t(this,A)[d]=0,this.dispatchEvent("note",{part:e,note:d&127,velo:0,state:this.NOTE_IDLE}))}})},soOn:e=>{t(this,L).forEach((n,c)=>{let d;switch(n){case this.NOTE_ATTACK:{d=this.NOTE_SOSTENUTO_ATTACK;break}case this.NOTE_DECAY:{d=this.NOTE_SOSTENUTO_DECAY;break}case this.NOTE_SUSTAIN:{d=this.NOTE_SOSTENUTO_SUSTAIN;break}}if(d){t(this,L)[c]=d;let s=t(this,U)[c];this.dispatchEvent("note",{part:e,note:s&127,velo:t(this,A)[s],state:d})}})},soOf:e=>{t(this,L).forEach((n,c)=>{if(n==this.NOTE_SOSTENUTO_HELD){let d=t(this,U)[c],s=d>>7;e==s&&(t(this,L)[c]=this.NOTE_IDLE,t(this,U)[c]=0,t(this,A)[d]=0,this.dispatchEvent("note",{part:e,note:d&127,velo:0,state:this.NOTE_IDLE}))}})},ano:e=>{t(this,U).forEach((n,c,d)=>{let s=n>>7,r=n&127;n==0&&t(this,A)[0]==0||s==e&&t(this,N).nOff(s,r)})}});E(this,Ke,{8:function(e){let n=e.channel,c=e.data[0];t(this,N).nOff(n,c)},9:function(e){let n=e.channel;t(this,P)[n]=1;let c=e.data[0],d=e.data[1];d>0?t(this,N).nOn(n,c,d):t(this,N).nOff(n,c)},10:function(e){let n=e.channel,c=n*128+e.data[0];t(this,U).indexOf(c)>-1&&(t(this,A)[c]=data[1],this.dispatchEvent("note",{part:n,note:e.data[0],velo:e.data[1],state:this.NOTE_SUSTAIN}))},11:function(e){let n=e.channel;[0,32].indexOf(e.data[0])>-1&&(()=>{switch(t(this,R)){case x.s90es:case x.motif:{if(e.data[0]==0){[0,63].indexOf(e.data[1])>-1&&(t(this,P)[n]=1);break}e.data[1]&&(t(this,P)[n]=1);break}default:{t(this,P)[n]=1;break}}})();let c=n*$.cc;switch(e.data[0]){case 96:return;case 97:return;case 120:return;case 121:{t(this,N).ano(n),t(this,pe)[n]=0;let d=n*$.cc;t(this,b)[d+p[1]]=0,t(this,b)[d+p[5]]=0,t(this,b)[d+p[64]]=0,t(this,b)[d+p[65]]=0,t(this,b)[d+p[66]]=0,t(this,b)[d+p[67]]=0,t(this,b)[d+p[11]]=127,t(this,b)[d+p[101]]=127,t(this,b)[d+p[100]]=127,t(this,b)[d+p[99]]=127,t(this,b)[d+p[98]]=127;return}case 123:{t(this,N).ano(n);return}case 124:{t(this,N).ano(n);return}case 125:{t(this,N).ano(n);return}case 126:{t(this,j)[n]=1,t(this,N).ano(n);return}case 127:{t(this,j)[n]=0,t(this,N).ano(n);return}}if(p[e.data[0]]==null)console.warn(`cc${e.data[0]} is not accepted.`);else{switch(Lt.indexOf(e.data[0])>-1&&this.allocateAce(e.data[0]),e.data[0]){case 0:{if(q()&&console.debug(`${be[t(this,R)]}, CH${n+1}: ${e.data[1]}`),t(this,R)==0)e.data[1]<48?(t(this,T)[n]>0&&(e.data[1]=t(this,b)[c],e.data[1]=120,console.debug(`Forced channel ${n+1} to stay drums.`)),e.data[1]>0&&(console.debug(`Roland GS detected with MSB: ${e.data[1]}`),this.switchMode("gs"))):e.data[1]==62?this.switchMode("x5d"):e.data[1]==63?this.switchMode("krs"):(e.data[1]==64||e.data[1]==127)&&this.switchMode("xg");else if(t(this,R)==x.gs)e.data[1]<56&&t(this,T)[n]>0&&(e.data[1]=t(this,b)[c],e.data[1]=120,console.debug(`Forced channel ${n+1} to stay drums.`));else if(t(this,R)==x.gm)e.data[1]<48?t(this,T)[n]>0&&(e.data[1]=120,this.switchMode("gs",!0),console.debug(`Forced channel ${n+1} to stay drums.`)):(e.data[1]==64||e.data[1]==127)&&this.switchMode("xg",!0);else if(t(this,R)==x.x5d){if(e.data[1]>0&&e.data[1]<8)this.switchMode("05rw",!0);else if(e.data[1]==56){let d=0;for(let s=0;s<16;s++){let r=t(this,b)[$.cc*s];(r==56||r==62)&&d++}d>14&&this.switchMode("ag10",!0)}}switch(t(this,R)){case x.xg:{[126,127].indexOf(e.data[1])>-1?t(this,T)[n]==0&&(this.setChType(n,this.CH_DRUM2),console.debug(`CH${n+1} set to drums by MSB.`)):t(this,T)[n]>0&&(this.setChType(n,this.CH_MELODIC),console.debug(`CH${n+1} set to melodic by MSB.`));break}case x["05rw"]:case x.x5d:case x.ns5r:{[61,62,126,127].indexOf(e.data[1])>-1?t(this,T)[n]==0&&(this.setChType(n,this.CH_DRUM2),console.debug(`CH${n+1} set to drums by MSB.`)):t(this,T)[n]>0&&(this.setChType(n,this.CH_MELODIC),console.debug(`CH${n+1} set to melodic by MSB.`));break}case x.g2:{e.data[1]==120?t(this,T)[n]==0&&(this.setChType(n,this.CH_DRUMS),console.debug(`CH${n+1} set to drums by MSB.`)):t(this,T)[n]>0&&(this.setChType(n,this.CH_MELODIC),console.debug(`CH${n+1} set to melodic by MSB.`));break}}this.dispatchEvent("voice",{part:n});break}case 6:{if(t(this,me)){[x.xg,x.gs,x.ns5r].indexOf(t(this,R))<0&&console.warn(`NRPN commits are not available under "${be[t(this,R)]}" mode, even when they are supported in Octavia.`);let d=t(this,b)[c+p[99]],s=t(this,b)[c+p[98]];if(d==1){let r=Bt.indexOf(s);if(r>-1)t(this,b)[c+p[71+r]]=e.data[1],q()&&console.debug(`Redirected NRPN 1 ${s} to cc${71+r}.`),this.dispatchEvent("cc",{part:n,cc:71+r,data:e.data[1]});else{let o=mt.indexOf(s);o>-1?t(this,Pe)[n*10+o]=e.data[1]-64:console.warn(`NRPN 0x01${s.toString(16).padStart(2,"0")} is not supported.`),q()&&console.debug(`CH${n+1} voice NRPN ${s} commit`)}}else{if(qe.indexOf(d)<0){let o=`NRPN 0x${d.toString(16).padStart(2,"0")}${s.toString(16).padStart(2,"0")} `;d==127?console.warn(`${o}is not necessary. Consider removing it.`):console.warn(`${o}is not supported.`)}else{let o=t(this,T)[n]-2;o<0?console.warn(`CH${n+1} cannot accept drum NRPN as type ${Ge[t(this,T)[n]]}.`):t(this,Fe)[(o*$.dpn+Ct[d])*$.dnc+s]=e.data[1]-64}q()&&console.debug(`CH${n+1} (${Ge[t(this,T)[n]]}) drum NRPN ${d} commit`)}}else{let d=et[t(this,b)[c+p[100]]];t(this,b)[c+p[101]]==0&&d!=null&&(q()&&console.debug(`CH${n+1} RPN 0 ${t(this,b)[c+p[100]]} commit: ${e.data[1]}`),e.data[1]=Math.min(Math.max(e.data[1],St[d][0]),St[d][1]),t(this,v)[n*$.rpn+d]=e.data[1])}break}case 32:{switch(t(this,R)){case x.s90es:case x.motif:{t(this,T)[n]=+([32,40].indexOf(e.data[1])>-1)<<1;break}}this.dispatchEvent("voice",{part:n});break}case 38:{t(this,me)||t(this,b)[c+101]==0&&et[t(this,b)[c+100]]!=null&&(t(this,v)[n*$.rpn+et[t(this,b)[c+100]]+1]=e.data[1]);break}case 64:{e.data[1]<64&&t(this,N).hoOf(n);break}case 66:{e.data[1]>>6?t(this,N).soOn(n):t(this,N).soOf(n);break}case 98:case 99:{w(this,me,1);break}case 100:case 101:{w(this,me,0);break}}t(this,b)[c+p[e.data[0]]]=e.data[1],this.dispatchEvent("cc",{part:n,cc:e.data[0],data:e.data[1]})}},12:function(e){let n=e.channel;switch(t(this,R)){case x.s90es:case x.motif:{e.data&&(t(this,P)[n]=1);break}default:t(this,P)[n]=1}t(this,O)[n]=e.data,t(this,re)[n]=0,q()&&console.debug(`T:${e.track} C:${n} P:${e.data}`),this.dispatchEvent("voice",{part:n})},13:function(e){let n=this,c=e.channel;t(this,U).forEach(function(d){let s=d>>7;c==s&&(t(n,A)[d]=e.data,n.dispatchEvent("note",{part:c,note:d&127,velo:e.data,state:n.NOTE_SUSTAIN}))})},14:function(e){let n=e.channel;t(this,pe)[n]=e.data[1]*128+e.data[0]-8192,this.dispatchEvent("pitch",{part:n,pitch:this.getPitchShift(n)})},15:function(e){Gt(e.data).forEach(n=>{let c=n[0],d=n[1];(t(this,ze)[c]||function(){console.debug(`Unknown manufacturer ${c}.`)})(d,n.subarray(2),e.track)})},248:function(e){},250:function(e){},251:function(e){},252:function(e){},254:function(e){},255:function(e){(t(this,G)[e.meta]||function(c,d,s){}).call(this,e.data,e.track,e.meta),e.meta!=32&&w(this,ce,0);let n=Ht.indexOf(e.meta)>-1;if(q()&&console.debug(e),n)return e.reply="meta",e}});E(this,ze,{64:(e,n,c)=>{t(this,Ce).run(n,c,e)},65:(e,n,c)=>{if(n[0]<16)t(this,ie).run(n,c,e),console.warn("Unknown device SysEx!");else{let d=n[n.length-1],s=wt(n.subarray(2,n.length-1));d==s?t(this,ie).run(n.subarray(0,n.length-1),c,e):console.warn(`Bad GS checksum ${d}. Should be ${s}.`)}},66:(e,n,c)=>{t(this,fe).run(n,c,e)},67:(e,n,c)=>{t(this,Q).run(n,c,e)},68:(e,n,c)=>{t(this,Re).run(n,c,e)},71:(e,n,c)=>{t(this,Te).run(n,c,e)},126:(e,n,c)=>{t(this,xe).run(n,c,e)},127:(e,n,c)=>{this.switchMode("gm"),t(this,Me).run(n,c,e)}});E(this,xe,void 0);E(this,Me,void 0);E(this,Q,void 0);E(this,ie,void 0);E(this,fe,void 0);E(this,Ce,void 0);E(this,Te,void 0);E(this,Re,void 0);let e=this;w(this,z,new Uint8Array(256),Tt),t(this,oe)[10]=new Uint8Array(512),w(this,ve,new Z),this.userBank.strictMode=!0,this.userBank.load(`MSB PRG LSB NME
+062 000 000
+122 000 000
+122 001 000
+122 002 000
+122 003 000
+122 004 000
+122 005 000
+122 006 000 `),t(this,G)[1]=function(s){switch(s.slice(0,2)){case"@I":{w(this,D,!0),t(this,M).unshift(`Kar.Info: ${s.slice(2)}`);break}case"@K":{w(this,D,!0),t(this,M).unshift("Karaoke mode active."),console.debug(`Karaoke mode active: ${s.slice(2)}`);break}case"@L":{w(this,D,!0),t(this,M).unshift(`Language: ${s.slice(2)}`);break}case"@T":{w(this,D,!0),t(this,M).unshift(`Ka.Title: ${s.slice(2)}`);break}case"@V":{w(this,D,!0),t(this,M).unshift(`Kara.Ver: ${s.slice(2)}`);break}case"XF":{let r=s.slice(2).split(":");switch(r[0]){case"hd":{r.slice(1).forEach((o,i)=>{o.length&&t(this,M).unshift(`${["SongDate","SnRegion","SongCat.","SongBeat","SongInst","Sn.Vocal","SongCmp.","SongLrc.","SongArr.","SongPerf","SongPrg.","SongTags"][i]}: ${o}`)});break}case"ln":{r.slice(1).forEach((o,i)=>{o.length&&t(this,M).unshift(`${["Kar.Lang","Kar.Name","Kar.Cmp.","Kar.Lrc.","kar.Arr.","Kar.Perf","Kar.Prg."][i]}: ${o}`)});break}default:t(this,M).unshift(`XGF_Data: ${s}`)}break}default:t(this,D)?s[0]=="\\"?t(this,M).unshift(`@ ${s.slice(1)}`):s[0]=="/"?t(this,M).unshift(s.slice(1)):t(this,M)[0]+=s:(t(this,M)[0]=s,t(this,M).unshift(""))}},t(this,G)[2]=function(s){t(this,M).unshift(`Copyrite: ${s}`)},t(this,G)[3]=function(s,r){r<1&&t(this,ce)<1&&t(this,M).unshift(`TrkTitle: ${s}`)},t(this,G)[4]=function(s,r){t(this,M).unshift(`${xt(t(this,ce),""," ")}Instrmnt: ${s}`)},t(this,G)[5]=function(s){s.trim()==""?t(this,M).unshift(""):t(this,M)[0]+=`${s}`},t(this,G)[6]=function(s){t(this,M).unshift(`${xt(t(this,ce),""," ")}C.Marker: ${s}`)},t(this,G)[7]=function(s){t(this,M).unshift(`CuePoint: ${s}`)},t(this,G)[32]=function(s){w(this,ce,s[0]+1)},t(this,G)[33]=function(s,r){console.debug(`Track ${r} requests to get assigned to output ${s}.`),t(e,Ee)[r]=s+1},t(this,G)[81]=function(s,r){w(e,Ue,s/1e3)},t(this,G)[127]=function(s,r){t(e,ve).run(s,r)},t(this,ve).default=function(s){console.warn(`Unrecognized sequencer-specific byte sequence: ${s}`)},t(this,ve).add([67,0,1],function(s,r){t(e,Ee)[r]=s[0]+1}),w(this,xe,new Z("universal non-realtime")),w(this,Me,new Z("universal realtime")),w(this,Q,new Z("Yamaha")),w(this,ie,new Z("Roland")),w(this,fe,new Z("Korg")),w(this,Ce,new Z("Kawai")),w(this,Te,new Z("Akai")),w(this,Re,new Z("Casio"));let n=function(s){console.info(`Unrecognized SysEx in "${this.name}" set.`,s)};t(this,xe).default=n,t(this,Me).default=n,t(this,Q).default=n,t(this,ie).default=n,t(this,fe).default=n,t(this,Ce).default=n,t(this,Te).default=n,t(this,Re).default=n,t(this,xe).add([9],s=>{e.switchMode(["gm","?","g2"][s[0]-1],!0),w(e,D,t(e,D)||!1),console.info(`MIDI reset: ${["GM","Init","GM2"][s[0]-1]}`),s[0]==2&&e.init()}),t(this,Me).add([4,1],s=>{w(e,I,((s[1]<<7)+s[0])/16383*100)}).add([4,3],s=>((s[1]<<7)+s[0]-8192)/8192).add([4,4],s=>s[1]-64),t(this,Q).add([76,0,0],s=>{switch(s[0]){case 125:{console.info(`XG drum setup reset: ${s}`);break}case 126:{e.switchMode("xg",!0),w(e,D,!1),console.info("MIDI reset: XG");break}default:{let r=[0,0,0,0],o=(i,a)=>{r[a]=i};if(s.subarray(1).forEach((i,a)=>{let l=a+s[0];([o,o,o,o,h=>{w(this,I,h*129/16383*100)},h=>{},h=>{}][l]||(()=>{}))(i,a)}),s[0]<4){let i=0;r.forEach(a=>{i=i<<4,i+=a}),i-=1024}}}}).add([76,2,1],s=>{let r="XG ";s[0]<32?(r+="reverb ",s.subarray(1).forEach((o,i)=>{([a=>{e.setEffectTypeRaw(0,!1,a),console.info(`${r}main type: ${Be[a]}`)},a=>{e.setEffectTypeRaw(0,!0,a),console.debug(`${r}sub type: ${a+1}`)},a=>{console.debug(`${r}time: ${ft(a)}s`)},a=>{console.debug(`${r}diffusion: ${a}`)},a=>{console.debug(`${r}initial delay: ${a}`)},a=>{console.debug(`${r}HPF cutoff: ${De[a]}Hz`)},a=>{console.debug(`${r}LPF cutoff: ${De[a]}Hz`)},a=>{console.debug(`${r}width: ${a}`)},a=>{console.debug(`${r}height: ${a}`)},a=>{console.debug(`${r}depth: ${a}`)},a=>{console.debug(`${r}wall type: ${a}`)},a=>{console.debug(`${r}dry/wet: ${a}`)},a=>{console.debug(`${r}send: ${X(a)}dB`)},a=>{console.debug(`${r}pan: ${a-64}`)},!1,!1,a=>{console.debug(`${r}delay: ${a}`)},a=>{console.debug(`${r}density: ${a}`)},a=>{console.debug(`${r}balance: ${a}`)},a=>{},a=>{console.debug(`${r}feedback: ${a}`)},a=>{}][s[0]+i]||function(){console.warn(`Unknown XG reverb address: ${s[0]}.`)})(o)})):s[0]<64?(r+="chorus ",s.subarray(1).forEach((o,i)=>{([a=>{e.setEffectTypeRaw(1,!1,a),console.info(`${r}main type: ${Be[a]}`)},a=>{e.setEffectTypeRaw(1,!0,a),console.debug(`${r}sub type: ${a+1}`)},a=>{console.debug(`${r}LFO: ${ht[a]}Hz`)},a=>{},a=>{console.debug(`${r}feedback: ${a}`)},a=>{console.debug(`${r}delay offset: ${dt(a)}ms`)},a=>{},a=>{console.debug(`${r}low: ${De[a]}Hz`)},a=>{console.debug(`${r}low: ${a-64}dB`)},a=>{console.debug(`${r}high: ${De[a]}Hz`)},a=>{console.debug(`${r}high: ${a-64}dB`)},a=>{console.debug(`${r}dry/wet: ${a}`)},a=>{console.debug(`${r}send: ${X(a)}dB`)},a=>{console.debug(`${r}pan: ${a-64}`)},a=>{console.debug(`${r}to reverb: ${X(a)}dB`)},!1,a=>{},a=>{},a=>{},a=>{console.debug(`${r}LFO phase diff: ${(a-64)*3}deg`)},a=>{console.debug(`${r}input mode: ${a?"stereo":"mono"}`)},a=>{}][s[0]-32+i]||function(){console.warn(`Unknown XG chorus address: ${s[0]}.`)})(o)})):s[0]<86?(r+="variation ",s.subarray(1).forEach((o,i)=>{([a=>{e.setEffectTypeRaw(2,!1,a),console.info(`${r}main type: ${Be[a]}`)},a=>{e.setEffectTypeRaw(2,!0,a),console.debug(`${r}sub type: ${a+1}`)}][s[0]-64+i]||function(){})(o)})):s[0]<97?(r+="variation ",s.subarray(1).forEach((o,i)=>{[a=>{console.debug(`${r}send: ${X(a)}dB`)},a=>{console.debug(`${r}pan: ${a-64}`)},a=>{console.debug(`${r}to reverb: ${X(a)}dB`)},a=>{console.debug(`${r}to chorus: ${X(a)}dB`)},a=>{console.debug(`${r}connection: ${a?"system":"insertion"}`)},a=>{console.debug(`${r}channel: CH${a+1}`)},a=>{console.debug(`${r}mod wheel: ${a-64}`)},a=>{console.debug(`${r}bend wheel: ${a-64}`)},a=>{console.debug(`${r}channel after touch: ${a-64}`)},a=>{console.debug(`${r}AC1: ${a-64}`)},a=>{console.debug(`${r}AC2: ${a-64}`)}][s[0]-86+i](o)})):s[0]>111&&s[0]<118?r+="variation ":console.warn(`Unknown XG variation address: ${s[0]}`)}).add([76,2,64],s=>{s.subarray(1).forEach((r,o)=>{let i=o+s[0];if(i==0)console.debug(`XG EQ preset: ${["flat","jazz","pop","rock","classic"][r]}`);else{let a=i-1>>2,l=i-1&3,h=`XG EQ ${a} ${["gain","freq","Q","shape"][l]}: `;[()=>{console.debug(`${h}${r-64}dB`)},()=>{console.debug(`${h}${r} (raw)`)},()=>{console.debug(`${h}${r/10}`)},()=>{console.debug(`${h}${["shelf","peak"][+!!r]}`)}][l]()}})}).add([76,3],s=>{let r=s[0],o=s[1],i=`XG Insertion ${s[0]+1} `;s.subarray(2).forEach((a,l)=>{([h=>{e.setEffectTypeRaw(3+r,!1,h),console.info(`${i}main type: ${Be[h]}`)},h=>{e.setEffectTypeRaw(3+r,!0,h),console.debug(`${i}sub type: ${h+1}`)}][o+l]||function(){})(a)})}).add([76,6,0],s=>{let r=s[0];r<64?e.setLetterDisplay(s.subarray(1),"XG letter display",r):w(e,we,Date.now())}).add([76,7,0],s=>{let r=s[0];w(e,K,0),w(e,te,Date.now()+3200),t(e,z,ne).fill(0);let o=s.subarray(1);for(let i=0;i>6-y&1,y++})}).add([76,8],(s,r)=>{let o=e.chRedir(s[0],r,!0),i=s[1],a=$.cc*o,l=`XG CH${o+1} `,h=`Unknown XG part address ${i}.`;s.subarray(2).forEach((f,g)=>{i<1?console.debug(h):i<41?([()=>{t(e,b)[a+p[0]]=f},()=>{t(e,b)[a+p[32]]=f},()=>{t(e,O)[o]=f},()=>{let y=e.chRedir(f,r,!0);t(e,H)[o]=y,o!=y&&(e.buildRchTree(),console.info(`${l}receives from CH${y+1}`))},()=>{t(e,j)[o]=+!f},()=>{},()=>{e.setChType(o,f,x.xg),console.debug(`${l}type: ${Ge[f]||f}`)},()=>{t(e,v)[$.rpn*o+3]=f},!1,!1,()=>{t(e,b)[a+p[7]]=f},!1,!1,()=>{t(e,b)[a+p[10]]=f||128},!1,!1,()=>{t(e,b)[a+p[128]]=f},()=>{t(e,b)[a+p[93]]=f},()=>{t(e,b)[a+p[91]]=f},()=>{t(e,b)[a+p[94]]=f},()=>{t(e,b)[a+p[76]]=f},()=>{t(e,b)[a+p[77]]=f},()=>{t(e,b)[a+p[78]]=f},()=>{t(e,b)[a+p[74]]=f},()=>{t(e,b)[a+p[71]]=f},()=>{t(e,b)[a+p[73]]=f},()=>{t(e,b)[a+p[75]]=f},()=>{t(e,b)[a+p[72]]=f}][i+g-1]||(()=>{}))():i<48?console.debug(h):i<111?i>102&&i<105&&(t(e,b)[a+p[[5,65][i&1]]]=f):i<114?console.debug(h):i<116?console.debug(`${l}EQ ${["bass","treble"][i&1]} gain: ${f-64}dB`):i<118?console.debug(h):i<120?console.debug(`${l}EQ ${["bass","treble"][i&1]} freq: ${f}`):console.debug(h)})}).add([76,9],(s,r)=>{let o=e.chRedir(s[0],r,!0),i=s[1],a=`PLG-150VL CH${o+1} `;s.subarray(2).forEach((l,h)=>{let f=h+i;switch(f){case 1:{console.info(`${a}breath mode: ${["system","breath","velocity","touch EG"][l]}`);break}case 0:case 27:case 28:break;default:if(f<27){let g=["pressure","embouchure","tonguing","scream","breath noise","growl","throat formant","harmonic enhancer","damping","absorption","amplification","brightness"][f-3>>1];f&1?f<23?(console.debug(`${a}${g} control source: ${pt(l)}`),l&&l<96&&e.allocateAce(l)):console.debug(`${a}${g} scale break point: ${l}`):console.debug(`${a}${g} depth: ${l-64}`)}}})}).add([76,10],s=>{}).add([76,16],s=>{}).add([76,17,0,0],s=>{}).add([76,112],s=>{console.debug(`XG enable PLG-1${["50VL","00SG","50DX"][s[0]]} for CH${s[2]+1}.`)}).add([73,0,0],(s,r)=>{let o=s[0];s.subarray(1).forEach((i,a)=>{let l=o+a;l==8?console.debug(`MU1000 set LCD contrast to ${i}.`):l>9&&l<16&&[()=>{e.dispatchEvent("channelactive",i)},()=>{i<8?(e.dispatchEvent("channelmin",i<<4),console.info(`Octavia System: Minimum CH${(i<<4)+1}`)):(e.dispatchEvent("channelreset"),console.info("Octavia System: Clear channel ranges"))},()=>{i<8?(e.dispatchEvent("channelmax",(i<<4)+15),console.info(`Octavia System: Maximum CH${(i<<4)+16}`)):(e.dispatchEvent("channelreset"),console.info("Octavia System: Clear channel ranges"))},()=>{e.dispatchEvent("channelreset"),console.info("Octavia System: Clear channel ranges")},()=>{w(e,J,!!i),console.info(`Octavia System: RS receiving ${["dis","en"][i]}abled.`)}][l-10]()})}).add([73,10,0],(s,r)=>{let o=s[0],i=`MU1000 RS${t(e,J)?"":" (ignored)"}: `;if(o<16)switch(o){case 2:{let a=e.chRedir(0,r,!0);t(e,J)&&(e.dispatchEvent("channelmin",a),e.dispatchEvent("channelmax",a+63)),console.info(`${i}Show CH1~64`);break}case 3:{let a=e.chRedir(s[1]<<5,r,!0);t(e,J)&&e.dispatchEvent("channelmin",a),t(e,J)&&e.dispatchEvent("channelmax",a+31),console.info(`${i}Show CH${a+1}~CH${a+32}`);break}default:console.debug(`${i}unknown switch ${o} invoked.`)}else if(o<32){if(t(e,J)){let a=e.chRedir(o-16+(t(e,He)<<4),r,!0);e.dispatchEvent("channelactive",a)}}else if(o<36){let a=e.chRedir(o-32<<4,r,!0);t(e,J)&&(e.dispatchEvent("channelmin",a),e.dispatchEvent("channelmax",a+15),w(e,He,o-32)),console.info(`${i}Show CH${a+1}~CH${a+16}`)}}).add([93,3],(s,r)=>{let o=e.chRedir(s[0],r,!0),i=`PLG-100SG CH${o+1} `,a=Date.now();if(s[1]==0){let l="",h=0;s.subarray(2).forEach((f,g)=>{g%2==0?l+=ut[f]||f.toString().padStart("0"):h+=f*13}),a>=t(e,Ne)&&t(e,M).unshift("SG Lyric: "),t(e,M)[0]+=`${bt(l)}`,w(e,Ne,a+Math.ceil(h/2)+t(e,Ue)),q()&&console.debug(`${i}vocals: ${l}`)}else console.warn(`Unknown PLG-100SG data: ${s}`)}),t(this,Q).add([76,48],s=>{}).add([76,49],s=>{}).add([76,50],s=>{}).add([76,51],s=>{}),t(this,Q).add([89,0],(s,r,o)=>{if(e.eprom){let i=s[0],a=(s[1]<<14)+(s[2]<<7)+s[3]+(e.eprom.offset||0);q()&&console.debug(`MU1000 EPROM trail to 0x${a.toString(16).padStart(6,"0")}, ${i} bytes.`);let l=e.eprom.data;s.subarray(4).forEach((h,f)=>{let g=f>>3,y=f&7;if(y==7)for(let S=0;S<7;S++)l[a+7*g+S]+=(h>>6-S&1)<<7;else l[a+7*g+y]=h})}}).add([89,1],(s,r,o)=>{let i=(s[0]<<21)+(s[1]<<14)+(s[2]<<7)+s[3];q()&&console.debug(`MU1000 EPROM jump to 0x${i.toString(16).padStart(6,"0")}.`),e.eprom&&(e.eprom.offset=i)}).add([89,2],(s,r,o)=>{if(e.eprom){let i=(s[0]<<21)+(s[1]<<14)+(s[2]<<7)+s[3]+(e.eprom.offset||0);q()&&console.debug(`MU1000 EPROM write to 0x${i.toString(16).padStart(6,"0")}.`);let a=e.eprom.data;s.subarray(4).forEach((l,h)=>{let f=h>>3,g=h&7;if(g==7)for(let y=0;y<7;y++)a[i+7*f+y]+=(l>>6-y&1)<<7;else a[i+7*f+g]=l})}}).add([89,3],(s,r,o)=>{}),t(this,Q).add([39,48],(s,r,o)=>{}).add([43,0,0],(s,r,o)=>{let i=[0,0,0,0],a=(l,h)=>{i[h]=l};if(s.subarray(1).forEach((l,h)=>{let f=h+s[0];[a,a,a,a,()=>{w(this,I,l*129/16383*100)},()=>l-64,()=>l||128,()=>l,()=>l,()=>{console.debug(`TG300 variation on cc${l}.`)}][f](l,f)}),s[0]<4){let l=0;i.forEach(h=>{l=l<<4,l+=h}),l-=1024}}).add([43,1,0],(s,r,o)=>{}).add([43,2],(s,r,o)=>{let i=e.chRedir(s[0],r,!0),a=s[1],l=$.cc*i,h=`TG300 CH${i+1} `;s.subarray(2).forEach((f,g)=>{g<5?([()=>{},()=>{t(e,b)[l+p[0]]=f},()=>{t(e,b)[l+p[32]]=f},()=>{t(e,O)[i]=f},()=>{let y=e.chRedir(f,r,!0);t(e,H)[i]=y,i!=y&&(e.buildRchTree(),console.info(`${h}receives from CH${y+1}`))}][g+a]||(()=>{}))(f,g+a):g<21||(g<47?([()=>{t(e,j)[i]=+!f},()=>{},()=>{},()=>{t(e,v)[$.rpn*i+3]=f},()=>{},()=>{t(e,b)[l+p[7]]=f},!1,!1,()=>{t(e,b)[l+p[10]]=f||128},!1,!1,()=>{console.debug(`${h} AC1 at cc${f}`)},()=>{console.debug(`${h} AC2 at cc${f}`)},()=>{t(e,b)[l+p[128]]=f},()=>{t(e,b)[l+p[93]]=f},()=>{t(e,b)[l+p[91]]=f},()=>{t(e,b)[l+p[94]]=f},()=>{t(e,b)[l+p[76]]=f},()=>{t(e,b)[l+p[77]]=f},()=>{t(e,b)[l+p[74]]=f},()=>{t(e,b)[l+p[71]]=f},()=>{t(e,b)[l+p[73]]=f},()=>{t(e,b)[l+p[75]]=f},()=>{t(e,b)[l+p[72]]=f},()=>{t(e,b)[l+p[78]]=f}][g+a-21]||(()=>{}))(f,g+a):g<95||([()=>{t(e,b)[l+p[65]]=f},()=>{t(e,b)[l+p[5]]=f}][g+a-95]||(()=>{}))(f,g+a))})}).add([43,7,0],(s,r,o)=>{let i=s[0];e.setLetterDisplay(s.subarray(1),"TG300 letter display",i)}).add([43,7,1],(s,r,o)=>{w(e,K,0),w(e,te,Date.now()+3200),t(e,z,ne).fill(0),s.forEach(function(i,a){let l=Math.floor(a/16),h=a%16,f=(h*3+l)*7,g=7,y=0;for(f-=h*5,l==2&&(g=2);y>6-y&1,y++})}),t(this,ie).add([66,18,0,0,127],(s,r,o)=>{e.switchMode("gs",!0),t(e,b)[$.cc*9]=120,t(e,b)[$.cc*25]=120,t(e,b)[$.cc*41]=120,t(e,b)[$.cc*57]=120,w(e,Y,3),w(e,D,!1),t(e,he).fill(0),console.info(`GS system to ${["single","dual"][s[0]]} mode.`)}).add([66,18,64,0],(s,r,o)=>{switch(s[0]){case 127:{e.switchMode("gs",!0),t(e,b)[$.cc*9]=120,t(e,b)[$.cc*25]=120,t(e,b)[$.cc*41]=120,t(e,b)[$.cc*57]=120,w(e,D,!1),t(e,he).fill(0),console.info("MIDI reset: GS");break}default:{let i=[0,0,0,0],a=(l,h)=>{i[h]=l};if(s.subarray(1).forEach((l,h)=>{let f=h+s[0];[a,a,a,a,g=>{w(this,I,g*129/16383*100)},g=>{},g=>{}][f](l,h)}),s[0]<4){let l=0;i.forEach(h=>{l=l<<4,l+=h}),l-=1024}}}}).add([66,18,64,1],s=>{let r=s[0];if(r<16){let o="".padStart(r," ");s.subarray(1).forEach((i,a)=>{o+=String.fromCharCode(Math.max(32,i))}),o=o.padEnd(16," "),console.debug(`GS patch name: ${o}`)}else r<48||(r<65?s.subarray(1).forEach((o,i)=>{let a=`GS ${r+i>55?"chorus":"reverb"} `;([()=>{console.info(`${a}type: ${Ye[o]}`),e.setEffectType(0,40,o)},()=>{},()=>{},()=>{},()=>{},()=>{},!1,()=>{console.debug(`${a}predelay: ${o}ms`)},()=>{console.info(`${a}type: ${gt[o]}`),e.setEffectType(1,40,16+o)},()=>{},()=>{},()=>{},()=>{},()=>{},()=>{},()=>{console.debug(`${a}to reverb: ${X(o)}`)},()=>{console.debug(`${a}to delay: ${X(o)}`)}][r+i-48]||(()=>{}))()}):r<80?console.debug(`Unknown GS patch address: ${r}`):r<91?s.subarray(1).forEach((o,i)=>{let a="GS delay ";([()=>{console.info(`${a}type: ${$t[o]}`),e.setEffectType(2,40,32+o)},()=>{},()=>{},()=>{},()=>{},()=>{},()=>{},()=>{},()=>{},()=>{},()=>{console.debug(`${a}to reverb: ${X(o)}`)}][r+i-80]||(()=>{}))()}):console.debug(`Unknown GS patch address: ${r}`))}).add([66,18,64,2],s=>{let r="GS EQ ";s.subarray(1).forEach((o,i)=>{([()=>{console.debug(`${r}low freq: ${[200,400][o]}Hz`)},()=>{console.debug(`${r}low gain: ${o-64}dB`)},()=>{console.debug(`${r}high freq: ${[3e3,6e3][o]}Hz`)},()=>{console.debug(`${r}high gain: ${o-64}dB`)}][s[0]+i]||function(){console.warn(`Unknown GS EQ address: ${s[0]+i}`)})()})}).add([66,18,64,3],s=>{let r="GS EFX ",o=function(i,a){let l=yt(t(e,V).subarray(10,12),a,i);l&&console.debug(`${r}${Je(t(e,V).subarray(10,12))} ${l}`)};s.subarray(1).forEach((i,a)=>{([()=>{e.setEffectTypeRaw(3,!1,32+i)},()=>{e.setEffectTypeRaw(3,!0,i),console.info(`${r}type: ${Je(t(e,V).subarray(10,12))}`)},!1,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,()=>{console.debug(`${r}to reverb: ${X(i)}dB`)},()=>{console.debug(`${r}to chorus: ${X(i)}dB`)},()=>{console.debug(`${r}to delay: ${X(i)}dB`)},!1,()=>{console.debug(`${r}1 source: ${i}`),i&&i<96&&e.allocateAce(i)},()=>{console.debug(`${r}1 depth: ${i-64}`)},()=>{console.debug(`${r}2 source: ${i}`),i&&i<96&&e.allocateAce(i)},()=>{console.debug(`${r}2 depth: ${i-64}`)},()=>{console.debug(`${r}to EQ: ${i?"ON":"OFF"}`)}][s[0]+a]||function(l,h){console.warn(`Unknown GS EFX address: ${h}`)})(i,s[0]+a)})}).add([66,18,65],s=>{}).add([69,18,16],s=>{var r;switch(s[0]){case 0:{let o=s[1];e.setLetterDisplay(s.subarray(2),"GS display text",o);break}case 32:{w(e,te,Date.now()+3200),s[1]==0&&w(e,K,Math.max(Math.min(s[2]-1,9),0));break}default:if(s[0]<11){t(e,K)>9&&w(e,K,0),w(e,te,Date.now()+3200),(r=t(e,oe)[s[0]-1])!=null&&r.length||(t(e,oe)[s[0]-1]=new Uint8Array(256));let o=t(e,oe)[s[0]-1],i=s[1];o.fill(0);let a=s.subarray(2);for(let l=0;l>4-k&1,k++})}else console.warn(`Unknown GS display section: ${s[0]}`)}});let c=function(s,r,o){let i=s[0],a=$.cc*r,l=$.rpn*r,h=`GS CH${r+1} `;i<3?s.subarray(1).forEach((f,g)=>{[()=>{t(e,b)[a+p[0]]=f},()=>{t(e,O)[r]=f},()=>{let y=e.chRedir(f,o,!0);t(e,H)[r]=y,r!=y&&(e.buildRchTree(),console.info(`${h}receives from CH${y+1}`))}][i+g]()}):i<19||(i<44?s.subarray(1).forEach((f,g)=>{([()=>{t(e,j)[r]=+!f},!1,()=>{e.setChType(r,f<<1,x.gs),console.debug(`${h}type: ${f?"drum ":"melodic"}${f||""}`)},()=>{t(e,v)[l+3]=f},!1,()=>{t(e,b)[a+p[7]]=f},!1,!1,()=>{t(e,b)[a+p[10]]=f||128},!1,!1,()=>{console.debug(`${h}CC 1: cc${f}`)},()=>{console.debug(`${h}CC 2: cc${f}`)},()=>{t(e,b)[a+p[93]]=f},()=>{t(e,b)[a+p[91]]=f},!1,!1,()=>{t(e,v)[l+1]=f},()=>{t(e,v)[l+2]=f},()=>{t(e,b)[a+p[94]]=f}][i+g-19]||(()=>{}))()}):i<76||console.debug(`Unknown GS part address: ${i}`))},d=function(s,r){let o=s[0],i=`GS CH${r+1} `;o<2?s.subarray(1).forEach((a,l)=>{[()=>{t(e,b)[$.cc*r+p[32]]=a},()=>{}][o+l]()}):o<32?console.warn(`Unknown GS misc address: ${o}`):o<35?s.subarray(1).forEach((a,l)=>{[()=>{console.debug(`${i}EQ: o${["ff","n"][a]}`)},()=>{},()=>{console.debug(`${i}EFX: o${["ff","n"][a]}`)}][o+l-32]()}):console.warn(`Unknown GS misc address: ${o}`)};t(this,ie).add([66,18,64,16],(s,r)=>{c(s,e.chRedir(9,r,!0),r)}).add([66,18,64,17],(s,r)=>{c(s,e.chRedir(0,r,!0),r)}).add([66,18,64,18],(s,r)=>{c(s,e.chRedir(1,r,!0),r)}).add([66,18,64,19],(s,r)=>{c(s,e.chRedir(2,r,!0),r)}).add([66,18,64,20],(s,r)=>{c(s,e.chRedir(3,r,!0),r)}).add([66,18,64,21],(s,r)=>{c(s,e.chRedir(4,r,!0),r)}).add([66,18,64,22],(s,r)=>{c(s,e.chRedir(5,r,!0),r)}).add([66,18,64,23],(s,r)=>{c(s,e.chRedir(6,r,!0),r)}).add([66,18,64,24],(s,r)=>{c(s,e.chRedir(7,r,!0),r)}).add([66,18,64,25],(s,r)=>{c(s,e.chRedir(8,r,!0),r)}).add([66,18,64,26],(s,r)=>{c(s,e.chRedir(10,r,!0),r)}).add([66,18,64,27],(s,r)=>{c(s,e.chRedir(11,r,!0),r)}).add([66,18,64,28],(s,r)=>{c(s,e.chRedir(12,r,!0),r)}).add([66,18,64,29],(s,r)=>{c(s,e.chRedir(13,r,!0),r)}).add([66,18,64,30],(s,r)=>{c(s,e.chRedir(14,r,!0),r)}).add([66,18,64,31],(s,r)=>{c(s,e.chRedir(15,r,!0),r)}).add([66,18,64,64],(s,r)=>{d(s,e.chRedir(9,r,!0))}).add([66,18,64,65],(s,r)=>{d(s,e.chRedir(0,r,!0))}).add([66,18,64,66],(s,r)=>{d(s,e.chRedir(1,r,!0))}).add([66,18,64,67],(s,r)=>{d(s,e.chRedir(2,r,!0))}).add([66,18,64,68],(s,r)=>{d(s,e.chRedir(3,r,!0))}).add([66,18,64,69],(s,r)=>{d(s,e.chRedir(4,r,!0))}).add([66,18,64,70],(s,r)=>{d(s,e.chRedir(5,r,!0))}).add([66,18,64,71],(s,r)=>{d(s,e.chRedir(6,r,!0))}).add([66,18,64,72],(s,r)=>{d(s,e.chRedir(7,r,!0))}).add([66,18,64,73],(s,r)=>{d(s,e.chRedir(8,r,!0))}).add([66,18,64,74],(s,r)=>{d(s,e.chRedir(10,r,!0))}).add([66,18,64,75],(s,r)=>{d(s,e.chRedir(11,r,!0))}).add([66,18,64,76],(s,r)=>{d(s,e.chRedir(12,r,!0))}).add([66,18,64,77],(s,r)=>{d(s,e.chRedir(13,r,!0))}).add([66,18,64,78],(s,r)=>{d(s,e.chRedir(14,r,!0))}).add([66,18,64,79],(s,r)=>{d(s,e.chRedir(15,r,!0))}),t(this,fe).add([54,65],(s,r)=>{e.switchMode("x5d");let o=(s[1]<<7)+s[0],i=(s[3]<<7)+s[2],a=e.chRedir(o&15,r,!0),l=$.cc*a;[()=>{i<1||(i<101?(e.setChType(a,e.CH_MELODIC,x.x5d),t(e,O)[a]=i-1,t(e,b)[l+p[0]]=82):i<229?(e.setChType(a,e.CH_MELODIC,x.x5d),t(e,O)[a]=i-101,t(e,b)[l+p[0]]=56):(e.setChType(a,e.CH_DRUMS,x.x5d),t(e,O)[a]=vt[i-229]||0,t(e,b)[l+p[0]]=62))},()=>{t(e,b)[l+p[7]]=i},()=>{i<31&&(t(e,b)[l+p[10]]=Math.round((i-15)*4.2+64))},()=>{t(e,b)[l+p[93]]=Ie(i)},()=>{t(e,b)[l+p[91]]=Ie(i)},()=>{t(e,v)[a*$.rpn+3]=i>8191?i-16320:64+i},()=>{t(e,v)[a*$.rpn+1]=i>8191?i-16320:64+i},()=>{i>0&&(t(e,v)[a*$.rpn]=i)},()=>{}][o>>4]()}).add([54,76,0],(s,r)=>{e.switchMode("x5d",!0);let o="",i=82,a=0,l=0,h="MSB PRG LSB NME";ee(s,function(f,g){if(g<16400){let y=g%164;switch(!0){case y<10:{f>31&&(o+=String.fromCharCode(f));break}case y==11:{h+=`
+${i} ${a} ${l} ${o.trim().replace("Init Voice","")}`,a++,o="";break}}a>99&&(i=90,a=0)}}),e.userBank.clearRange({msb:82,prg:[0,99],lsb:0}),e.userBank.load(h)}).add([54,77,0],(s,r)=>{e.switchMode("x5d",!0);let o="",i=90,a=0,l=0,h="MSB PRG LSB NME";ee(s,function(f,g){if(g<13600){let y=g%136;switch(!0){case y<10:{f>31&&(o+=String.fromCharCode(f));break}case y==11:{h+=`
+${i} ${a} ${l} ${o.trim().replace("Init Combi","")}`,a++,o="";break}}}}),e.userBank.clearRange({msb:90,prg:[0,99],lsb:0}),e.userBank.load(h)}).add([54,78],(s,r)=>{e.switchMode("x5d",!0),console.debug(`X5D mode switch requested: ${["combi","combi edit","prog","prog edit","multi","global"][s[0]]} mode.`)}).add([54,85],(s,r)=>{e.switchMode("x5d",!0),ee(s,(o,i)=>{i>0&&i<3&&e.setEffectType(i-1,44,o)})}).add([54,104],(s,r)=>{e.switchMode("x5d",!0),ee(s,function(o,i,a,l){if(i<192){let h=e.chRedir(Math.floor(i/12),r,!0),f=h*$.cc;switch(i%12){case 0:{o<128?(e.setChType(h,e.CH_MELODIC,x.x5d),t(e,b)[f+p[0]]=82,t(e,O)[h]=o):(e.setChType(h,e.CH_DRUMS,x.x5d),t(e,b)[f+p[0]]=62,t(e,O)[h]=vt[o-128]),o>0&&(t(e,P)[h]=1);break}case 1:{t(e,b)[f+p[7]]=o;break}case 2:{t(e,v)[h*$.rpn+3]=o>127?o-192:64+o;break}case 3:{t(e,v)[h*$.rpn+1]=o>127?o-192:64+o;break}case 4:{o<31&&(t(e,b)[f+p[10]]=Math.round((o-15)*4.2+64));break}case 5:{let g=o>>4,y=o&15;t(e,b)[f+p[91]]=Ie(y),t(e,b)[f+p[93]]=Ie(g);break}case 10:break;case 11:{let g=e.chRedir(o&15,r,!0),y=o>>4;t(e,H)[h]=o,(g!=h||y)&&(console.info(`X5D Part CH${h+1} receives from CH${g+1}.`),e.buildRchTree())}}}else{let h=e.chRedir(i-192,r,!0)}})}),t(this,ie).add([22,18,127],s=>{e.switchMode("mt32",!0),w(e,D,!1),e.userBank.clearRange({msb:0,lsb:127,prg:[0,127]}),console.info("MIDI reset: MT-32")}).add([22,18,0],(s,r,o)=>{e.switchMode("mt32");let i=e.chRedir(o,r,!0),a=s[1];s.subarray(2).forEach((l,h)=>{let f=h+a;t(e,ge)[f+(i-1)*16]=l,([!1,()=>{let g=t(e,ge)[i-1<<4];if(g<3)if(t(e,re)[i]=1,g==2)for(let y=0;y{t(e,v)[i*$.rpn+3]=l+40},()=>{t(e,v)[i*$.rpn+1]=l+14},()=>{t(e,v)[i*$.rpn]=l},!1,()=>{t(e,b)[$.cc*i+p[91]]=l?127:0},!1,()=>{t(e,b)[$.cc*i+p[7]]=l},()=>{t(e,b)[$.cc*i+p[10]]=Math.ceil(l*9.05)}][f]||(()=>{}))()})}).add([22,18,1],(s,r,o)=>{e.switchMode("mt32");let i=e.chRedir(o,r,!0)}).add([22,18,2],(s,r,o)=>{e.switchMode("mt32");let i=e.chRedir(o,r,!0),a=s[1]+(s[0]<<7);a<10&&(t(e,re)[i]=1),s.subarray(2).forEach((l,h)=>{let f=h+a;f<14&&(t(e,W)[(i-1)*$.cmt+f]=l)})}).add([22,18,3],(s,r,o)=>{if(e.switchMode("mt32"),s[0]){let i=s[1]-16}else{let i=s[1];s.subarray(2).forEach((a,l)=>{let h=l+i;t(e,ge)[h]=a;let f=e.chRedir(1+h>>4,r,!0),g=h&15;([!1,()=>{let y=t(e,ge)[f-1<<4];if(y<3)if(t(e,re)[f]=1,y==2)for(let S=0;S{t(e,v)[f*$.rpn+3]=a+40},()=>{t(e,v)[f*$.rpn+1]=a+14},()=>{t(e,v)[f*$.rpn]=a},!1,()=>{t(e,b)[$.cc*f+p[91]]=a?127:0},!1,()=>{t(e,b)[$.cc*f+p[7]]=a},()=>{t(e,b)[$.cc*f+p[10]]=Math.ceil(a*9.05)}][g]||(()=>{}))()})}}).add([22,18,4],(s,r,o)=>{e.switchMode("mt32");let i=s[1]+(s[0]<<7);s.subarray(2).forEach((a,l)=>{let h=l+i,f=e.chRedir(Math.floor(h/246+1),r,!0),g=h%246;g<14&&(t(e,W)[(f-1)*$.cmt+g]=a),g<10&&(t(e,re)[f]=1)})}).add([22,18,5],(s,r,o)=>{e.switchMode("mt32");let i=(s[0]<<7)+s[1];s.subarray(2).forEach((a,l)=>{let h=i+l,f=Math.floor(h/8),g=h&7,y=f*8;t(e,Ae)[h]=a,([!1,()=>{let S=t(e,Ae)[y];if(S<3){let k="";if(S==2){let m=$.cmt*f;k=`MT-m:${a.toString().padStart(3,"0")}`}else k=e.baseBank.get(0,a+(S<<6),127,"mt32").name;e.userBank.clearRange({msb:0,lsb:127,prg:f}),e.userBank.load(`MSB LSB PRG NME
+000 127 ${f} ${k}`,!0)}}][g]||(()=>{}))()})}).add([22,18,8],(s,r,o)=>{e.switchMode("mt32");let i=((s[0]&1)<<7)+s[1];s.subarray(2).forEach((a,l)=>{let h=i+l;h<$.cmt&&(t(e,$e)[(s[0]>>1)*$.cmt+h]=a)})}).add([22,18,16],(s,r,o)=>{e.switchMode("mt32");let i=s[1],a=!1,l=function(h,f){t(e,H)[f-12]=h,a=!0};s.subarray(2).forEach((h,f)=>{let g=f+i;([!1,!1,!1,!1,!1,!1,!1,!1,!1,!1,!1,!1,!1,l,l,l,l,l,l,l,l,l,()=>{w(e,I,h)}][g]||(()=>{}))(h,f)}),a&&e.buildRchTree()}).add([22,18,32],s=>{e.switchMode("mt32");let r=s[1],o=" ".repeat(r);s.subarray(2).forEach(i=>{i>31&&(o+=String.fromCharCode(i))}),w(e,ae,o.padStart(20," ")),w(e,we,Date.now()+3200)}).add([22,18,82],(s,r)=>{let o=e.chRedir(0,r,!0);for(let i=0;i<16;i++)t(e,N).ano(o+i),i&&i<10&&(t(e,O)[o+i]=Ze[i-1]);console.info("MT-32 alt reset complete.")}),t(this,fe).add([66,0],(s,r)=>{e.switchMode("ns5r",!0),w(e,D,!1),console.debug(`NS5R mode switch requested: ${["global","multi","prog edit","comb edit","drum edit","effect edit"][s[0]]} mode.`)}).add([66,1],(s,r)=>{e.switchMode(["ns5r","05rw"][s[0]],!0),w(e,D,!1)}).add([66,18,0,0],(s,r)=>{let o=s[0];switch(o){case 124:case 126:case 127:{e.switchMode("ns5r",!0),w(e,D,!1);break}case 125:{console.info(`NS5R drum setup reset: ${s}`);break}default:if(o<10){let i=[0,0,0,0],a=(l,h)=>{i[h]=l};if(s.subarray(1).forEach((l,h)=>{[a,a,a,a,()=>{w(e,I,l*129/16383*100)},()=>l-64,()=>l-64,()=>{},()=>{},()=>{}][o+h]()}),s[0]<4){let l=0;i.forEach(h=>{l=l<<4,l+=h}),l-=1024}}}}).add([66,18,0,1],(s,r)=>{}).add([66,18,0,2],(s,r)=>{}).add([66,18,1],(s,r)=>{let o=e.chRedir(s[0],r,!0),i=o*$.cc,a=s[1],l=`NS5R CH${o+1} `;s.subarray(2).forEach((h,f)=>{let g=a+f;g<3?[()=>{t(e,b)[i+p[0]]=h||121},()=>{t(e,b)[i+p[32]]=h},()=>{t(e,O)[o]=h}][g]():g<8||(g<14?[()=>{let y=e.chRedir(h,r,!0);t(e,H)[o]=y,o!=y&&(e.buildRchTree(),console.info(`${l}receives from CH${y+1}`))},()=>{t(e,j)[o]=+!h},()=>{e.setChType(o,h,x.ns5r),console.debug(`${l}type: ${Ge[h]}`)},()=>{t(e,v)[$.rpn*o+3]=h},()=>{},()=>{}][g-8]():g<16||(g<33?[()=>{t(e,b)[i+p[7]]=h},()=>{t(e,b)[i+p[11]]=h},()=>{},()=>{},()=>{t(e,b)[i+p[10]]=h||128},()=>{},()=>{},()=>{t(e,b)[i+p[93]]=h},()=>{t(e,b)[i+p[91]]=h},()=>{t(e,b)[i+p[76]]=h},()=>{t(e,b)[i+p[77]]=h},()=>{t(e,b)[i+p[78]]=h},()=>{t(e,b)[i+p[74]]=h},()=>{t(e,b)[i+p[71]]=h},()=>{t(e,b)[i+p[73]]=h},()=>{t(e,b)[i+p[75]]=h},()=>{t(e,b)[i+p[72]]=h}][g-16]():g<112||g<114&&[()=>{t(e,b)[i+p[5]]=h},()=>{t(e,b)[i+p[65]]=h}][g-112]()))})}).add([66,18,8,0],(s,r)=>{let o=s[0];if(o<32)e.setLetterDisplay(s.subarray(1,33),"NS5R letter display");else{let i=o-32;w(e,te,Date.now()+3200),w(e,K,10),t(e,z,ne).fill(0);let a=s.subarray(1),l=4;a.forEach(function(h,f){let g=f+i,y=g>>4,S=g&15;if(g<80){let k=y>3,m=0,B=y0;)t(e,z,ne)[S*32+y*7+(B-m)]=k&1,k=k>>1,m++}})}}).add([66,52],(s,r)=>{e.switchMode("ns5r",!0),w(e,D,!1);let o="";ee(s,(i,a)=>{a<8?(i>31&&(o+=String.fromCharCode(i)),a==7&&(e.aiEfxName=o)):a<10&&e.setEffectType(a-8,44,i)})}).add([66,53],(s,r)=>{e.switchMode("ns5r",!0),w(e,D,!1),ee(s,function(o,i){switch(!0){case i<2944:{let a=e.chRedir(Math.floor(i/92),r,!0),l=a*$.cc;switch(i%92){case 0:{t(e,b)[l+p[0]]=o||121;break}case 1:{t(e,b)[l+p[32]]=o;break}case 2:{t(e,O)[a]=o,o>0&&(t(e,P)[a]=1);break}case 3:{let h=e.chRedir(o,r,!0);t(e,H)[a]=h,a!=h&&(console.info(`NS5R CH${a+1} receives from CH${h+1}.`),e.buildRchTree())}case 7:break;case 8:{t(e,v)[a*$.rpn+3]=o<40||o>88?o+(o>63?-192:64):o;break}case 9:case 10:{t(e,b)[l+p[7]]=o;break}case 11:{t(e,b)[l+p[11]]=o;break}case 14:{t(e,b)[l+p[10]]=o||128;break}case 19:{t(e,b)[l+p[93]]=o;break}case 20:{t(e,b)[l+p[91]]=o;break}case 84:{t(e,b)[l+p[65]]=o;break}case 85:{t(e,b)[l+p[5]]=o;break}}break}case i<3096:break;case i<3134:break;case i<8566:break}})}).add([66,54],(s,r)=>{e.switchMode("ns5r",!0);let o="",i=80,a=0,l=0,h="MSB PRG LSB NME";ee(s,function(f,g){let y=g%158;switch(!0){case y<10:{f>31&&(o+=String.fromCharCode(f));break}case y==11:{i=f&127;break}case y==12:{l=f&127;break}case y==13:{h+=`
+${i} ${a} ${l} ${o.trim().replace("Init Voice","")}`,a++,o="";break}}}),e.userBank.clearRange({msb:80,lsb:0}),e.userBank.load(h)}).add([66,55],(s,r)=>{e.switchMode("ns5r",!0);let o="",i=88,a=0,l=0,h="MSB PRG LSB NME";ee(s,function(f,g){let y=g%126;switch(!0){case y<10:{f>31&&(o+=String.fromCharCode(f));break}case y==11:break;case y==12:break;case y==13:{h+=`
+${i} ${a} ${l} ${o.trim().replace("Init Combi","")}`,a++,o="";break}}}),e.userBank.clearRange({msb:88,lsb:0}),e.userBank.load(h)}).add([66,125],s=>{e.dispatchEvent("backlight",["green","orange","red",!1,"yellow","blue","purple"][s[0]]||"white")}).add([66,127],s=>{let r=new Uint8Array(5760);ee(s,(o,i,a)=>{if(i<720)for(let l=0;l<8;l++)r[i*8+l]=o>>7-l&1}),e.dispatchEvent("screen",{type:"ns5r",data:r})}).add([76],(s,r,o)=>{t(e,fe).run([66,...s],r,o)}),t(this,Ce).add([16,0,8,0],(s,r,o)=>{let i=(s[2]<<4)+s[3],a="K11 ";([()=>{e.switchMode("k11",!0),w(e,D,!1),w(e,Y,i?4:0),console.info("MIDI reset: GMega/K11")},()=>{console.debug(`${a}reverb type: ${i}`)},()=>{console.debug(`${a}reverb time: ${i}`)},()=>{console.debug(`${a}reverb time: ${i}`)},()=>{console.debug(`${a}reverb predelay: ${i}`)},()=>{console.debug(`${a}reverb predelay: ${i}`)},()=>{console.debug(`${a}depth high: ${i}`)},()=>{console.debug(`${a}depth high: ${i}`)},()=>{console.debug(`${a}depth low: ${i}`)},()=>{console.debug(`${a}depth low: ${i}`)}][s[0]]||(()=>{}))()}).add([16,0,8,1],(s,r,o)=>{let i=e.chRedir(s[1],r,!0),a=$.cc*i,l=$.rpn*i,h=(s[3]<<4)+s[4],f=`K11 CH${i+1} `;([()=>{h<128?(e.setChType(i,e.CH_MELODIC,x.k11),t(e,b)[a+p[0]]=0,t(e,O)[i]=h):(e.setChType(i,e.CH_DRUMS,x.k11),t(e,O)[i]=h-128)},()=>{let g=e.chRedir(h,r,!0);t(e,H)[i]=g,i!=g&&(e.buildRchTree(),console.info(`${f}receives from CH${g+1}`))},()=>{t(e,b)[a+p[7]]=h},()=>{t(e,P)[i]=h},()=>{t(e,b)[a+p[10]]=h},()=>{t(e,v)[l+3]=h+40},()=>{t(e,v)[l+1]=h>>1,t(e,v)[l+2]=h&1},()=>{t(e,b)[a+p[91]]=h?127:0},()=>{},()=>{t(e,b)[a+p[74]]=h},()=>{t(e,b)[a+p[73]]=h},()=>{t(e,b)[a+p[72]]=h}][s[0]]||(()=>{}))()}).add([16,0,9,0],(s,r,o)=>{let i=(s[2]<<4)+s[3],a="GMLX ";([()=>{console.debug(`${a}reverb type: ${i}`)},()=>{console.debug(`${a}reverb time: ${i}`)},()=>{console.debug(`${a}reverb predelay: ${i}`)},()=>{console.debug(`${a}depth high: ${i}`)},()=>{console.debug(`${a}depth low: ${i}`)}][s[0]]||(()=>{}))()}).add([16,0,9,3],(s,r,o)=>{let i=(s[2]<<4)+s[3],a=e.chRedir(s[1],r,!0),l=a*$.cc;[()=>{i<128?(e.setChType(a,e.CH_MELODIC,x.k11),t(e,b)[l+p[0]]=0,t(e,b)[l+p[32]]=0,t(e,O)[a]=i):i<160?(e.setChType(a,e.CH_MELODIC,x.k11),t(e,b)[l+p[0]]=0,t(e,b)[l+p[32]]=7,t(e,O)[a]=i-100):(e.setChType(a,e.CH_DRUMS,x.k11),t(e,b)[l+p[0]]=122,t(e,b)[l+p[32]]=0,t(e,O)[a]=i-160)},()=>{let h=e.chRedir(i,r,!0);t(e,H)[a]=h,a!=h&&(e.buildRchTree(),console.info(`GMLX CH${a+1} receives from CH${h+1}`))}][s[0]]()}).add([16,0,9,4],(s,r,o)=>{let i=(s[2]<<4)+s[3],a=e.chRedir(s[1],r,!0),l=a*$.cc,h=a*$.rpn,f=`GMLX CH${a+1} `;[()=>{t(e,P)[a]=i},()=>{t(e,b)[l+p[7]]=i},()=>{t(e,b)[l+p[10]]=i},()=>{t(e,b)[l+p[91]]=i?127:0},()=>{t(e,v)[h+3]=i+40},()=>{t(e,v)[h+1]=i},()=>{t(e,v)[h]=i},()=>{}][s[0]]()}),t(this,Te).add([66,93,64],(s,r,o)=>{let i=s[2];switch(s[0]){case 0:{switch(s[1]){case 4:{w(e,I,i*129/16383*100);break}case 5:{i-64;break}case 6:{console.debug(`SG global reverb: ${i?"on":"off"}`);break}case 127:{e.switchMode("sg",!0);break}}break}case 1:{switch(s[1]){case 48:{console.debug(`SG reverb type: ${Ye[i]}`);break}}break}default:if(s[0]>>4==1){let a=e.chRedir(s[0]&15,r,!0);if(s[1]==2){let l=e.chRedir(i,r,!0);t(e,H)[a]=l,a!=l&&(e.buildRchTree(),console.info(`SG CH${a+1} receives from CH${l+1}`))}else s[1]==19&&(t(e,b)[$.cc*a+p[7]]=i)}else console.warn(`Unknown AKAI SG SysEx: ${s}`)}}),t(this,Re).add([9],(s,r,o)=>{console.debug(`GZ set effect: ${["stage reverb","hall reverb","room reverb","chorus","tremelo","phaser","rotary speaker","enhancer","flanger","EQ"][s[0]]||"off"}`)}),t(this,Q).add([127,0],(s,r,o)=>{e.switchMode("motif");let i=new Uint8Array([127,1,...s]);t(e,Q).run(i,r,o)}).add([127,1,0,0],(s,r,o)=>{e.switchMode("s90es");let i="S90/Motif ES system ",a=s[0];s.subarray(1).forEach((l,h)=>{([()=>{w(e,I,l*12900/16383)}][a+h]||(()=>{console.info(`Unrecognized ${i}ID: ${a+h}`)}))()})}).add([127,1,0,0,14],(s,r,o)=>{e.switchMode("s90es");let i="S90/Motif ES bulk header ",a=[];a[95]=(l,h,f)=>{console.debug(`${i}multi edit buffer: ${l[1]}`)},(a[s[0]]||(()=>{console.info(`Unrecognized ${i}ID: ${s[0]}.`)}))(s.subarray(1))}).add([127,1,0,0,15],(s,r,o)=>{e.switchMode("s90es");let i="S90/Motif ES bulk footer ",a=[];a[95]=(l,h,f)=>{console.debug(`${i}multi edit buffer: ${l[1]}`)},(a[s[0]]||(()=>{console.info(`Unrecognized ${i}ID: ${s[0]}.`)}))(s.subarray(1))}).add([127,1,0,58,55],(s,r,o)=>{e.switchMode("s90es");let i=e.chRedir(s[0],r,!0),a=$.cc*i,l=s[1],h=`S90/Motif ES bulk CH${i<16?i+1:"U"+(i-95)} `;console.debug(h,s),!(s[0]>15)&&s.subarray(2).forEach((f,g)=>{([()=>{t(e,b)[a+p[0]]=f},()=>{f&&(t(e,P)[i]=1),t(e,b)[a+p[32]]=f,t(e,T)[i]=+([32,40].indexOf(f)>-1)<<1},()=>{f&&(t(e,P)[i]=1),t(e,O)[i]=f},()=>{let y=e.chRedir(f,r,!0);t(e,H)[i]=y,i!=y&&(e.buildRchTree(),console.info(`${h}receives from CH${y+1}`))},()=>{t(e,j)[i]=f?0:1},!1,!1,!1,!1,!1,!1,!1,!1,()=>{t(e,b)[a+p[7]]=f},()=>{t(e,b)[a+p[10]]=f},!1,!1,!1,()=>{t(e,b)[a+p[91]]=f},()=>{t(e,b)[a+p[93]]=f},()=>{t(e,b)[a+p[94]]=f},()=>{t(e,b)[a+p[128]]=f},()=>{},()=>{t(e,b)[a+p[74]]=f},()=>{t(e,b)[a+p[71]]=f},!1,()=>{t(e,b)[a+p[65]]=f},()=>{t(e,b)[a+p[5]]=f},()=>{}][l+g]||(()=>{}))()})}).add([127,1,54,16],(s,r,o)=>{e.switchMode("s90es");let i=s[0];s.subarray(1).forEach((a,l)=>{let f=`S90/Motif ES EQ${(l>>2)+1} `;([()=>{let g=a-64},()=>{let g=De[a]},()=>{let g=a/10},()=>{let g=a}][i+l&3]||(()=>{}))()})})}chRedir(e,n,c){if(t(this,Ee)[n])return(t(this,Ee)[n]-1)*16+e;if([2,3].indexOf(t(this,Y))>-1){if(c==1)return e;let d=0,s=!0;for(;s;)t(this,he)[e+d]==0?(t(this,he)[e+d]=n,console.debug(`Assign track ${n} to channel ${e+d+1}.`),s=!1):t(this,he)[e+d]==n?s=!1:(d+=16,d>=128&&(d=0,s=!1));return e+d}else return e}buildRchTree(){let e=[];t(this,H).forEach((n,c)=>{var d;(d=e[n])!=null&&d.constructor||(e[n]=[]),e[n].push(c)}),w(this,Xe,e)}getActive(){let e=t(this,P).slice();return t(this,R)==x.mt32,e}getCc(e){let n=e*$.cc,c=t(this,b).subarray(n,n+$.cc);return c[p[0]]=c[p[0]]||t(this,ye),c[p[32]]=c[p[32]]||t(this,Y),c}getCcCh(e,n){if(_e.indexOf(n)<0)throw new Error("CC number not accepted");return t(this,b)[$.cc*e+p[n]]}getCcAll(){let e=t(this,b).slice();for(let n=0;n<$.ch;n++){let c=n*$.cc;e[c+p[0]]=e[c+p[0]]||t(this,ye),e[c+p[32]]=e[c+p[32]]||t(this,Y)}return e}getChType(){return t(this,T)}setChType(e,n,c=t(this,R)){n&=15,t(this,T)[e]=n,n>0&&(t(this,b)[e*$.cc+p[0]]=Se[c])}getPitch(){return t(this,pe)}getProgram(){return t(this,O)}getTexts(){return t(this,M).slice()}getVel(e){let n=new Map,c=this;return t(c,U).forEach(function(d,s){let r=Math.floor(d/128),o=d%128;e==r&&t(c,A)[d]>0&&n.set(o,{v:t(c,A)[d],s:t(c,L)[s]})}),n}getBitmap(){return{bitmap:t(this,z,ne),expire:t(this,te)}}getLetter(){return{text:t(this,ae),expire:t(this,we)}}getMode(){return be[t(this,R)]}getMaster(){return{volume:t(this,I)}}getRawStrength(){let e=this;return t(this,U).forEach(function(n){let c=Math.floor(n/128);t(e,A)[n]>t(e,se)[c]&&(t(e,se)[c]=t(e,A)[n])}),t(this,se)}getStrength(){let e=[],n=this;return this.getRawStrength().forEach(function(c,d){e[d]=Math.floor(c*t(n,b)[d*$.cc+p[7]]*t(n,b)[d*$.cc+p[11]]*t(n,I)/803288)}),e}getRpn(){return t(this,v)}getNrpn(){return t(this,Pe)}getVoice(e,n,c,d){let s=e||t(this,ye),r=n,o=c||t(this,Y);be[t(this,R)]=="ns5r"&&s>0&&s<56&&(o=3);let i=this.userBank.get(s,r,o,d);if(be[t(this,R)]=="mt32"&&i.name.indexOf("MT-m:")==0){let a=parseInt(i.name.slice(5)),l=a*$.cmt,h="";t(this,$e).subarray(l,l+10).forEach(f=>{f>31&&(h+=String.fromCharCode(f))}),this.userBank.load(`MSB LSB PRG
+0 127 ${r} ${h}`,!0),i.name=h,i.ending=" "}return(i.ending!=" "||!i.name.length)&&(i=this.baseBank.get(s,r,o,d)),i}getChVoice(e){let n=this.getVoice(t(this,b)[e*$.cc+p[0]],t(this,O)[e],t(this,b)[e*$.cc+p[32]],be[t(this,R)]);if(t(this,re)[e])switch(t(this,R)){case x.mt32:n.ending="~",n.name="",t(this,W).subarray(14*(e-1),14*(e-1)+10).forEach(c=>{c>31&&(n.name+=String.fromCharCode(c))})}return n}getPitchShift(e){let n=e*$.rpn;return t(this,pe)[e]/8192*t(this,v)[n]+(t(this,v)[n+3]-64)+((t(this,v)[n+1]<<7)+t(this,v)[n+2]-8192)/8192}getEffectType(e=0){let n=3*e+1;return t(this,V).subarray(n,n+2)}setEffectTypeRaw(e=0,n,c){let d=3*e;t(this,V)[d]=1,t(this,V)[d+1+ +n]=c}setEffectType(e=0,n,c){this.setEffectTypeRaw(e,!1,n),this.setEffectTypeRaw(e,!0,c)}setLetterDisplay(e,n,c=0,d=3200){let s=this,r;w(s,ae," ".repeat(c)),e.forEach(o=>{w(s,ae,t(s,ae)+String.fromCharCode(o>31?o:32)),o<32&&(r=r||new Set,r.add(o))}),w(s,we,Date.now()+3200),w(s,ae,t(s,ae).padEnd(32," ")),r&&(r=Array.from(r),r.forEach((o,i,a)=>{a[i]=o.toString(16).padStart(2,"0")}),console.warn(`${n}${n?" ":""}invalid code point${r.length>1?"s":""}: 0x${r.join(", 0x")}`))}allocateAce(e){if(!e||e>95){console.warn(`cc${e} cannot be allocated as an active custom effect.`);return}let n=!0,c=0;for(;n&&c<$.ace;)t(this,le)[c]==e?n=!1:t(this,le)[c]||(n=!1,t(this,le)[c]=e,console.info(`Allocated cc${e} to ACE slot ${c}.`)),c++;c>=$.ace&&console.warn("ACE slots are full.")}getAce(){return t(this,le)}getChAce(e,n){if(n<0||n>=$.ace)throw new RangeError("No such ACE slot");let c=t(this,le)[n];if(c){if(_e.indexOf(c)>=0)return t(this,b)[e*$.cc+p[c]];throw new Error(`Invalid ACE source: ${c}`)}else return 0}init(e=0){this.dispatchEvent("mode","?"),w(this,R,0),w(this,ye,0),w(this,Y,0),w(this,ce,0),t(this,P).fill(0),t(this,b).fill(0),t(this,le).fill(0),t(this,O).fill(0),t(this,A).fill(0),t(this,U).fill(0),t(this,se).fill(0),t(this,pe).fill(0),t(this,Pe).fill(0),t(this,Fe).fill(0),w(this,I,100),w(this,M,[]),w(this,Ue,500),w(this,Ne,0),w(this,we,0),w(this,ae,""),w(this,te,0),w(this,K,0),t(this,z,ne).fill(0),w(this,D,!1),w(this,He,0),w(this,J,!0),t(this,H).forEach(function(n,c,d){d[c]=c}),this.buildRchTree(),e==0&&(t(this,he).fill(0),t(this,Ee).fill(0)),t(this,b)[$.cc*9]=Se[0],t(this,b)[$.cc*25]=Se[0],t(this,b)[$.cc*41]=Se[0],t(this,b)[$.cc*57]=Se[0],t(this,T).fill(this.CH_MELODIC),t(this,T)[9]=this.CH_DRUM1,t(this,T)[25]=this.CH_DRUM3,t(this,T)[41]=this.CH_DRUMS,t(this,T)[57]=this.CH_DRUMS,t(this,T)[73]=this.CH_DRUM5,t(this,T)[89]=this.CH_DRUM7,t(this,T)[105]=this.CH_DRUMS,t(this,T)[121]=this.CH_DRUMS,t(this,Ae).fill(0),t(this,$e).fill(0),t(this,ge).fill(0),t(this,W).fill(0),t(this,re).fill(0),t(this,V).fill(0),this.aiEfxName="",this.userBank.clearRange({msb:0,lsb:127,prg:[0,127]});for(let n=0;n<$.ch;n++){let c=n*$.cc;t(this,b)[c+p[7]]=100,t(this,b)[c+p[11]]=127,t(this,b)[c+p[10]]=64,t(this,b)[c+p[71]]=64,t(this,b)[c+p[72]]=64,t(this,b)[c+p[73]]=64,t(this,b)[c+p[74]]=64,t(this,b)[c+p[75]]=64,t(this,b)[c+p[76]]=64,t(this,b)[c+p[77]]=64,t(this,b)[c+p[78]]=64,t(this,b)[c+p[91]]=40,t(this,b)[c+p[101]]=127,t(this,b)[c+p[100]]=127,t(this,b)[c+p[99]]=127,t(this,b)[c+p[98]]=127;let d=n*$.rpn;t(this,v)[d]=2,t(this,v)[d+1]=64,t(this,v)[d+2]=0,t(this,v)[d+3]=64,t(this,v)[d+4]=0,t(this,v)[d+5]=0}}switchMode(e,n=!1){let c=be.indexOf(e);if(c>-1){if(t(this,R)==0||n){let d=t(this,R);w(this,R,c),w(this,K,0),w(this,ye,Et[0][c]),w(this,Y,Et[1][c]);for(let r=0;r<$.ch;r++)t(this,T)[r]>0&&t(this,b)[r*$.cc+p[0]]==Se[d]&&(t(this,b)[r*$.cc]=Se[c]);switch(this.initOnReset,c){case x.mt32:{Ze.forEach((r,o)=>{let i=o+1;t(this,P)[i]||(t(this,O)[i]=r,t(this,b)[i*$.cc+p[91]]=127)});break}}let s;switch(c){case x.gs:{s=[40,4,40,18,40,32,32,0,0,0,0,0,0,0];break}case x.x5d:case x.ns5r:{s=[44,1,44,19,44,0,44,0,0,0,0,0,0,0];break}default:s=[1,0,65,0,5,0,0,0,0,0,0,0,0,0]}for(let r=0;r<$.efx;r++)t(this,V)[3*r]||(t(this,V)[3*r+1]=s[2*r],t(this,V)[3*r+2]=s[2*r+1]);this.dispatchEvent("mode",e)}}else throw new Error(`Unknown mode ${e}`)}newStrength(){t(this,se).fill(0)}runJson(e){var n;if(e.type>14)return e.type==15&&e.data.constructor!=Uint8Array&&(e.data=Uint8Array.from(e.data)),t(this,Ke)[e.type].call(this,e);{let c=this.chRedir(e.part,e.track),d=!1;(n=t(this,Xe)[c])==null||n.forEach(s=>{e.channel=s,d=!0,t(this,Ke)[e.type].call(this,e)}),d||console.warn(`${kt[e.type]?kt[e.type]:e.type}${[11,12].includes(e.type)?(e.data[0]!=null?e.data[0]:e.data).toString():""} event sent to CH${c+1} without any recipient.`)}t(this,M).length>100&&t(this,M).splice(100,t(this,M).length-99)}runRaw(e){}async loadBank(e,n){switch(e=e.toLowerCase(),e){case"s7e":{this.userBank.clearRange({msb:63,lsb:[21,22]}),this.userBank.clearRange({msb:63,lsb:[24,27]});break}default:throw new Error(`Unknown bank format ${e}`)}switch(e){case"s7e":{Ve.context=this,this.userBank.load(await Ve.read(e,n));break}}}},R=new WeakMap,K=new WeakMap,te=new WeakMap,oe=new WeakMap,z=new WeakSet,ne=function(){return t(this,oe)[t(this,K)]},Tt=function(e){t(this,oe)[t(this,K)]=e},P=new WeakMap,H=new WeakMap,T=new WeakMap,b=new WeakMap,le=new WeakMap,O=new WeakMap,A=new WeakMap,j=new WeakMap,U=new WeakMap,L=new WeakMap,pe=new WeakMap,se=new WeakMap,me=new WeakMap,v=new WeakMap,Pe=new WeakMap,Fe=new WeakMap,re=new WeakMap,ge=new WeakMap,W=new WeakMap,Ae=new WeakMap,$e=new WeakMap,V=new WeakMap,ye=new WeakMap,Y=new WeakMap,I=new WeakMap,ce=new WeakMap,Ue=new WeakMap,Ne=new WeakMap,ae=new WeakMap,we=new WeakMap,He=new WeakMap,J=new WeakMap,D=new WeakMap,Xe=new WeakMap,tt=new WeakMap,M=new WeakMap,he=new WeakMap,Ee=new WeakMap,G=new WeakMap,ve=new WeakMap,N=new WeakMap,Ke=new WeakMap,ze=new WeakMap,xe=new WeakMap,Me=new WeakMap,Q=new WeakMap,ie=new WeakMap,fe=new WeakMap,Ce=new WeakMap,Te=new WeakMap,Re=new WeakMap,Mt);export{ms as OctaviaDevice,$ as allocated,p as ccToPos,Ct as dnToPos};
diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 00000000..f747cf3d
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,26 @@
+# Docs
+## Octavia documentation
+Here lies documentation of the Octavia project.
+
+### Support table
+* [Implementation sheet](support/implementation.md)
+* [SysEx instructions sheet](support/sysex.md)
+* [Targets](support/target.md)
+
+### Implementation
+* [Basic messages](impl/basic.md)
+* [Control changes](impl/cc.md)
+* [RPN/NRPN values](impl/pn.md)
+* [Audio Effects](impl/efx.md)
+
+### SysEx documentation
+* [Mutual instructions](sysex/mutual.md)
+* [Roland MT-32](sysex/mt32.md)
+* [KORG 05/X5/N5](sysex/korgOld.md)
+
+### API documentation
+* [`state.mjs`: the core processing unit](state/README.md)
+* [`basic.mjs`: the basis for visualizers](basic/README.md)
+* [`bridge.mjs`: the basis for middleware](bridge/README.md)
+* [`disp.mjs`: ready-made example visualizers](disp/README.md)
+* [`middle.mjs`: ready-made middleware with real-time translation capabilities](middle/README.md)
\ No newline at end of file
diff --git a/docs/conf.json b/docs/conf.json
new file mode 100644
index 00000000..32fe4b7d
--- /dev/null
+++ b/docs/conf.json
@@ -0,0 +1,6 @@
+{
+ "site": {
+ "name": "Octavia Docs",
+ "favicon": "favicon.svg"
+ }
+}
diff --git a/docs/impl/efx.md b/docs/impl/efx.md
new file mode 100644
index 00000000..f5a85d7c
--- /dev/null
+++ b/docs/impl/efx.md
@@ -0,0 +1,57 @@
+# Audio Effects
+## Audio effects
+Octavia supports tracking a range of audio effects applied on supported targets. For maximum compatibility, Octavia has seven available slots reserved for effect sends, which correspond to reverb, chorus, variation and four insertions in order.
+
+Each slot isn't dedicated to what that slot is primarily used for, but rather allocated and controlled by the CC registers they are assigned to by default (cc91, cc93, cc94, cc16-19). For example, the variation slot (cc94) is taken away by delay effects when in GS mode, while the reverb and chorus slot could be taken away by any effect desired in X5DR or NS5R mode.
+
+Due to varied setups, each effect also isn't just bound to the CC registers they are assigned to. They can also listen on other CC registers, or even multiple if they wish.
+
+## Comparison table
+### Singular effect
+#### Reverb
+| Yamaha XG | GS Reverb | GS Insertion | KORG AI² |
+| --------- | --------- | ------------ | -------- |
+| Hall (1, 2, M, L) | Hall (1, 2) | Hall (1, 2) | Hall (normal, ensemble, concert) |
+| Room (1-3, S, M, L) | Room (1-3) | Room (1, 2) | Room (normal, large) |
+| Stage (1, 2) | | Stage (1, 2) | Stage |
+| Plate (XG, GM) | Plate | | Plate (wet, dry) |
+| Delay (LCR, LR) | Delay | Delay (stereo) | Delay (stereo) |
+| Echo | | | |
+| Cross Delay | Panning Delay | Delay (3-tap, 4-tap, mod, 3D, trem.c.) | Delay (cross, dual, tap 1-3) |
+| Early Reflection (1, 2) | | | Early Reflection (1-3) |
+| Gate (forward, reverse) | | Gate (forward, reverse, sweep 1-2) | |
+| White Room | | | |
+| Tunnel | | | |
+| Canyon | | | |
+| Basement | | | |
+| Karaoke (1, 2, 3) | | | |
+| | | | Spring |
+#### Chorus
+| Yamaha XG | GS Chorus | GS Insertion | KORG AI² |
+| --------- | --------- | ------------ | -------- |
+#### Delay
+| Yamaha XG | GS Delay | GS Insertion | KORG AI² |
+| --------- | --------- | ------------ | -------- |
+#### Miscellaneous
+| Yamaha XG | GS Insertion | KORG AI² |
+| --------- | ------------ | -------- |
+### Dual effect
+#### Mutual
+* X: Yamaha XG
+* G: Roland GS
+* A: KORG AI²
+
+| | Rev | Cho | Ovr | Dst | Enh | Fln | Dly | Rot | Phs | Amp | Cmp | AWa |
+| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
+| Rev | | | | | | | A | | | | | |
+| Cho | | | G | G | G | G | GA | | | | | |
+| Ovr | | G | G | | | G | XGA | XG | G | | | XG |
+| Dst | | G | | | | G | XGA | X | | | X | X |
+| Enh | | G | | | | G | G | | | | | |
+| Fln | | G | G | G | G | | GA | | | | | |
+| Dly | A | GA | XGA | XGA | G | GA | A | A | A | | | |
+| Rot | | | XG | X | | | A | X | | X | | |
+| Phs | | | G | | | | A | | | | | |
+| Amp | | | | | | | | X | | | | |
+| Cmp | | | | X | | | | | | | | |
+| AWa | | | XG | X | | | | | | | | |
diff --git a/docs/impl/pn.md b/docs/impl/pn.md
new file mode 100644
index 00000000..059fda0d
--- /dev/null
+++ b/docs/impl/pn.md
@@ -0,0 +1,2 @@
+# RPN/NRPN values
+## RPN/NRPN values
diff --git a/docs/index.htm b/docs/index.htm
new file mode 100644
index 00000000..aed5ef76
--- /dev/null
+++ b/docs/index.htm
@@ -0,0 +1 @@
+Parchment is loading...
diff --git a/docs/index.js b/docs/index.js
new file mode 100644
index 00000000..7aaa9880
--- /dev/null
+++ b/docs/index.js
@@ -0,0 +1 @@
+"use strict";(()=>{var x=function(e,t="&",r="="){let n=new Map;return e.length&&e.slice(1).split(t).forEach(c=>{let h=decodeURIComponent(c),y=h.indexOf(r);y>=0?n.set(h.slice(0,y),h.slice(y+r.length)):n.set(h,null)}),n};var s=function(e,t=document){return t?.querySelector(e)},a=function(e,t=document){return Array.from(t?.querySelectorAll(e))};var g,A=new Worker("./worker.js"),k=[],L=x(location.search),o,v=!1,p,d,D=function(e){for(let t in d)t==e?d[t].removeAttribute("hidden-slowly"):d[t].setAttribute("hidden-slowly","true");d[e]?p.removeAttribute("hidden-slowly"):p.setAttribute("hidden-slowly","true")},f=document,u=f.children[0],O=async function(e){e.preventDefault(),e.stopPropagation();let t=this.getAttribute("parchment");S(),await $(t),k.push(t)},P=function(){location.hash=`#${this.id||""}`},l=function(e){return e?.length||(e?.length==0?e="README":e=L.get("p")||"README"),e.toLowerCase().indexOf(".md")<0?e+".md":e},S=function(){let e=history.state||{};e[l()]={sX:u.scrollLeft,sY:u.scrollTop},history.replaceState(e,"")},T=function(e){a("table",e).forEach(t=>{t.setAttribute("role","grid")}),a("img",e).forEach(t=>{t.setAttribute("decoding","async"),t.setAttribute("loading","lazy")}),a("h1, h2, h3, h4, h5, h6",e).forEach(t=>{t.addEventListener("click",P)}),a("a",e).forEach(t=>{let r=t.getAttribute("href"),n=r.indexOf(":"),c=r.indexOf("/");n>-1&&n<6&&c<8?(t.setAttribute("target","_blank"),t.setAttribute("data-tooltip","This link will be opened in a new tab.")):r[0]=="#"||(t.setAttribute("parchment",r),t.href=`?p=${r}`),t.addEventListener("click",O)})},C=new DOMParser,b=new Map,i,w,j=function(e){return b.has(e)?!0:(A.postMessage({id:e}),!1)};var E=async function(e){for(;o.children.length>0;)i?(i.body.appendChild(o.children[0]),console.debug("Moving the current render result...")):(o.removeChild(o.children[0]),console.debug("Removing the current render result..."));i=e,m();let t=i.body.children.length,r=0;for(let n=0;n{let t=e.data;if(t.ok){let r=C.parseFromString(t.data,"text/html");T(r),b.set(t.id,r),w==t.id&&E(r)}else w==t.id});self.parsedDoms=b;var m=async function(e){i?(self.currentDom=i,f.title=`${s("h1",i)?.innerText||"Untitled"} - ${g?.site?.name||"Parchment"}`):f.title=`${e||"Loading"} - ${g?.site?.name||"Parchment"}`};f.addEventListener("readystatechange",function(){switch(this.readyState){case"interactive":{o=s("main.container"),p=s(".overlay"),d={loading:s("#loading-overlay")},m(),$(l()),k.push(l());break}case"loaded":{m();break}}});fetch("./conf.json").then(e=>e.json()).then(e=>{g=e,m()});addEventListener("beforeunload",()=>{v&&S()});})();
diff --git a/docs/parchment.css b/docs/parchment.css
new file mode 100644
index 00000000..5c6fc8ee
--- /dev/null
+++ b/docs/parchment.css
@@ -0,0 +1 @@
+:root{--primary: #039be5}[hidden-slowly]{opacity:0!important;pointer-events:none}blockquote>p{margin-bottom:0}blockquote>blockquote{margin:calc(var(--typography-spacing-vertical) / 2) 0}th{font-weight:700}main,footer{padding:calc(var(--spacing) * 2) 0!important}footer{opacity:.5}.overlay{background-color:var(--background-color);position:fixed;top:0;left:0;height:100%;display:flex;justify-content:center}.overlay-item{position:absolute;top:0}.overlay,.overlay-item{opacity:1;transition:.5s opacity}#loading-overlay{max-width:max-content}
diff --git a/docs/pico.css b/docs/pico.css
new file mode 100644
index 00000000..4125c0de
--- /dev/null
+++ b/docs/pico.css
@@ -0,0 +1,4 @@
+@charset "UTF-8";/*!
+ * Pico.css v1.5.7 (https://picocss.com)
+ * Copyright 2019-2023 - Licensed under MIT
+ */:root{--font-family:system-ui,-apple-system,"Segoe UI","Roboto","Ubuntu","Cantarell","Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--line-height:1.5;--font-weight:400;--font-size:16px;--border-radius:0.25rem;--border-width:1px;--outline-width:3px;--spacing:1rem;--typography-spacing-vertical:1.5rem;--block-spacing-vertical:calc(var(--spacing) * 2);--block-spacing-horizontal:var(--spacing);--grid-spacing-vertical:0;--grid-spacing-horizontal:var(--spacing);--form-element-spacing-vertical:0.75rem;--form-element-spacing-horizontal:1rem;--nav-element-spacing-vertical:1rem;--nav-element-spacing-horizontal:0.5rem;--nav-link-spacing-vertical:0.5rem;--nav-link-spacing-horizontal:0.5rem;--form-label-font-weight:var(--font-weight);--transition:0.2s ease-in-out;--modal-overlay-backdrop-filter:blur(0.25rem)}@media (min-width:576px){:root{--font-size:17px}}@media (min-width:768px){:root{--font-size:18px}}@media (min-width:992px){:root{--font-size:19px}}@media (min-width:1200px){:root{--font-size:20px}}@media (min-width:576px){body>footer,body>header,body>main,section{--block-spacing-vertical:calc(var(--spacing) * 2.5)}}@media (min-width:768px){body>footer,body>header,body>main,section{--block-spacing-vertical:calc(var(--spacing) * 3)}}@media (min-width:992px){body>footer,body>header,body>main,section{--block-spacing-vertical:calc(var(--spacing) * 3.5)}}@media (min-width:1200px){body>footer,body>header,body>main,section{--block-spacing-vertical:calc(var(--spacing) * 4)}}@media (min-width:576px){article{--block-spacing-horizontal:calc(var(--spacing) * 1.25)}}@media (min-width:768px){article{--block-spacing-horizontal:calc(var(--spacing) * 1.5)}}@media (min-width:992px){article{--block-spacing-horizontal:calc(var(--spacing) * 1.75)}}@media (min-width:1200px){article{--block-spacing-horizontal:calc(var(--spacing) * 2)}}dialog>article{--block-spacing-vertical:calc(var(--spacing) * 2);--block-spacing-horizontal:var(--spacing)}@media (min-width:576px){dialog>article{--block-spacing-vertical:calc(var(--spacing) * 2.5);--block-spacing-horizontal:calc(var(--spacing) * 1.25)}}@media (min-width:768px){dialog>article{--block-spacing-vertical:calc(var(--spacing) * 3);--block-spacing-horizontal:calc(var(--spacing) * 1.5)}}a{--text-decoration:none}a.contrast,a.secondary{--text-decoration:underline}small{--font-size:0.875em}h1,h2,h3,h4,h5,h6{--font-weight:700}h1{--font-size:2rem;--typography-spacing-vertical:3rem}h2{--font-size:1.75rem;--typography-spacing-vertical:2.625rem}h3{--font-size:1.5rem;--typography-spacing-vertical:2.25rem}h4{--font-size:1.25rem;--typography-spacing-vertical:1.874rem}h5{--font-size:1.125rem;--typography-spacing-vertical:1.6875rem}[type=checkbox],[type=radio]{--border-width:2px}[type=checkbox][role=switch]{--border-width:3px}tfoot td,tfoot th,thead td,thead th{--border-width:3px}:not(thead,tfoot)>*>td{--font-size:0.875em}code,kbd,pre,samp{--font-family:"Menlo","Consolas","Roboto Mono","Ubuntu Monospace","Noto Mono","Oxygen Mono","Liberation Mono",monospace,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"}kbd{--font-weight:bolder}:root:not([data-theme=dark]),[data-theme=light]{--background-color:#fff;--color:hsl(205deg, 20%, 32%);--h1-color:hsl(205deg, 30%, 15%);--h2-color:#24333e;--h3-color:hsl(205deg, 25%, 23%);--h4-color:#374956;--h5-color:hsl(205deg, 20%, 32%);--h6-color:#4d606d;--muted-color:hsl(205deg, 10%, 50%);--muted-border-color:hsl(205deg, 20%, 94%);--primary:hsl(195deg, 85%, 41%);--primary-hover:hsl(195deg, 90%, 32%);--primary-focus:rgba(16, 149, 193, 0.125);--primary-inverse:#fff;--secondary:hsl(205deg, 15%, 41%);--secondary-hover:hsl(205deg, 20%, 32%);--secondary-focus:rgba(89, 107, 120, 0.125);--secondary-inverse:#fff;--contrast:hsl(205deg, 30%, 15%);--contrast-hover:#000;--contrast-focus:rgba(89, 107, 120, 0.125);--contrast-inverse:#fff;--mark-background-color:#fff2ca;--mark-color:#543a26;--ins-color:#388e3c;--del-color:#c62828;--blockquote-border-color:var(--muted-border-color);--blockquote-footer-color:var(--muted-color);--button-box-shadow:0 0 0 rgba(0, 0, 0, 0);--button-hover-box-shadow:0 0 0 rgba(0, 0, 0, 0);--form-element-background-color:transparent;--form-element-border-color:hsl(205deg, 14%, 68%);--form-element-color:var(--color);--form-element-placeholder-color:var(--muted-color);--form-element-active-background-color:transparent;--form-element-active-border-color:var(--primary);--form-element-focus-color:var(--primary-focus);--form-element-disabled-background-color:hsl(205deg, 18%, 86%);--form-element-disabled-border-color:hsl(205deg, 14%, 68%);--form-element-disabled-opacity:0.5;--form-element-invalid-border-color:#c62828;--form-element-invalid-active-border-color:#d32f2f;--form-element-invalid-focus-color:rgba(211, 47, 47, 0.125);--form-element-valid-border-color:#388e3c;--form-element-valid-active-border-color:#43a047;--form-element-valid-focus-color:rgba(67, 160, 71, 0.125);--switch-background-color:hsl(205deg, 16%, 77%);--switch-color:var(--primary-inverse);--switch-checked-background-color:var(--primary);--range-border-color:hsl(205deg, 18%, 86%);--range-active-border-color:hsl(205deg, 16%, 77%);--range-thumb-border-color:var(--background-color);--range-thumb-color:var(--secondary);--range-thumb-hover-color:var(--secondary-hover);--range-thumb-active-color:var(--primary);--table-border-color:var(--muted-border-color);--table-row-stripped-background-color:#f6f8f9;--code-background-color:hsl(205deg, 20%, 94%);--code-color:var(--muted-color);--code-kbd-background-color:var(--contrast);--code-kbd-color:var(--contrast-inverse);--code-tag-color:hsl(330deg, 40%, 50%);--code-property-color:hsl(185deg, 40%, 40%);--code-value-color:hsl(40deg, 20%, 50%);--code-comment-color:hsl(205deg, 14%, 68%);--accordion-border-color:var(--muted-border-color);--accordion-close-summary-color:var(--color);--accordion-open-summary-color:var(--muted-color);--card-background-color:var(--background-color);--card-border-color:var(--muted-border-color);--card-box-shadow:0.0145rem 0.029rem 0.174rem rgba(27, 40, 50, 0.01698),0.0335rem 0.067rem 0.402rem rgba(27, 40, 50, 0.024),0.0625rem 0.125rem 0.75rem rgba(27, 40, 50, 0.03),0.1125rem 0.225rem 1.35rem rgba(27, 40, 50, 0.036),0.2085rem 0.417rem 2.502rem rgba(27, 40, 50, 0.04302),0.5rem 1rem 6rem rgba(27, 40, 50, 0.06),0 0 0 0.0625rem rgba(27, 40, 50, 0.015);--card-sectionning-background-color:#fbfbfc;--dropdown-background-color:#fbfbfc;--dropdown-border-color:#e1e6eb;--dropdown-box-shadow:var(--card-box-shadow);--dropdown-color:var(--color);--dropdown-hover-background-color:hsl(205deg, 20%, 94%);--modal-overlay-background-color:rgba(213, 220, 226, 0.7);--progress-background-color:hsl(205deg, 18%, 86%);--progress-color:var(--primary);--loading-spinner-opacity:0.5;--tooltip-background-color:var(--contrast);--tooltip-color:var(--contrast-inverse);--icon-checkbox:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");--icon-chevron:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(65, 84, 98)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--icon-chevron-button:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--icon-chevron-button-inverse:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--icon-close:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(115, 130, 140)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'%3E%3C/line%3E%3Cline x1='6' y1='6' x2='18' y2='18'%3E%3C/line%3E%3C/svg%3E");--icon-date:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(65, 84, 98)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='16' y1='2' x2='16' y2='6'%3E%3C/line%3E%3Cline x1='8' y1='2' x2='8' y2='6'%3E%3C/line%3E%3Cline x1='3' y1='10' x2='21' y2='10'%3E%3C/line%3E%3C/svg%3E");--icon-invalid:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(198, 40, 40)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E");--icon-minus:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='5' y1='12' x2='19' y2='12'%3E%3C/line%3E%3C/svg%3E");--icon-search:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(65, 84, 98)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'%3E%3C/line%3E%3C/svg%3E");--icon-time:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(65, 84, 98)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cpolyline points='12 6 12 12 16 14'%3E%3C/polyline%3E%3C/svg%3E");--icon-valid:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(56, 142, 60)' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");color-scheme:light}@media only screen and (prefers-color-scheme:dark){:root:not([data-theme]){--background-color:#11191f;--color:hsl(205deg, 16%, 77%);--h1-color:hsl(205deg, 20%, 94%);--h2-color:#e1e6eb;--h3-color:hsl(205deg, 18%, 86%);--h4-color:#c8d1d8;--h5-color:hsl(205deg, 16%, 77%);--h6-color:#afbbc4;--muted-color:hsl(205deg, 10%, 50%);--muted-border-color:#1f2d38;--primary:hsl(195deg, 85%, 41%);--primary-hover:hsl(195deg, 80%, 50%);--primary-focus:rgba(16, 149, 193, 0.25);--primary-inverse:#fff;--secondary:hsl(205deg, 15%, 41%);--secondary-hover:hsl(205deg, 10%, 50%);--secondary-focus:rgba(115, 130, 140, 0.25);--secondary-inverse:#fff;--contrast:hsl(205deg, 20%, 94%);--contrast-hover:#fff;--contrast-focus:rgba(115, 130, 140, 0.25);--contrast-inverse:#000;--mark-background-color:#d1c284;--mark-color:#11191f;--ins-color:#388e3c;--del-color:#c62828;--blockquote-border-color:var(--muted-border-color);--blockquote-footer-color:var(--muted-color);--button-box-shadow:0 0 0 rgba(0, 0, 0, 0);--button-hover-box-shadow:0 0 0 rgba(0, 0, 0, 0);--form-element-background-color:#11191f;--form-element-border-color:#374956;--form-element-color:var(--color);--form-element-placeholder-color:var(--muted-color);--form-element-active-background-color:var(--form-element-background-color);--form-element-active-border-color:var(--primary);--form-element-focus-color:var(--primary-focus);--form-element-disabled-background-color:hsl(205deg, 25%, 23%);--form-element-disabled-border-color:hsl(205deg, 20%, 32%);--form-element-disabled-opacity:0.5;--form-element-invalid-border-color:#b71c1c;--form-element-invalid-active-border-color:#c62828;--form-element-invalid-focus-color:rgba(198, 40, 40, 0.25);--form-element-valid-border-color:#2e7d32;--form-element-valid-active-border-color:#388e3c;--form-element-valid-focus-color:rgba(56, 142, 60, 0.25);--switch-background-color:#374956;--switch-color:var(--primary-inverse);--switch-checked-background-color:var(--primary);--range-border-color:#24333e;--range-active-border-color:hsl(205deg, 25%, 23%);--range-thumb-border-color:var(--background-color);--range-thumb-color:var(--secondary);--range-thumb-hover-color:var(--secondary-hover);--range-thumb-active-color:var(--primary);--table-border-color:var(--muted-border-color);--table-row-stripped-background-color:rgba(115, 130, 140, 0.05);--code-background-color:#18232c;--code-color:var(--muted-color);--code-kbd-background-color:var(--contrast);--code-kbd-color:var(--contrast-inverse);--code-tag-color:hsl(330deg, 30%, 50%);--code-property-color:hsl(185deg, 30%, 50%);--code-value-color:hsl(40deg, 10%, 50%);--code-comment-color:#4d606d;--accordion-border-color:var(--muted-border-color);--accordion-active-summary-color:var(--primary);--accordion-close-summary-color:var(--color);--accordion-open-summary-color:var(--muted-color);--card-background-color:#141e26;--card-border-color:var(--card-background-color);--card-box-shadow:0.0145rem 0.029rem 0.174rem rgba(0, 0, 0, 0.01698),0.0335rem 0.067rem 0.402rem rgba(0, 0, 0, 0.024),0.0625rem 0.125rem 0.75rem rgba(0, 0, 0, 0.03),0.1125rem 0.225rem 1.35rem rgba(0, 0, 0, 0.036),0.2085rem 0.417rem 2.502rem rgba(0, 0, 0, 0.04302),0.5rem 1rem 6rem rgba(0, 0, 0, 0.06),0 0 0 0.0625rem rgba(0, 0, 0, 0.015);--card-sectionning-background-color:#18232c;--dropdown-background-color:hsl(205deg, 30%, 15%);--dropdown-border-color:#24333e;--dropdown-box-shadow:var(--card-box-shadow);--dropdown-color:var(--color);--dropdown-hover-background-color:rgba(36, 51, 62, 0.75);--modal-overlay-background-color:rgba(36, 51, 62, 0.8);--progress-background-color:#24333e;--progress-color:var(--primary);--loading-spinner-opacity:0.5;--tooltip-background-color:var(--contrast);--tooltip-color:var(--contrast-inverse);--icon-checkbox:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");--icon-chevron:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(162, 175, 185)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--icon-chevron-button:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--icon-chevron-button-inverse:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(0, 0, 0)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--icon-close:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(115, 130, 140)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'%3E%3C/line%3E%3Cline x1='6' y1='6' x2='18' y2='18'%3E%3C/line%3E%3C/svg%3E");--icon-date:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(162, 175, 185)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='16' y1='2' x2='16' y2='6'%3E%3C/line%3E%3Cline x1='8' y1='2' x2='8' y2='6'%3E%3C/line%3E%3Cline x1='3' y1='10' x2='21' y2='10'%3E%3C/line%3E%3C/svg%3E");--icon-invalid:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(183, 28, 28)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E");--icon-minus:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='5' y1='12' x2='19' y2='12'%3E%3C/line%3E%3C/svg%3E");--icon-search:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(162, 175, 185)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'%3E%3C/line%3E%3C/svg%3E");--icon-time:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(162, 175, 185)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cpolyline points='12 6 12 12 16 14'%3E%3C/polyline%3E%3C/svg%3E");--icon-valid:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(46, 125, 50)' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");color-scheme:dark}}[data-theme=dark]{--background-color:#11191f;--color:hsl(205deg, 16%, 77%);--h1-color:hsl(205deg, 20%, 94%);--h2-color:#e1e6eb;--h3-color:hsl(205deg, 18%, 86%);--h4-color:#c8d1d8;--h5-color:hsl(205deg, 16%, 77%);--h6-color:#afbbc4;--muted-color:hsl(205deg, 10%, 50%);--muted-border-color:#1f2d38;--primary:hsl(195deg, 85%, 41%);--primary-hover:hsl(195deg, 80%, 50%);--primary-focus:rgba(16, 149, 193, 0.25);--primary-inverse:#fff;--secondary:hsl(205deg, 15%, 41%);--secondary-hover:hsl(205deg, 10%, 50%);--secondary-focus:rgba(115, 130, 140, 0.25);--secondary-inverse:#fff;--contrast:hsl(205deg, 20%, 94%);--contrast-hover:#fff;--contrast-focus:rgba(115, 130, 140, 0.25);--contrast-inverse:#000;--mark-background-color:#d1c284;--mark-color:#11191f;--ins-color:#388e3c;--del-color:#c62828;--blockquote-border-color:var(--muted-border-color);--blockquote-footer-color:var(--muted-color);--button-box-shadow:0 0 0 rgba(0, 0, 0, 0);--button-hover-box-shadow:0 0 0 rgba(0, 0, 0, 0);--form-element-background-color:#11191f;--form-element-border-color:#374956;--form-element-color:var(--color);--form-element-placeholder-color:var(--muted-color);--form-element-active-background-color:var(--form-element-background-color);--form-element-active-border-color:var(--primary);--form-element-focus-color:var(--primary-focus);--form-element-disabled-background-color:hsl(205deg, 25%, 23%);--form-element-disabled-border-color:hsl(205deg, 20%, 32%);--form-element-disabled-opacity:0.5;--form-element-invalid-border-color:#b71c1c;--form-element-invalid-active-border-color:#c62828;--form-element-invalid-focus-color:rgba(198, 40, 40, 0.25);--form-element-valid-border-color:#2e7d32;--form-element-valid-active-border-color:#388e3c;--form-element-valid-focus-color:rgba(56, 142, 60, 0.25);--switch-background-color:#374956;--switch-color:var(--primary-inverse);--switch-checked-background-color:var(--primary);--range-border-color:#24333e;--range-active-border-color:hsl(205deg, 25%, 23%);--range-thumb-border-color:var(--background-color);--range-thumb-color:var(--secondary);--range-thumb-hover-color:var(--secondary-hover);--range-thumb-active-color:var(--primary);--table-border-color:var(--muted-border-color);--table-row-stripped-background-color:rgba(115, 130, 140, 0.05);--code-background-color:#18232c;--code-color:var(--muted-color);--code-kbd-background-color:var(--contrast);--code-kbd-color:var(--contrast-inverse);--code-tag-color:hsl(330deg, 30%, 50%);--code-property-color:hsl(185deg, 30%, 50%);--code-value-color:hsl(40deg, 10%, 50%);--code-comment-color:#4d606d;--accordion-border-color:var(--muted-border-color);--accordion-active-summary-color:var(--primary);--accordion-close-summary-color:var(--color);--accordion-open-summary-color:var(--muted-color);--card-background-color:#141e26;--card-border-color:var(--card-background-color);--card-box-shadow:0.0145rem 0.029rem 0.174rem rgba(0, 0, 0, 0.01698),0.0335rem 0.067rem 0.402rem rgba(0, 0, 0, 0.024),0.0625rem 0.125rem 0.75rem rgba(0, 0, 0, 0.03),0.1125rem 0.225rem 1.35rem rgba(0, 0, 0, 0.036),0.2085rem 0.417rem 2.502rem rgba(0, 0, 0, 0.04302),0.5rem 1rem 6rem rgba(0, 0, 0, 0.06),0 0 0 0.0625rem rgba(0, 0, 0, 0.015);--card-sectionning-background-color:#18232c;--dropdown-background-color:hsl(205deg, 30%, 15%);--dropdown-border-color:#24333e;--dropdown-box-shadow:var(--card-box-shadow);--dropdown-color:var(--color);--dropdown-hover-background-color:rgba(36, 51, 62, 0.75);--modal-overlay-background-color:rgba(36, 51, 62, 0.8);--progress-background-color:#24333e;--progress-color:var(--primary);--loading-spinner-opacity:0.5;--tooltip-background-color:var(--contrast);--tooltip-color:var(--contrast-inverse);--icon-checkbox:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");--icon-chevron:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(162, 175, 185)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--icon-chevron-button:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--icon-chevron-button-inverse:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(0, 0, 0)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--icon-close:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(115, 130, 140)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'%3E%3C/line%3E%3Cline x1='6' y1='6' x2='18' y2='18'%3E%3C/line%3E%3C/svg%3E");--icon-date:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(162, 175, 185)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='16' y1='2' x2='16' y2='6'%3E%3C/line%3E%3Cline x1='8' y1='2' x2='8' y2='6'%3E%3C/line%3E%3Cline x1='3' y1='10' x2='21' y2='10'%3E%3C/line%3E%3C/svg%3E");--icon-invalid:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(183, 28, 28)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E");--icon-minus:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='5' y1='12' x2='19' y2='12'%3E%3C/line%3E%3C/svg%3E");--icon-search:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(162, 175, 185)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'%3E%3C/line%3E%3C/svg%3E");--icon-time:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(162, 175, 185)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cpolyline points='12 6 12 12 16 14'%3E%3C/polyline%3E%3C/svg%3E");--icon-valid:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(46, 125, 50)' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");color-scheme:dark}[type=checkbox],[type=radio],[type=range],progress{accent-color:var(--primary)}*,::after,::before{box-sizing:border-box;background-repeat:no-repeat}::after,::before{text-decoration:inherit;vertical-align:inherit}:where(:root){-webkit-tap-highlight-color:transparent;-webkit-text-size-adjust:100%;-moz-text-size-adjust:100%;text-size-adjust:100%;background-color:var(--background-color);color:var(--color);font-weight:var(--font-weight);font-size:var(--font-size);line-height:var(--line-height);font-family:var(--font-family);text-rendering:optimizeLegibility;overflow-wrap:break-word;cursor:default;-moz-tab-size:4;-o-tab-size:4;tab-size:4}main{display:block}body{width:100%;margin:0}body>footer,body>header,body>main{width:100%;margin-right:auto;margin-left:auto;padding:var(--block-spacing-vertical) 0}.container,.container-fluid{width:100%;margin-right:auto;margin-left:auto;padding-right:var(--spacing);padding-left:var(--spacing)}@media (min-width:576px){.container{max-width:510px;padding-right:0;padding-left:0}}@media (min-width:768px){.container{max-width:700px}}@media (min-width:992px){.container{max-width:920px}}@media (min-width:1200px){.container{max-width:1130px}}section{margin-bottom:var(--block-spacing-vertical)}.grid{grid-column-gap:var(--grid-spacing-horizontal);grid-row-gap:var(--grid-spacing-vertical);display:grid;grid-template-columns:1fr;margin:0}@media (min-width:992px){.grid{grid-template-columns:repeat(auto-fit,minmax(0%,1fr))}}.grid>*{min-width:0}figure{display:block;margin:0;padding:0;overflow-x:auto}figure figcaption{padding:calc(var(--spacing) * .5) 0;color:var(--muted-color)}b,strong{font-weight:bolder}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}address,blockquote,dl,figure,form,ol,p,pre,table,ul{margin-top:0;margin-bottom:var(--typography-spacing-vertical);color:var(--color);font-style:normal;font-weight:var(--font-weight);font-size:var(--font-size)}[role=link],a{--color:var(--primary);--background-color:transparent;outline:0;background-color:var(--background-color);color:var(--color);-webkit-text-decoration:var(--text-decoration);text-decoration:var(--text-decoration);transition:background-color var(--transition),color var(--transition),box-shadow var(--transition),-webkit-text-decoration var(--transition);transition:background-color var(--transition),color var(--transition),text-decoration var(--transition),box-shadow var(--transition);transition:background-color var(--transition),color var(--transition),text-decoration var(--transition),box-shadow var(--transition),-webkit-text-decoration var(--transition)}[role=link]:is([aria-current],:hover,:active,:focus),a:is([aria-current],:hover,:active,:focus){--color:var(--primary-hover);--text-decoration:underline}[role=link]:focus,a:focus{--background-color:var(--primary-focus)}[role=link].secondary,a.secondary{--color:var(--secondary)}[role=link].secondary:is([aria-current],:hover,:active,:focus),a.secondary:is([aria-current],:hover,:active,:focus){--color:var(--secondary-hover)}[role=link].secondary:focus,a.secondary:focus{--background-color:var(--secondary-focus)}[role=link].contrast,a.contrast{--color:var(--contrast)}[role=link].contrast:is([aria-current],:hover,:active,:focus),a.contrast:is([aria-current],:hover,:active,:focus){--color:var(--contrast-hover)}[role=link].contrast:focus,a.contrast:focus{--background-color:var(--contrast-focus)}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:var(--typography-spacing-vertical);color:var(--color);font-weight:var(--font-weight);font-size:var(--font-size);font-family:var(--font-family)}h1{--color:var(--h1-color)}h2{--color:var(--h2-color)}h3{--color:var(--h3-color)}h4{--color:var(--h4-color)}h5{--color:var(--h5-color)}h6{--color:var(--h6-color)}:where(address,blockquote,dl,figure,form,ol,p,pre,table,ul)~:is(h1,h2,h3,h4,h5,h6){margin-top:var(--typography-spacing-vertical)}.headings,hgroup{margin-bottom:var(--typography-spacing-vertical)}.headings>*,hgroup>*{margin-bottom:0}.headings>:last-child,hgroup>:last-child{--color:var(--muted-color);--font-weight:unset;font-size:1rem;font-family:unset}p{margin-bottom:var(--typography-spacing-vertical)}small{font-size:var(--font-size)}:where(dl,ol,ul){padding-right:0;padding-left:var(--spacing);-webkit-padding-start:var(--spacing);padding-inline-start:var(--spacing);-webkit-padding-end:0;padding-inline-end:0}:where(dl,ol,ul) li{margin-bottom:calc(var(--typography-spacing-vertical) * .25)}:where(dl,ol,ul) :is(dl,ol,ul){margin:0;margin-top:calc(var(--typography-spacing-vertical) * .25)}ul li{list-style:square}mark{padding:.125rem .25rem;background-color:var(--mark-background-color);color:var(--mark-color);vertical-align:baseline}blockquote{display:block;margin:var(--typography-spacing-vertical) 0;padding:var(--spacing);border-right:none;border-left:.25rem solid var(--blockquote-border-color);-webkit-border-start:0.25rem solid var(--blockquote-border-color);border-inline-start:0.25rem solid var(--blockquote-border-color);-webkit-border-end:none;border-inline-end:none}blockquote footer{margin-top:calc(var(--typography-spacing-vertical) * .5);color:var(--blockquote-footer-color)}abbr[title]{border-bottom:1px dotted;text-decoration:none;cursor:help}ins{color:var(--ins-color);text-decoration:none}del{color:var(--del-color)}::-moz-selection{background-color:var(--primary-focus)}::selection{background-color:var(--primary-focus)}:where(audio,canvas,iframe,img,svg,video){vertical-align:middle}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}:where(iframe){border-style:none}img{max-width:100%;height:auto;border-style:none}:where(svg:not([fill])){fill:currentColor}svg:not(:root){overflow:hidden}button{margin:0;overflow:visible;font-family:inherit;text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}button{display:block;width:100%;margin-bottom:var(--spacing)}[role=button]{display:inline-block;text-decoration:none}[role=button],button,input[type=button],input[type=reset],input[type=submit]{--background-color:var(--primary);--border-color:var(--primary);--color:var(--primary-inverse);--box-shadow:var(--button-box-shadow, 0 0 0 rgba(0, 0, 0, 0));padding:var(--form-element-spacing-vertical) var(--form-element-spacing-horizontal);border:var(--border-width) solid var(--border-color);border-radius:var(--border-radius);outline:0;background-color:var(--background-color);box-shadow:var(--box-shadow);color:var(--color);font-weight:var(--font-weight);font-size:1rem;line-height:var(--line-height);text-align:center;cursor:pointer;transition:background-color var(--transition),border-color var(--transition),color var(--transition),box-shadow var(--transition)}[role=button]:is([aria-current],:hover,:active,:focus),button:is([aria-current],:hover,:active,:focus),input[type=button]:is([aria-current],:hover,:active,:focus),input[type=reset]:is([aria-current],:hover,:active,:focus),input[type=submit]:is([aria-current],:hover,:active,:focus){--background-color:var(--primary-hover);--border-color:var(--primary-hover);--box-shadow:var(--button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0));--color:var(--primary-inverse)}[role=button]:focus,button:focus,input[type=button]:focus,input[type=reset]:focus,input[type=submit]:focus{--box-shadow:var(--button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)),0 0 0 var(--outline-width) var(--primary-focus)}:is(button,input[type=submit],input[type=button],[role=button]).secondary,input[type=reset]{--background-color:var(--secondary);--border-color:var(--secondary);--color:var(--secondary-inverse);cursor:pointer}:is(button,input[type=submit],input[type=button],[role=button]).secondary:is([aria-current],:hover,:active,:focus),input[type=reset]:is([aria-current],:hover,:active,:focus){--background-color:var(--secondary-hover);--border-color:var(--secondary-hover);--color:var(--secondary-inverse)}:is(button,input[type=submit],input[type=button],[role=button]).secondary:focus,input[type=reset]:focus{--box-shadow:var(--button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)),0 0 0 var(--outline-width) var(--secondary-focus)}:is(button,input[type=submit],input[type=button],[role=button]).contrast{--background-color:var(--contrast);--border-color:var(--contrast);--color:var(--contrast-inverse)}:is(button,input[type=submit],input[type=button],[role=button]).contrast:is([aria-current],:hover,:active,:focus){--background-color:var(--contrast-hover);--border-color:var(--contrast-hover);--color:var(--contrast-inverse)}:is(button,input[type=submit],input[type=button],[role=button]).contrast:focus{--box-shadow:var(--button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)),0 0 0 var(--outline-width) var(--contrast-focus)}:is(button,input[type=submit],input[type=button],[role=button]).outline,input[type=reset].outline{--background-color:transparent;--color:var(--primary)}:is(button,input[type=submit],input[type=button],[role=button]).outline:is([aria-current],:hover,:active,:focus),input[type=reset].outline:is([aria-current],:hover,:active,:focus){--background-color:transparent;--color:var(--primary-hover)}:is(button,input[type=submit],input[type=button],[role=button]).outline.secondary,input[type=reset].outline{--color:var(--secondary)}:is(button,input[type=submit],input[type=button],[role=button]).outline.secondary:is([aria-current],:hover,:active,:focus),input[type=reset].outline:is([aria-current],:hover,:active,:focus){--color:var(--secondary-hover)}:is(button,input[type=submit],input[type=button],[role=button]).outline.contrast{--color:var(--contrast)}:is(button,input[type=submit],input[type=button],[role=button]).outline.contrast:is([aria-current],:hover,:active,:focus){--color:var(--contrast-hover)}:where(button,[type=submit],[type=button],[type=reset],[role=button])[disabled],:where(fieldset[disabled]) :is(button,[type=submit],[type=button],[type=reset],[role=button]),a[role=button]:not([href]){opacity:.5;pointer-events:none}input,optgroup,select,textarea{margin:0;font-size:1rem;line-height:var(--line-height);font-family:inherit;letter-spacing:inherit}input{overflow:visible}select{text-transform:none}legend{max-width:100%;padding:0;color:inherit;white-space:normal}textarea{overflow:auto}[type=checkbox],[type=radio]{padding:0}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}::-moz-focus-inner{padding:0;border-style:none}:-moz-focusring{outline:0}:-moz-ui-invalid{box-shadow:none}::-ms-expand{display:none}[type=file],[type=range]{padding:0;border-width:0}input:not([type=checkbox],[type=radio],[type=range]){height:calc(1rem * var(--line-height) + var(--form-element-spacing-vertical) * 2 + var(--border-width) * 2)}fieldset{margin:0;margin-bottom:var(--spacing);padding:0;border:0}fieldset legend,label{display:block;margin-bottom:calc(var(--spacing) * .25);font-weight:var(--form-label-font-weight,var(--font-weight))}input:not([type=checkbox],[type=radio]),select,textarea{width:100%}input:not([type=checkbox],[type=radio],[type=range],[type=file]),select,textarea{-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:var(--form-element-spacing-vertical) var(--form-element-spacing-horizontal)}input,select,textarea{--background-color:var(--form-element-background-color);--border-color:var(--form-element-border-color);--color:var(--form-element-color);--box-shadow:none;border:var(--border-width) solid var(--border-color);border-radius:var(--border-radius);outline:0;background-color:var(--background-color);box-shadow:var(--box-shadow);color:var(--color);font-weight:var(--font-weight);transition:background-color var(--transition),border-color var(--transition),color var(--transition),box-shadow var(--transition)}:where(select,textarea):is(:active,:focus),input:not([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[readonly]):is(:active,:focus){--background-color:var(--form-element-active-background-color)}:where(select,textarea):is(:active,:focus),input:not([type=submit],[type=button],[type=reset],[role=switch],[readonly]):is(:active,:focus){--border-color:var(--form-element-active-border-color)}input:not([type=submit],[type=button],[type=reset],[type=range],[type=file],[readonly]):focus,select:focus,textarea:focus{--box-shadow:0 0 0 var(--outline-width) var(--form-element-focus-color)}:where(fieldset[disabled]) :is(input:not([type=submit],[type=button],[type=reset]),select,textarea),input:not([type=submit],[type=button],[type=reset])[disabled],select[disabled],textarea[disabled]{--background-color:var(--form-element-disabled-background-color);--border-color:var(--form-element-disabled-border-color);opacity:var(--form-element-disabled-opacity);pointer-events:none}:where(input,select,textarea):not([type=checkbox],[type=radio],[type=date],[type=datetime-local],[type=month],[type=time],[type=week])[aria-invalid]{padding-right:calc(var(--form-element-spacing-horizontal) + 1.5rem)!important;padding-left:var(--form-element-spacing-horizontal);-webkit-padding-start:var(--form-element-spacing-horizontal)!important;padding-inline-start:var(--form-element-spacing-horizontal)!important;-webkit-padding-end:calc(var(--form-element-spacing-horizontal) + 1.5rem)!important;padding-inline-end:calc(var(--form-element-spacing-horizontal) + 1.5rem)!important;background-position:center right .75rem;background-size:1rem auto;background-repeat:no-repeat}:where(input,select,textarea):not([type=checkbox],[type=radio],[type=date],[type=datetime-local],[type=month],[type=time],[type=week])[aria-invalid=false]{background-image:var(--icon-valid)}:where(input,select,textarea):not([type=checkbox],[type=radio],[type=date],[type=datetime-local],[type=month],[type=time],[type=week])[aria-invalid=true]{background-image:var(--icon-invalid)}:where(input,select,textarea)[aria-invalid=false]{--border-color:var(--form-element-valid-border-color)}:where(input,select,textarea)[aria-invalid=false]:is(:active,:focus){--border-color:var(--form-element-valid-active-border-color)!important;--box-shadow:0 0 0 var(--outline-width) var(--form-element-valid-focus-color)!important}:where(input,select,textarea)[aria-invalid=true]{--border-color:var(--form-element-invalid-border-color)}:where(input,select,textarea)[aria-invalid=true]:is(:active,:focus){--border-color:var(--form-element-invalid-active-border-color)!important;--box-shadow:0 0 0 var(--outline-width) var(--form-element-invalid-focus-color)!important}[dir=rtl] :where(input,select,textarea):not([type=checkbox],[type=radio]):is([aria-invalid],[aria-invalid=true],[aria-invalid=false]){background-position:center left .75rem}input::-webkit-input-placeholder,input::placeholder,select:invalid,textarea::-webkit-input-placeholder,textarea::placeholder{color:var(--form-element-placeholder-color);opacity:1}input:not([type=checkbox],[type=radio]),select,textarea{margin-bottom:var(--spacing)}select::-ms-expand{border:0;background-color:transparent}select:not([multiple],[size]){padding-right:calc(var(--form-element-spacing-horizontal) + 1.5rem);padding-left:var(--form-element-spacing-horizontal);-webkit-padding-start:var(--form-element-spacing-horizontal);padding-inline-start:var(--form-element-spacing-horizontal);-webkit-padding-end:calc(var(--form-element-spacing-horizontal) + 1.5rem);padding-inline-end:calc(var(--form-element-spacing-horizontal) + 1.5rem);background-image:var(--icon-chevron);background-position:center right .75rem;background-size:1rem auto;background-repeat:no-repeat}[dir=rtl] select:not([multiple],[size]){background-position:center left .75rem}:where(input,select,textarea,.grid)+small{display:block;width:100%;margin-top:calc(var(--spacing) * -.75);margin-bottom:var(--spacing);color:var(--muted-color)}label>:where(input,select,textarea){margin-top:calc(var(--spacing) * .25)}[type=checkbox],[type=radio]{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:1.25em;height:1.25em;margin-top:-.125em;margin-right:.375em;margin-left:0;-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:.375em;margin-inline-end:.375em;border-width:var(--border-width);font-size:inherit;vertical-align:middle;cursor:pointer}[type=checkbox]::-ms-check,[type=radio]::-ms-check{display:none}[type=checkbox]:checked,[type=checkbox]:checked:active,[type=checkbox]:checked:focus,[type=radio]:checked,[type=radio]:checked:active,[type=radio]:checked:focus{--background-color:var(--primary);--border-color:var(--primary);background-image:var(--icon-checkbox);background-position:center;background-size:.75em auto;background-repeat:no-repeat}[type=checkbox]~label,[type=radio]~label{display:inline-block;margin-right:.375em;margin-bottom:0;cursor:pointer}[type=checkbox]:indeterminate{--background-color:var(--primary);--border-color:var(--primary);background-image:var(--icon-minus);background-position:center;background-size:.75em auto;background-repeat:no-repeat}[type=radio]{border-radius:50%}[type=radio]:checked,[type=radio]:checked:active,[type=radio]:checked:focus{--background-color:var(--primary-inverse);border-width:.35em;background-image:none}[type=checkbox][role=switch]{--background-color:var(--switch-background-color);--border-color:var(--switch-background-color);--color:var(--switch-color);width:2.25em;height:1.25em;border:var(--border-width) solid var(--border-color);border-radius:1.25em;background-color:var(--background-color);line-height:1.25em}[type=checkbox][role=switch]:focus{--background-color:var(--switch-background-color);--border-color:var(--switch-background-color)}[type=checkbox][role=switch]:checked{--background-color:var(--switch-checked-background-color);--border-color:var(--switch-checked-background-color)}[type=checkbox][role=switch]:before{display:block;width:calc(1.25em - (var(--border-width) * 2));height:100%;border-radius:50%;background-color:var(--color);content:"";transition:margin .1s ease-in-out}[type=checkbox][role=switch]:checked{background-image:none}[type=checkbox][role=switch]:checked::before{margin-left:calc(1.125em - var(--border-width));-webkit-margin-start:calc(1.125em - var(--border-width));margin-inline-start:calc(1.125em - var(--border-width))}[type=checkbox]:checked[aria-invalid=false],[type=checkbox][aria-invalid=false],[type=checkbox][role=switch]:checked[aria-invalid=false],[type=checkbox][role=switch][aria-invalid=false],[type=radio]:checked[aria-invalid=false],[type=radio][aria-invalid=false]{--border-color:var(--form-element-valid-border-color)}[type=checkbox]:checked[aria-invalid=true],[type=checkbox][aria-invalid=true],[type=checkbox][role=switch]:checked[aria-invalid=true],[type=checkbox][role=switch][aria-invalid=true],[type=radio]:checked[aria-invalid=true],[type=radio][aria-invalid=true]{--border-color:var(--form-element-invalid-border-color)}[type=color]::-webkit-color-swatch-wrapper{padding:0}[type=color]::-moz-focus-inner{padding:0}[type=color]::-webkit-color-swatch{border:0;border-radius:calc(var(--border-radius) * .5)}[type=color]::-moz-color-swatch{border:0;border-radius:calc(var(--border-radius) * .5)}input:not([type=checkbox],[type=radio],[type=range],[type=file]):is([type=date],[type=datetime-local],[type=month],[type=time],[type=week]){--icon-position:0.75rem;--icon-width:1rem;padding-right:calc(var(--icon-width) + var(--icon-position));background-image:var(--icon-date);background-position:center right var(--icon-position);background-size:var(--icon-width) auto;background-repeat:no-repeat}input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=time]{background-image:var(--icon-time)}[type=date]::-webkit-calendar-picker-indicator,[type=datetime-local]::-webkit-calendar-picker-indicator,[type=month]::-webkit-calendar-picker-indicator,[type=time]::-webkit-calendar-picker-indicator,[type=week]::-webkit-calendar-picker-indicator{width:var(--icon-width);margin-right:calc(var(--icon-width) * -1);margin-left:var(--icon-position);opacity:0}[dir=rtl] :is([type=date],[type=datetime-local],[type=month],[type=time],[type=week]){text-align:right}[type=file]{--color:var(--muted-color);padding:calc(var(--form-element-spacing-vertical) * .5) 0;border:0;border-radius:0;background:0 0}[type=file]::file-selector-button{--background-color:var(--secondary);--border-color:var(--secondary);--color:var(--secondary-inverse);margin-right:calc(var(--spacing)/ 2);margin-left:0;-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:calc(var(--spacing)/ 2);margin-inline-end:calc(var(--spacing)/ 2);padding:calc(var(--form-element-spacing-vertical) * .5) calc(var(--form-element-spacing-horizontal) * .5);border:var(--border-width) solid var(--border-color);border-radius:var(--border-radius);outline:0;background-color:var(--background-color);box-shadow:var(--box-shadow);color:var(--color);font-weight:var(--font-weight);font-size:1rem;line-height:var(--line-height);text-align:center;cursor:pointer;transition:background-color var(--transition),border-color var(--transition),color var(--transition),box-shadow var(--transition)}[type=file]::file-selector-button:is(:hover,:active,:focus){--background-color:var(--secondary-hover);--border-color:var(--secondary-hover)}[type=file]::-webkit-file-upload-button{--background-color:var(--secondary);--border-color:var(--secondary);--color:var(--secondary-inverse);margin-right:calc(var(--spacing)/ 2);margin-left:0;-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:calc(var(--spacing)/ 2);margin-inline-end:calc(var(--spacing)/ 2);padding:calc(var(--form-element-spacing-vertical) * .5) calc(var(--form-element-spacing-horizontal) * .5);border:var(--border-width) solid var(--border-color);border-radius:var(--border-radius);outline:0;background-color:var(--background-color);box-shadow:var(--box-shadow);color:var(--color);font-weight:var(--font-weight);font-size:1rem;line-height:var(--line-height);text-align:center;cursor:pointer;-webkit-transition:background-color var(--transition),border-color var(--transition),color var(--transition),box-shadow var(--transition);transition:background-color var(--transition),border-color var(--transition),color var(--transition),box-shadow var(--transition)}[type=file]::-webkit-file-upload-button:is(:hover,:active,:focus){--background-color:var(--secondary-hover);--border-color:var(--secondary-hover)}[type=file]::-ms-browse{--background-color:var(--secondary);--border-color:var(--secondary);--color:var(--secondary-inverse);margin-right:calc(var(--spacing)/ 2);margin-left:0;margin-inline-start:0;margin-inline-end:calc(var(--spacing)/ 2);padding:calc(var(--form-element-spacing-vertical) * .5) calc(var(--form-element-spacing-horizontal) * .5);border:var(--border-width) solid var(--border-color);border-radius:var(--border-radius);outline:0;background-color:var(--background-color);box-shadow:var(--box-shadow);color:var(--color);font-weight:var(--font-weight);font-size:1rem;line-height:var(--line-height);text-align:center;cursor:pointer;-ms-transition:background-color var(--transition),border-color var(--transition),color var(--transition),box-shadow var(--transition);transition:background-color var(--transition),border-color var(--transition),color var(--transition),box-shadow var(--transition)}[type=file]::-ms-browse:is(:hover,:active,:focus){--background-color:var(--secondary-hover);--border-color:var(--secondary-hover)}[type=range]{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:100%;height:1.25rem;background:0 0}[type=range]::-webkit-slider-runnable-track{width:100%;height:.25rem;border-radius:var(--border-radius);background-color:var(--range-border-color);-webkit-transition:background-color var(--transition),box-shadow var(--transition);transition:background-color var(--transition),box-shadow var(--transition)}[type=range]::-moz-range-track{width:100%;height:.25rem;border-radius:var(--border-radius);background-color:var(--range-border-color);-moz-transition:background-color var(--transition),box-shadow var(--transition);transition:background-color var(--transition),box-shadow var(--transition)}[type=range]::-ms-track{width:100%;height:.25rem;border-radius:var(--border-radius);background-color:var(--range-border-color);-ms-transition:background-color var(--transition),box-shadow var(--transition);transition:background-color var(--transition),box-shadow var(--transition)}[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:1.25rem;height:1.25rem;margin-top:-.5rem;border:2px solid var(--range-thumb-border-color);border-radius:50%;background-color:var(--range-thumb-color);cursor:pointer;-webkit-transition:background-color var(--transition),transform var(--transition);transition:background-color var(--transition),transform var(--transition)}[type=range]::-moz-range-thumb{-webkit-appearance:none;width:1.25rem;height:1.25rem;margin-top:-.5rem;border:2px solid var(--range-thumb-border-color);border-radius:50%;background-color:var(--range-thumb-color);cursor:pointer;-moz-transition:background-color var(--transition),transform var(--transition);transition:background-color var(--transition),transform var(--transition)}[type=range]::-ms-thumb{-webkit-appearance:none;width:1.25rem;height:1.25rem;margin-top:-.5rem;border:2px solid var(--range-thumb-border-color);border-radius:50%;background-color:var(--range-thumb-color);cursor:pointer;-ms-transition:background-color var(--transition),transform var(--transition);transition:background-color var(--transition),transform var(--transition)}[type=range]:focus,[type=range]:hover{--range-border-color:var(--range-active-border-color);--range-thumb-color:var(--range-thumb-hover-color)}[type=range]:active{--range-thumb-color:var(--range-thumb-active-color)}[type=range]:active::-webkit-slider-thumb{transform:scale(1.25)}[type=range]:active::-moz-range-thumb{transform:scale(1.25)}[type=range]:active::-ms-thumb{transform:scale(1.25)}input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=search]{-webkit-padding-start:calc(var(--form-element-spacing-horizontal) + 1.75rem);padding-inline-start:calc(var(--form-element-spacing-horizontal) + 1.75rem);border-radius:5rem;background-image:var(--icon-search);background-position:center left 1.125rem;background-size:1rem auto;background-repeat:no-repeat}input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=search][aria-invalid]{-webkit-padding-start:calc(var(--form-element-spacing-horizontal) + 1.75rem)!important;padding-inline-start:calc(var(--form-element-spacing-horizontal) + 1.75rem)!important;background-position:center left 1.125rem,center right .75rem}input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=search][aria-invalid=false]{background-image:var(--icon-search),var(--icon-valid)}input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=search][aria-invalid=true]{background-image:var(--icon-search),var(--icon-invalid)}[type=search]::-webkit-search-cancel-button{-webkit-appearance:none;display:none}[dir=rtl] :where(input):not([type=checkbox],[type=radio],[type=range],[type=file])[type=search]{background-position:center right 1.125rem}[dir=rtl] :where(input):not([type=checkbox],[type=radio],[type=range],[type=file])[type=search][aria-invalid]{background-position:center right 1.125rem,center left .75rem}:where(table){width:100%;border-collapse:collapse;border-spacing:0;text-indent:0}td,th{padding:calc(var(--spacing)/ 2) var(--spacing);border-bottom:var(--border-width) solid var(--table-border-color);color:var(--color);font-weight:var(--font-weight);font-size:var(--font-size);text-align:left;text-align:start}tfoot td,tfoot th{border-top:var(--border-width) solid var(--table-border-color);border-bottom:0}table[role=grid] tbody tr:nth-child(odd){background-color:var(--table-row-stripped-background-color)}code,kbd,pre,samp{font-size:.875em;font-family:var(--font-family)}pre{-ms-overflow-style:scrollbar;overflow:auto}code,kbd,pre{border-radius:var(--border-radius);background:var(--code-background-color);color:var(--code-color);font-weight:var(--font-weight);line-height:initial}code,kbd{display:inline-block;padding:.375rem .5rem}pre{display:block;margin-bottom:var(--spacing);overflow-x:auto}pre>code{display:block;padding:var(--spacing);background:0 0;font-size:14px;line-height:var(--line-height)}code b{color:var(--code-tag-color);font-weight:var(--font-weight)}code i{color:var(--code-property-color);font-style:normal}code u{color:var(--code-value-color);text-decoration:none}code em{color:var(--code-comment-color);font-style:normal}kbd{background-color:var(--code-kbd-background-color);color:var(--code-kbd-color);vertical-align:baseline}hr{height:0;border:0;border-top:1px solid var(--muted-border-color);color:inherit}[hidden],template{display:none!important}canvas{display:inline-block}details{display:block;margin-bottom:var(--spacing);padding-bottom:var(--spacing);border-bottom:var(--border-width) solid var(--accordion-border-color)}details summary{line-height:1rem;list-style-type:none;cursor:pointer;transition:color var(--transition)}details summary:not([role]){color:var(--accordion-close-summary-color)}details summary::-webkit-details-marker{display:none}details summary::marker{display:none}details summary::-moz-list-bullet{list-style-type:none}details summary::after{display:block;width:1rem;height:1rem;-webkit-margin-start:calc(var(--spacing,1rem) * 0.5);margin-inline-start:calc(var(--spacing,1rem) * .5);float:right;transform:rotate(-90deg);background-image:var(--icon-chevron);background-position:right center;background-size:1rem auto;background-repeat:no-repeat;content:"";transition:transform var(--transition)}details summary:focus{outline:0}details summary:focus:not([role=button]){color:var(--accordion-active-summary-color)}details summary[role=button]{width:100%;text-align:left}details summary[role=button]::after{height:calc(1rem * var(--line-height,1.5));background-image:var(--icon-chevron-button)}details summary[role=button]:not(.outline).contrast::after{background-image:var(--icon-chevron-button-inverse)}details[open]>summary{margin-bottom:calc(var(--spacing))}details[open]>summary:not([role]):not(:focus){color:var(--accordion-open-summary-color)}details[open]>summary::after{transform:rotate(0)}[dir=rtl] details summary{text-align:right}[dir=rtl] details summary::after{float:left;background-position:left center}article{margin:var(--block-spacing-vertical) 0;padding:var(--block-spacing-vertical) var(--block-spacing-horizontal);border-radius:var(--border-radius);background:var(--card-background-color);box-shadow:var(--card-box-shadow)}article>footer,article>header{margin-right:calc(var(--block-spacing-horizontal) * -1);margin-left:calc(var(--block-spacing-horizontal) * -1);padding:calc(var(--block-spacing-vertical) * .66) var(--block-spacing-horizontal);background-color:var(--card-sectionning-background-color)}article>header{margin-top:calc(var(--block-spacing-vertical) * -1);margin-bottom:var(--block-spacing-vertical);border-bottom:var(--border-width) solid var(--card-border-color);border-top-right-radius:var(--border-radius);border-top-left-radius:var(--border-radius)}article>footer{margin-top:var(--block-spacing-vertical);margin-bottom:calc(var(--block-spacing-vertical) * -1);border-top:var(--border-width) solid var(--card-border-color);border-bottom-right-radius:var(--border-radius);border-bottom-left-radius:var(--border-radius)}:root{--scrollbar-width:0px}dialog{display:flex;z-index:999;position:fixed;top:0;right:0;bottom:0;left:0;align-items:center;justify-content:center;width:inherit;min-width:100%;height:inherit;min-height:100%;padding:var(--spacing);border:0;-webkit-backdrop-filter:var(--modal-overlay-backdrop-filter);backdrop-filter:var(--modal-overlay-backdrop-filter);background-color:var(--modal-overlay-background-color);color:var(--color)}dialog article{max-height:calc(100vh - var(--spacing) * 2);overflow:auto}@media (min-width:576px){dialog article{max-width:510px}}@media (min-width:768px){dialog article{max-width:700px}}dialog article>footer,dialog article>header{padding:calc(var(--block-spacing-vertical) * .5) var(--block-spacing-horizontal)}dialog article>header .close{margin:0;margin-left:var(--spacing);float:right}dialog article>footer{text-align:right}dialog article>footer [role=button]{margin-bottom:0}dialog article>footer [role=button]:not(:first-of-type){margin-left:calc(var(--spacing) * .5)}dialog article p:last-of-type{margin:0}dialog article .close{display:block;width:1rem;height:1rem;margin-top:calc(var(--block-spacing-vertical) * -.5);margin-bottom:var(--typography-spacing-vertical);margin-left:auto;background-image:var(--icon-close);background-position:center;background-size:auto 1rem;background-repeat:no-repeat;opacity:.5;transition:opacity var(--transition)}dialog article .close:is([aria-current],:hover,:active,:focus){opacity:1}dialog:not([open]),dialog[open=false]{display:none}.modal-is-open{padding-right:var(--scrollbar-width,0);overflow:hidden;pointer-events:none;touch-action:none}.modal-is-open dialog{pointer-events:auto}:where(.modal-is-opening,.modal-is-closing) dialog,:where(.modal-is-opening,.modal-is-closing) dialog>article{animation-duration:.2s;animation-timing-function:ease-in-out;animation-fill-mode:both}:where(.modal-is-opening,.modal-is-closing) dialog{animation-duration:.8s;animation-name:modal-overlay}:where(.modal-is-opening,.modal-is-closing) dialog>article{animation-delay:.2s;animation-name:modal}.modal-is-closing dialog,.modal-is-closing dialog>article{animation-delay:0s;animation-direction:reverse}@keyframes modal-overlay{from{-webkit-backdrop-filter:none;backdrop-filter:none;background-color:transparent}}@keyframes modal{from{transform:translateY(-100%);opacity:0}}:where(nav li)::before{float:left;content:""}nav,nav ul{display:flex}nav{justify-content:space-between}nav ol,nav ul{align-items:center;margin-bottom:0;padding:0;list-style:none}nav ol:first-of-type,nav ul:first-of-type{margin-left:calc(var(--nav-element-spacing-horizontal) * -1)}nav ol:last-of-type,nav ul:last-of-type{margin-right:calc(var(--nav-element-spacing-horizontal) * -1)}nav li{display:inline-block;margin:0;padding:var(--nav-element-spacing-vertical) var(--nav-element-spacing-horizontal)}nav li>*{--spacing:0}nav :where(a,[role=link]){display:inline-block;margin:calc(var(--nav-link-spacing-vertical) * -1) calc(var(--nav-link-spacing-horizontal) * -1);padding:var(--nav-link-spacing-vertical) var(--nav-link-spacing-horizontal);border-radius:var(--border-radius);text-decoration:none}nav :where(a,[role=link]):is([aria-current],:hover,:active,:focus){text-decoration:none}nav[aria-label=breadcrumb]{align-items:center;justify-content:start}nav[aria-label=breadcrumb] ul li:not(:first-child){-webkit-margin-start:var(--nav-link-spacing-horizontal);margin-inline-start:var(--nav-link-spacing-horizontal)}nav[aria-label=breadcrumb] ul li:not(:last-child) ::after{position:absolute;width:calc(var(--nav-link-spacing-horizontal) * 2);-webkit-margin-start:calc(var(--nav-link-spacing-horizontal)/ 2);margin-inline-start:calc(var(--nav-link-spacing-horizontal)/ 2);content:"/";color:var(--muted-color);text-align:center}nav[aria-label=breadcrumb] a[aria-current]{background-color:transparent;color:inherit;text-decoration:none;pointer-events:none}nav [role=button]{margin-right:inherit;margin-left:inherit;padding:var(--nav-link-spacing-vertical) var(--nav-link-spacing-horizontal)}aside li,aside nav,aside ol,aside ul{display:block}aside li{padding:calc(var(--nav-element-spacing-vertical) * .5) var(--nav-element-spacing-horizontal)}aside li a{display:block}aside li [role=button]{margin:inherit}[dir=rtl] nav[aria-label=breadcrumb] ul li:not(:last-child) ::after{content:"\\"}progress{display:inline-block;vertical-align:baseline}progress{-webkit-appearance:none;-moz-appearance:none;display:inline-block;appearance:none;width:100%;height:.5rem;margin-bottom:calc(var(--spacing) * .5);overflow:hidden;border:0;border-radius:var(--border-radius);background-color:var(--progress-background-color);color:var(--progress-color)}progress::-webkit-progress-bar{border-radius:var(--border-radius);background:0 0}progress[value]::-webkit-progress-value{background-color:var(--progress-color)}progress::-moz-progress-bar{background-color:var(--progress-color)}@media (prefers-reduced-motion:no-preference){progress:indeterminate{background:var(--progress-background-color) linear-gradient(to right,var(--progress-color) 30%,var(--progress-background-color) 30%) top left/150% 150% no-repeat;animation:progress-indeterminate 1s linear infinite}progress:indeterminate[value]::-webkit-progress-value{background-color:transparent}progress:indeterminate::-moz-progress-bar{background-color:transparent}}@media (prefers-reduced-motion:no-preference){[dir=rtl] progress:indeterminate{animation-direction:reverse}}@keyframes progress-indeterminate{0%{background-position:200% 0}100%{background-position:-200% 0}}details[role=list],li[role=list]{position:relative}details[role=list] summary+ul,li[role=list]>ul{display:flex;z-index:99;position:absolute;top:auto;right:0;left:0;flex-direction:column;margin:0;padding:0;border:var(--border-width) solid var(--dropdown-border-color);border-radius:var(--border-radius);border-top-right-radius:0;border-top-left-radius:0;background-color:var(--dropdown-background-color);box-shadow:var(--card-box-shadow);color:var(--dropdown-color);white-space:nowrap}details[role=list] summary+ul li,li[role=list]>ul li{width:100%;margin-bottom:0;padding:calc(var(--form-element-spacing-vertical) * .5) var(--form-element-spacing-horizontal);list-style:none}details[role=list] summary+ul li:first-of-type,li[role=list]>ul li:first-of-type{margin-top:calc(var(--form-element-spacing-vertical) * .5)}details[role=list] summary+ul li:last-of-type,li[role=list]>ul li:last-of-type{margin-bottom:calc(var(--form-element-spacing-vertical) * .5)}details[role=list] summary+ul li a,li[role=list]>ul li a{display:block;margin:calc(var(--form-element-spacing-vertical) * -.5) calc(var(--form-element-spacing-horizontal) * -1);padding:calc(var(--form-element-spacing-vertical) * .5) var(--form-element-spacing-horizontal);overflow:hidden;color:var(--dropdown-color);text-decoration:none;text-overflow:ellipsis}details[role=list] summary+ul li a:hover,li[role=list]>ul li a:hover{background-color:var(--dropdown-hover-background-color)}details[role=list] summary::after,li[role=list]>a::after{display:block;width:1rem;height:calc(1rem * var(--line-height,1.5));-webkit-margin-start:0.5rem;margin-inline-start:.5rem;float:right;transform:rotate(0);background-position:right center;background-size:1rem auto;background-repeat:no-repeat;content:""}details[role=list]{padding:0;border-bottom:none}details[role=list] summary{margin-bottom:0}details[role=list] summary:not([role]){height:calc(1rem * var(--line-height) + var(--form-element-spacing-vertical) * 2 + var(--border-width) * 2);padding:var(--form-element-spacing-vertical) var(--form-element-spacing-horizontal);border:var(--border-width) solid var(--form-element-border-color);border-radius:var(--border-radius);background-color:var(--form-element-background-color);color:var(--form-element-placeholder-color);line-height:inherit;cursor:pointer;transition:background-color var(--transition),border-color var(--transition),color var(--transition),box-shadow var(--transition)}details[role=list] summary:not([role]):active,details[role=list] summary:not([role]):focus{border-color:var(--form-element-active-border-color);background-color:var(--form-element-active-background-color)}details[role=list] summary:not([role]):focus{box-shadow:0 0 0 var(--outline-width) var(--form-element-focus-color)}details[role=list][open] summary{border-bottom-right-radius:0;border-bottom-left-radius:0}details[role=list][open] summary::before{display:block;z-index:1;position:fixed;top:0;right:0;bottom:0;left:0;background:0 0;content:"";cursor:default}nav details[role=list] summary,nav li[role=list] a{display:flex;direction:ltr}nav details[role=list] summary+ul,nav li[role=list]>ul{min-width:-moz-fit-content;min-width:fit-content;border-radius:var(--border-radius)}nav details[role=list] summary+ul li a,nav li[role=list]>ul li a{border-radius:0}nav details[role=list] summary,nav details[role=list] summary:not([role]){height:auto;padding:var(--nav-link-spacing-vertical) var(--nav-link-spacing-horizontal)}nav details[role=list][open] summary{border-radius:var(--border-radius)}nav details[role=list] summary+ul{margin-top:var(--outline-width);-webkit-margin-start:0;margin-inline-start:0}nav details[role=list] summary[role=link]{margin-bottom:calc(var(--nav-link-spacing-vertical) * -1);line-height:var(--line-height)}nav details[role=list] summary[role=link]+ul{margin-top:calc(var(--nav-link-spacing-vertical) + var(--outline-width));-webkit-margin-start:calc(var(--nav-link-spacing-horizontal) * -1);margin-inline-start:calc(var(--nav-link-spacing-horizontal) * -1)}li[role=list] a:active~ul,li[role=list] a:focus~ul,li[role=list]:hover>ul{display:flex}li[role=list]>ul{display:none;margin-top:calc(var(--nav-link-spacing-vertical) + var(--outline-width));-webkit-margin-start:calc(var(--nav-element-spacing-horizontal) - var(--nav-link-spacing-horizontal));margin-inline-start:calc(var(--nav-element-spacing-horizontal) - var(--nav-link-spacing-horizontal))}li[role=list]>a::after{background-image:var(--icon-chevron)}[aria-busy=true]{cursor:progress}[aria-busy=true]:not(input,select,textarea)::before{display:inline-block;width:1em;height:1em;border:.1875em solid currentColor;border-radius:1em;border-right-color:transparent;content:"";vertical-align:text-bottom;vertical-align:-.125em;animation:spinner .75s linear infinite;opacity:var(--loading-spinner-opacity)}[aria-busy=true]:not(input,select,textarea):not(:empty)::before{margin-right:calc(var(--spacing) * .5);margin-left:0;-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:calc(var(--spacing) * .5);margin-inline-end:calc(var(--spacing) * .5)}[aria-busy=true]:not(input,select,textarea):empty{text-align:center}a[aria-busy=true],button[aria-busy=true],input[type=button][aria-busy=true],input[type=reset][aria-busy=true],input[type=submit][aria-busy=true]{pointer-events:none}@keyframes spinner{to{transform:rotate(360deg)}}[data-tooltip]{position:relative}[data-tooltip]:not(a,button,input){border-bottom:1px dotted;text-decoration:none;cursor:help}[data-tooltip]::after,[data-tooltip]::before,[data-tooltip][data-placement=top]::after,[data-tooltip][data-placement=top]::before{display:block;z-index:99;position:absolute;bottom:100%;left:50%;padding:.25rem .5rem;overflow:hidden;transform:translate(-50%,-.25rem);border-radius:var(--border-radius);background:var(--tooltip-background-color);content:attr(data-tooltip);color:var(--tooltip-color);font-style:normal;font-weight:var(--font-weight);font-size:.875rem;text-decoration:none;text-overflow:ellipsis;white-space:nowrap;opacity:0;pointer-events:none}[data-tooltip]::after,[data-tooltip][data-placement=top]::after{padding:0;transform:translate(-50%,0);border-top:.3rem solid;border-right:.3rem solid transparent;border-left:.3rem solid transparent;border-radius:0;background-color:transparent;content:"";color:var(--tooltip-background-color)}[data-tooltip][data-placement=bottom]::after,[data-tooltip][data-placement=bottom]::before{top:100%;bottom:auto;transform:translate(-50%,.25rem)}[data-tooltip][data-placement=bottom]:after{transform:translate(-50%,-.3rem);border:.3rem solid transparent;border-bottom:.3rem solid}[data-tooltip][data-placement=left]::after,[data-tooltip][data-placement=left]::before{top:50%;right:100%;bottom:auto;left:auto;transform:translate(-.25rem,-50%)}[data-tooltip][data-placement=left]:after{transform:translate(.3rem,-50%);border:.3rem solid transparent;border-left:.3rem solid}[data-tooltip][data-placement=right]::after,[data-tooltip][data-placement=right]::before{top:50%;right:auto;bottom:auto;left:100%;transform:translate(.25rem,-50%)}[data-tooltip][data-placement=right]:after{transform:translate(-.3rem,-50%);border:.3rem solid transparent;border-right:.3rem solid}[data-tooltip]:focus::after,[data-tooltip]:focus::before,[data-tooltip]:hover::after,[data-tooltip]:hover::before{opacity:1}@media (hover:hover) and (pointer:fine){[data-tooltip]:hover::after,[data-tooltip]:hover::before,[data-tooltip][data-placement=bottom]:focus::after,[data-tooltip][data-placement=bottom]:focus::before,[data-tooltip][data-placement=bottom]:hover [data-tooltip]:focus::after,[data-tooltip][data-placement=bottom]:hover [data-tooltip]:focus::before{animation-duration:.2s;animation-name:tooltip-slide-top}[data-tooltip]:hover::after,[data-tooltip][data-placement=bottom]:focus::after,[data-tooltip][data-placement=bottom]:hover [data-tooltip]:focus::after{animation-name:tooltip-caret-slide-top}[data-tooltip][data-placement=bottom]:focus::after,[data-tooltip][data-placement=bottom]:focus::before,[data-tooltip][data-placement=bottom]:hover::after,[data-tooltip][data-placement=bottom]:hover::before{animation-duration:.2s;animation-name:tooltip-slide-bottom}[data-tooltip][data-placement=bottom]:focus::after,[data-tooltip][data-placement=bottom]:hover::after{animation-name:tooltip-caret-slide-bottom}[data-tooltip][data-placement=left]:focus::after,[data-tooltip][data-placement=left]:focus::before,[data-tooltip][data-placement=left]:hover::after,[data-tooltip][data-placement=left]:hover::before{animation-duration:.2s;animation-name:tooltip-slide-left}[data-tooltip][data-placement=left]:focus::after,[data-tooltip][data-placement=left]:hover::after{animation-name:tooltip-caret-slide-left}[data-tooltip][data-placement=right]:focus::after,[data-tooltip][data-placement=right]:focus::before,[data-tooltip][data-placement=right]:hover::after,[data-tooltip][data-placement=right]:hover::before{animation-duration:.2s;animation-name:tooltip-slide-right}[data-tooltip][data-placement=right]:focus::after,[data-tooltip][data-placement=right]:hover::after{animation-name:tooltip-caret-slide-right}}@keyframes tooltip-slide-top{from{transform:translate(-50%,.75rem);opacity:0}to{transform:translate(-50%,-.25rem);opacity:1}}@keyframes tooltip-caret-slide-top{from{opacity:0}50%{transform:translate(-50%,-.25rem);opacity:0}to{transform:translate(-50%,0);opacity:1}}@keyframes tooltip-slide-bottom{from{transform:translate(-50%,-.75rem);opacity:0}to{transform:translate(-50%,.25rem);opacity:1}}@keyframes tooltip-caret-slide-bottom{from{opacity:0}50%{transform:translate(-50%,-.5rem);opacity:0}to{transform:translate(-50%,-.3rem);opacity:1}}@keyframes tooltip-slide-left{from{transform:translate(.75rem,-50%);opacity:0}to{transform:translate(-.25rem,-50%);opacity:1}}@keyframes tooltip-caret-slide-left{from{opacity:0}50%{transform:translate(.05rem,-50%);opacity:0}to{transform:translate(.3rem,-50%);opacity:1}}@keyframes tooltip-slide-right{from{transform:translate(-.75rem,-50%);opacity:0}to{transform:translate(.25rem,-50%);opacity:1}}@keyframes tooltip-caret-slide-right{from{opacity:0}50%{transform:translate(-.05rem,-50%);opacity:0}to{transform:translate(-.3rem,-50%);opacity:1}}[aria-controls]{cursor:pointer}[aria-disabled=true],[disabled]{cursor:not-allowed}[aria-hidden=false][hidden]{display:initial}[aria-hidden=false][hidden]:not(:focus){clip:rect(0,0,0,0);position:absolute}[tabindex],a,area,button,input,label,select,summary,textarea{-ms-touch-action:manipulation}[dir=rtl]{direction:rtl}@media (prefers-reduced-motion:reduce){:not([aria-busy=true]),:not([aria-busy=true])::after,:not([aria-busy=true])::before{background-attachment:initial!important;animation-duration:1ms!important;animation-delay:-1ms!important;animation-iteration-count:1!important;scroll-behavior:auto!important;transition-delay:0s!important;transition-duration:0s!important}}
\ No newline at end of file
diff --git a/docs/state/README.md b/docs/state/README.md
new file mode 100644
index 00000000..c38572c8
--- /dev/null
+++ b/docs/state/README.md
@@ -0,0 +1,35 @@
+# state.mjs API
+All constants and interfaces documented here are guaranteed to work, and very likely not subject to further changes.
+
+## Constants
+### MIDI modes
+Octavia is compatible with a range of modes on MIDI synthesizers. A list of supported modes to their respective keys is available below.
+
+* `?`: The default "nothing" mode. Octavia will try to detect the correct mode.
+* `gm`: General MIDI mode.
+* `gs`: Roland GS mode.
+* `xg`: Yamaha XG mode. Compatible with TG-100 and TG-300.
+* `g2`: General MIDI Level 2 mode.
+* `mt32`: Roland MT-32 mode.
+* `ns5r`: KORG NS5R mode. Compatible with NX5R, and has limited compatibility with KORG N1R and N5.
+* `x5d`: KORG X5D(R) mode. Compatible with AG-10.
+* `05rw`: KORG 05R/W and KORG X5 mode. Compatible with AG-10.
+* `krs`: KORG KROSS 2 mode.
+* `k11`: Kawai GMega and Kawai K11 mode.
+* `sg`: Akai SG mode.
+
+### MIDI event types
+* `8`: Note off
+* `9`: Note on
+* `10`: Note aftertouch, a.k.a. polyphonic aftertouch
+* `11`: Channel controller change
+* `12`: Channel program change
+* `13`: Channel aftertouch
+* `14`: Channel pitch bend
+* `15`: System exclusive message
+
+### `allocated`
+### `ccToPos`
+
+## Interfaces
+### `OctaviaDevice`
diff --git a/docs/support/compress.md b/docs/support/compress.md
new file mode 100644
index 00000000..6fed7198
--- /dev/null
+++ b/docs/support/compress.md
@@ -0,0 +1,20 @@
+# Compression results
+## Compression result comparison
+_Disclaimer: Data updated on 10th Feb 2023. Might be outdated._
+| Algo | Quality | Size | Name |
+| ------ | ------- | ------- | ---- |
+| (raw) | (raw) | 51.5KiB | `state.mjs` |
+| gzip | 9 | 16.6KiB | `state.mjs` |
+| bzip2 | 9 | 15.8KiB | `state.mjs` |
+| zstd | 9 | 16.4KiB | `state.mjs` |
+| brotli | 11 | 14.3KiB | `state.mjs` |
+| (raw) | (raw) | 15.1KiB | `basic.mjs` |
+| gzip | 9 | 6.25KiB | `basic.mjs` |
+| bzip2 | 9 | 6.29KiB | `basic.mjs` |
+| zstd | 9 | 6.26KiB | `basic.mjs` |
+| brotli | 11 | 5.44KiB | `basic.mjs` |
+| (raw) | (raw) | 24.5KiB | `state_skim.mjs` |
+| gzip | 9 | 9.35KiB | `state_skim.mjs` |
+| bzip2 | 9 | 9.04KiB | `state_skim.mjs` |
+| zstd | 9 | 9.27KiB | `state_skim.mjs` |
+| brotli | 11 | 8.13KiB | `state_skim.mjs` |
diff --git a/docs/support/implementation.md b/docs/support/implementation.md
new file mode 100644
index 00000000..fb81f89b
--- /dev/null
+++ b/docs/support/implementation.md
@@ -0,0 +1,487 @@
+# Implementation Table
+## MIDI Implementation Chart
+
+
+
+ Function
+ Recognized
+ Remarks
+
+
+
+
+ Basic Channel
+ Default
+ ✓ 1-16
+
+
+
+ Changed
+ ✓ 1-16
+ Supports up to 128 channels.
+
+
+ Note number
+ 0-127
+
+
+
+ Mode
+ Default
+ 3
+
+
+
+ Messages
+ ✓ 3, 4
+
+
+
+ Velocity
+ Note on
+ ✓ 9nV=1-127
+
+
+
+ Note off
+ ✓ 9nV=0 8n
+
+
+
+ Aftertouch
+ Key
+ ✓
+
+
+
+ Channel
+ ✓
+
+
+
+ Pitchbend
+ ✓
+ 0-24 semitone steps 14-bit resolution
+
+
+ Control Change
+ 0
+ ✓
+ MSB Bank Select
+
+
+ 1
+ ✓
+ Modulation
+
+
+ 2
+ ✓
+ Breath
+
+
+ 4
+ ✓
+ Foot
+
+
+ 5
+ ✓
+ Portamento Time
+
+
+ 6
+ ✓
+ MSB (N)RPN Data Commit
+
+
+ 7
+ ✓
+ Volume
+
+
+ 8
+ ✓
+ Balance
+
+
+ 10
+ ✓
+ Pan
+
+
+ 11
+ ✓
+ Expression
+
+
+ 12
+ ✓
+ General-purpose effect
+
+
+ 13
+ ✓
+ General-purpose effect
+
+
+ 16
+ ✓
+ General-purpose sound
+
+
+ 17
+ ✓
+ General-purpose sound
+
+
+ 18
+ ✓
+ General-purpose sound
+
+
+ 19
+ ✓
+ General-purpose sound
+
+
+ 32
+ ✓
+ LSB Bank Select
+
+
+ 38
+ ✓
+ LSB (N)RPN Data Commit
+
+
+ 64
+ ✓
+ Sustain (Hold)
+
+
+ 65
+ ✓
+ Portamento
+
+
+ 66
+ ✓
+ Sostenuto
+
+
+ 67
+ ✓
+ Soft PedalStore only
+
+
+ 68
+ ✓
+ LegatoStore only
+
+
+ 69
+ ✓
+ Hold 2Store only
+
+
+ 70
+ ✓
+ Timbre VariationStore only
+
+
+ 71
+ ✓
+ Resonance
+
+
+ 72
+ ✓
+ Release Time
+
+
+ 73
+ ✓
+ Attack Time
+
+
+ 74
+ ✓
+ Brightness
+
+
+ 75
+ ✓
+ Decay Time
+
+
+ 76
+ ✓
+ Vibrato Rate
+
+
+ 77
+ ✓
+ Vibrato Depth
+
+
+ 78
+ ✓
+ Vibrato Delay
+
+
+ 84
+ ✓
+ Portamento Control
+
+
+ 91
+ ✓
+ Reverb
+
+
+ 92
+ ✓
+ Tremelo
+
+
+ 93
+ ✓
+ Chorus
+
+
+ 94
+ ✓
+ Variation
+
+
+ 95
+ ✓
+ Phaser
+
+
+ 96
+ ✓
+ Data Increment
+
+
+ 97
+ ✓
+ Data Decrement
+
+
+ 98
+ ✓
+ LSB NRPN
+
+
+ 99
+ ✓
+ MSB NRPN
+
+
+ 100
+ ✓
+ LSB RPN
+
+
+ 101
+ ✓
+ MSB RPN
+
+
+ 120
+ ✕
+ All Sound Off
+
+
+ 121
+ ✓
+ All Controllers Reset
+
+
+ 123
+ ✓
+ All Notes Off
+
+
+ 124
+ ✕
+ Omni OffSame as cc123
+
+
+ 125
+ ✕
+ Omni OnSame as cc123
+
+
+ 126
+ ✓
+ Mono
+
+
+ 127
+ ✓
+ Poly
+
+
+ Program Change
+ 0-127
+
+
+
+ System Exclusive
+ General MIDI
+ ✓
+
+
+
+ General MIDI rev. 2
+ ✓
+
+
+
+ YAMAHA XG
+ ✓
+
+
+
+ YAMAHA PLG-150AP
+ ✕
+
+
+
+ YAMAHA PLG-150AN
+ ✕
+
+
+
+ YAMAHA PLG-150DR/PC
+ ✕
+
+
+
+ YAMAHA PLG-150DX
+ ✕
+
+
+
+ YAMAHA PLG-150PF
+ ✕
+
+
+
+ YAMAHA PLG-150VL
+ ✕
+
+
+
+ YAMAHA TG
+ ✕
+
+
+
+ YAMAHA PLG-100SG
+ ✓
+
+
+
+ Roland GS
+ ✓
+
+
+
+ Roland C/M
+ ✓
+
+
+
+ KORG NS5R
+ ✓
+
+
+
+ KORG N1R
+ ✓
+ Redirected to NS5R
+
+
+ KORG X5D(R)
+ ✓
+
+
+
+ KORG 05R/W
+ ✕
+
+
+
+ KAWAI GMega
+ ✓
+ Also known as KAWAI K11
+
+
+ AKAI SG01
+ ✓
+
+
+
+ CASIO GZ-50M
+ ✓
+
+
+
+ ALESIS NanoSynth
+ ✕
+
+
+
+ System Common
+ Song position
+ ✕
+
+
+
+ Song select
+ ✕
+
+
+
+ Tune
+ ✕
+
+
+
+ System RealTime
+ Clock
+ ✕
+ No action defined
+
+
+ Start
+ ✕
+ No action defined
+
+
+ Continue
+ ✕
+ No action defined
+
+
+ Stop
+ ✕
+ No action defined
+
+
+ Aux messages
+ Local ON/OFF
+ ✕
+
+
+
+ Active Sense
+ ✕
+ No action defined
+
+
+
diff --git a/docs/support/sysex.md b/docs/support/sysex.md
new file mode 100644
index 00000000..d15d2b9e
--- /dev/null
+++ b/docs/support/sysex.md
@@ -0,0 +1,73 @@
+# SysEx Instructions
+## Supported SysEx Instructions
+* ✓: Supported
+* -: Partially supported
+* ✕: Not supported
+* ?: Unknown
+* (blank): N/A
+
+### Mutual instructions
+| | GM | GM2 | MT-32 | XG | GS | 05R/W | X5D | NS5R | GMega | GMega LX | SG-01 | GZ-50M |
+| --------------- | -- | --- | ----- | -- | -- | ----- | --- | ---- | ----- | -------- | ----- | ------ |
+| System reset | ✓ | ✓ | ✓ | ✓ | ✓ | | | | ✓ | ✓ | ✓ | |
+| Master setup | ✓ | ✓ | ✓ | ✓ | ✓ | | | ✓ | ✓ | ✓ | | |
+| Reverb setup | | ✕ | | ✓ | ✓ | | | | ✓ | ✓ | ✓ | ✓ |
+| Chorus setup | | ✕ | | ✓ | ✓ | | | | ✓ | ✓ | ✓ | ✓ |
+| Variation setup | | ? | | ✓ | ✓ | | | | | | | |
+| Part setup | | ? | | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | |
+| Equalizer | | | | ✓ | ✓ | | | | | | | |
+| EFX / insertion | | | | - | ✓³ | | | - | | | | |
+| Bitmap display¹ | | | | ✓ | ✓ | | | ✓ | | | | |
+| Text display² | | | ✓ | ✓ | ✓ | | | ✓ | | | | |
+| Drum setup | | ? | ✕ | ✕ | ✕ | ✕ | ✕ | ✕ | ✕ | ✕ | | |
+
+1. Support in GS is called "frame draw", and with multi-page support.
+2. Called "letter display" in XG, and "text insert" in GS.
+3. GS only has "delay" effect occupying the space of variation setup.
+
+### Device-specific instructions
+#### Roland MT-32
+* Temporary Patch Setup
+* ~~Temporary Drum Setup~~
+* Temporary Timbre Setup
+* Device Patch Setup
+* Device Timbre Setup
+* Patch Memory Write
+* Timbre Memory Write
+* System
+
+#### Yamaha MU1000
+* ~~A/D Part Setup~~
+* ~~A/D Mono/Stereo~~
+* System
+
+#### Yamaha PLG-100SG
+* ~~Master Setup~~
+* ~~Part Setup~~
+* PhoneSEQ Setup
+* ~~Lyrics Information Setup~~
+
+#### Yamaha PLG-150DX
+* ~~Master Setup~~
+* ~~Part Setup~~
+* ~~DX Voice Param~~
+* ~~DX Voice Additional Param~~
+
+#### Yamaha PLG-150VL
+* ~~Master Setup~~
+* ~~Current Voice Parameters~~
+* Part Setup
+
+#### Roland SC-88
+* Single/dual Mode
+
+#### KORG X5D
+* All Program Dump
+* All Combi Dump
+* Extended Multi Dump
+
+#### KORG NS5R
+* Mode Switch
+* All Program Dump
+* All Combi Dump
+* Extended Multi Dump
diff --git a/docs/support/target.md b/docs/support/target.md
new file mode 100644
index 00000000..1bd46b6b
--- /dev/null
+++ b/docs/support/target.md
@@ -0,0 +1,103 @@
+# Targets
+## Supported targets
+### General support table
+The following list of targets have their support by Octavia status presented in a table. A target can be a **m**odel, a **p**lugin board, a **l**ineup, or a **s**tandard.
+
+A supported standard may also have a list of specific target models listed.
+
+For specific SysEx support range, refer to [Supported SysEx Instructions](./sysex.md);
+
+| Vendor | Target | Type | Bank | SysEx |
+| ------ | --------- | ---- | ---- | ----- |
+| MMA | GM | S | ✓ | ✓ |
+| MMA | GM2 | S | ✓ | ✓ |
+| Roland | MT-32 | S | ✓ | ✓ |
+| Roland | GS | S | ✓ | ✓ |
+| YAMAHA | TG | L | ✓ | ✓ |
+| YAMAHA | XG¹ | S | ✓ | ✓ |
+| YAMAHA | PLG-150AN | P | ✓ | ✕ |
+| YAMAHA | PLG-150AP | P | ✓ | ✕ |
+| YAMAHA | PLG-150DR | P | ✓ | ✓ |
+| YAMAHA | PLG-150DX | P | ✓ | ✕ |
+| YAMAHA | PLG-150PC | P | ✓ | ✕ |
+| YAMAHA | PLG-150PF | P | ✓ | ✕ |
+| YAMAHA | PLG-150VL | P | ✓ | ✓ |
+| YAMAHA | PLG-100SG | P | ✓ | ✓ |
+| KORG | AG-10 | M | ✓ | ✓ |
+| KORG | 05R/W | L | ✓ | ✕ |
+| KORG | X5DR | L | ✓ | ✓ |
+| KORG | NS5R/NX5R | L | ✓ | ✓ |
+| KAWAI | GMega | L | ✓ | ✓ |
+| KAWAI | GMega LX | M | ✓ | ✓ |
+| AKAI | SG01k | M | ✓ | ✓ |
+| CASIO | GZ-50M | M | ✓ | ✓ |
+| ALESIS | NanoSynth | M | ✕ | ✕ |
+
+1. Octavia implements XG level 3.0 or later, and XG version 2.0 or later.
+
+### Specific targets
+#### Roland MT-32
+| Target | Type | Status |
+| ------- | ---- | ------ |
+| MT-32 | M | ✓ |
+| MT-100 | M | - |
+| CM-32L | M | ✓ |
+| CM-32LN | M | - |
+| CM-64 | M | - |
+| CM-500 | M | - |
+| LAPC-I | M | - |
+| LAPC-N | M | - |
+| RA-50 | M | - |
+| E-20 | M | - |
+
+#### Roland GS
+| Target | Type | Status |
+| --------- | ---- | ------ |
+| CM-300 | M | ✓ |
+| SC-55 | L | ✓ |
+| SC-88 | L | ✓ |
+| SC-88 Pro | L | ✓ |
+| SC-8850 | L | ✓ |
+| SD-20 | M | - |
+| SD-35 | M | - |
+| SD-50 | M | - |
+| SD-80 | M | - |
+| SD-90 | M | - |
+| SK-50 | L | - |
+
+#### Yamaha TG
+| Target | Type | Status |
+| ------ | ---- | ------ |
+| TG55 | M | - |
+| TG33 | M | - |
+| TG77 | M | - |
+| TG100 | M | - |
+| TG500 | M | - |
+| TG300 | M | ✓ |
+
+#### Yamaha XG
+| Target | Type | Status |
+| ----------- | ---- | ------ |
+| DBXG50 | M | ✓ |
+| DBXG51 | M | ✓ |
+| DBXG60 | M | - |
+| MU5 | M | ✓ |
+| MU80 | M | ✓ |
+| MU50 | M | ✓ |
+| MU90 | L | ✓ |
+| MU10 | M | ✓ |
+| MU100 | L | ✓ |
+| MU15 | M | ✓ |
+| MU128 | L | ✓ |
+| MU1000 | L | ✓ |
+| MU2000 | L | ✓ |
+| MU500 | M | ✓ |
+| QY700 | M | ✓ |
+| QY70 | M | ✓ |
+| QY100 | M | ✓ |
+| SW60XG | M | - |
+| SW1000XG | M | - |
+| S-YXG50 | M | ✓ |
+| S-YXG70 | M | ✓ |
+| S-YXG100 | M | ✓ |
+| S-YXG2006LE | M | ✓ |
diff --git a/docs/worker.js b/docs/worker.js
new file mode 100644
index 00000000..97c77f48
--- /dev/null
+++ b/docs/worker.js
@@ -0,0 +1,131 @@
+"use strict";(()=>{var Z=Object.create;var N=Object.defineProperty;var Q=Object.getOwnPropertyDescriptor;var X=Object.getOwnPropertyNames;var J=Object.getPrototypeOf,Y=Object.prototype.hasOwnProperty;var ee=(v,t)=>()=>(t||v((t={exports:{}}).exports,t),t.exports);var re=(v,t,y,x)=>{if(t&&typeof t=="object"||typeof t=="function")for(let P of X(t))!Y.call(v,P)&&P!==y&&N(v,P,{get:()=>t[P],enumerable:!(x=Q(t,P))||x.enumerable});return v};var ae=(v,t,y)=>(y=v!=null?Z(J(v)):{},re(t||!v||!v.__esModule?N(y,"default",{value:v,enumerable:!0}):y,v));var V=ee((R,H)=>{(function(){function v(e){"use strict";var a={omitExtraWLInCodeBlocks:{defaultValue:!1,describe:"Omit the default extra whiteline added to code blocks",type:"boolean"},noHeaderId:{defaultValue:!1,describe:"Turn on/off generated header id",type:"boolean"},prefixHeaderId:{defaultValue:!1,describe:"Add a prefix to the generated header ids. Passing a string will prefix that string to the header id. Setting to true will add a generic 'section-' prefix",type:"string"},rawPrefixHeaderId:{defaultValue:!1,describe:'Setting this option to true will prevent showdown from modifying the prefix. This might result in malformed IDs (if, for instance, the " char is used in the prefix)',type:"boolean"},ghCompatibleHeaderId:{defaultValue:!1,describe:"Generate header ids compatible with github style (spaces are replaced with dashes, a bunch of non alphanumeric chars are removed)",type:"boolean"},rawHeaderId:{defaultValue:!1,describe:`Remove only spaces, ' and " from generated header ids (including prefixes), replacing them with dashes (-). WARNING: This might result in malformed ids`,type:"boolean"},headerLevelStart:{defaultValue:!1,describe:"The header blocks level start",type:"integer"},parseImgDimensions:{defaultValue:!1,describe:"Turn on/off image dimension parsing",type:"boolean"},simplifiedAutoLink:{defaultValue:!1,describe:"Turn on/off GFM autolink style",type:"boolean"},excludeTrailingPunctuationFromURLs:{defaultValue:!1,describe:"Excludes trailing punctuation from links generated with autoLinking",type:"boolean"},literalMidWordUnderscores:{defaultValue:!1,describe:"Parse midword underscores as literal underscores",type:"boolean"},literalMidWordAsterisks:{defaultValue:!1,describe:"Parse midword asterisks as literal asterisks",type:"boolean"},strikethrough:{defaultValue:!1,describe:"Turn on/off strikethrough support",type:"boolean"},tables:{defaultValue:!1,describe:"Turn on/off tables support",type:"boolean"},tablesHeaderId:{defaultValue:!1,describe:"Add an id to table headers",type:"boolean"},ghCodeBlocks:{defaultValue:!0,describe:"Turn on/off GFM fenced code blocks support",type:"boolean"},tasklists:{defaultValue:!1,describe:"Turn on/off GFM tasklist support",type:"boolean"},smoothLivePreview:{defaultValue:!1,describe:"Prevents weird effects in live previews due to incomplete input",type:"boolean"},smartIndentationFix:{defaultValue:!1,describe:"Tries to smartly fix indentation in es6 strings",type:"boolean"},disableForced4SpacesIndentedSublists:{defaultValue:!1,describe:"Disables the requirement of indenting nested sublists by 4 spaces",type:"boolean"},simpleLineBreaks:{defaultValue:!1,describe:"Parses simple line breaks as (GFM Style)",type:"boolean"},requireSpaceBeforeHeadingText:{defaultValue:!1,describe:"Makes adding a space between `#` and the header text mandatory (GFM Style)",type:"boolean"},ghMentions:{defaultValue:!1,describe:"Enables github @mentions",type:"boolean"},ghMentionsLink:{defaultValue:"https://github.com/{u}",describe:"Changes the link generated by @mentions. Only applies if ghMentions option is enabled.",type:"string"},encodeEmails:{defaultValue:!0,describe:"Encode e-mail addresses through the use of Character Entities, transforming ASCII e-mail addresses into its equivalent decimal entities",type:"boolean"},openLinksInNewWindow:{defaultValue:!1,describe:"Open all links in new windows",type:"boolean"},backslashEscapesHTMLTags:{defaultValue:!1,describe:"Support for HTML Tag escaping. ex: foo
",type:"boolean"},emoji:{defaultValue:!1,describe:"Enable emoji support. Ex: `this is a :smile: emoji`",type:"boolean"},underline:{defaultValue:!1,describe:"Enable support for underline. Syntax is double or triple underscores: `__underline word__`. With this option enabled, underscores no longer parses into `` and ``",type:"boolean"},ellipsis:{defaultValue:!0,describe:"Replaces three dots with the ellipsis unicode character",type:"boolean"},completeHTMLDocument:{defaultValue:!1,describe:"Outputs a complete html document, including ``, `` and `` tags",type:"boolean"},metadata:{defaultValue:!1,describe:"Enable support for document metadata (defined at the top of the document between `«««` and `»»»` or between `---` and `---`).",type:"boolean"},splitAdjacentBlockquotes:{defaultValue:!1,describe:"Split adjacent blockquote blocks",type:"boolean"}};if(e===!1)return JSON.parse(JSON.stringify(a));var r,n={};for(r in a)a.hasOwnProperty(r)&&(n[r]=a[r].defaultValue);return n}var t={},y={},x={},P=v(!0),B="vanilla",A={github:{omitExtraWLInCodeBlocks:!0,simplifiedAutoLink:!0,excludeTrailingPunctuationFromURLs:!0,literalMidWordUnderscores:!0,strikethrough:!0,tables:!0,tablesHeaderId:!0,ghCodeBlocks:!0,tasklists:!0,disableForced4SpacesIndentedSublists:!0,simpleLineBreaks:!0,requireSpaceBeforeHeadingText:!0,ghCompatibleHeaderId:!0,ghMentions:!0,backslashEscapesHTMLTags:!0,emoji:!0,splitAdjacentBlockquotes:!0},original:{noHeaderId:!0,ghCodeBlocks:!1},ghost:{omitExtraWLInCodeBlocks:!0,parseImgDimensions:!0,simplifiedAutoLink:!0,excludeTrailingPunctuationFromURLs:!0,literalMidWordUnderscores:!0,strikethrough:!0,tables:!0,tablesHeaderId:!0,ghCodeBlocks:!0,tasklists:!0,smoothLivePreview:!0,simpleLineBreaks:!0,requireSpaceBeforeHeadingText:!0,ghMentions:!1,encodeEmails:!0},vanilla:v(!0),allOn:function(){"use strict";var e,a=v(!0),r={};for(e in a)a.hasOwnProperty(e)&&(r[e]=!0);return r}()};function T(e,a){"use strict";var r=a?"Error in "+a+" extension->":"Error in unnamed extension",n={valid:!0,error:""};t.helper.isArray(e)||(e=[e]);for(var o=0;o").replace(/&/g,"&")};function q(e,a,r,n){"use strict";var o,l,s,c=-1<(n=n||"").indexOf("g"),u=new RegExp(a+"|"+r,"g"+n.replace(/g/g,"")),h=new RegExp(a,n.replace(/g/g,"")),p=[];do for(o=0;d=u.exec(e);)if(h.test(d[0]))o++||(s=(l=u.lastIndex)-d[0].length);else if(o&&!--o){var i=d.index+d[0].length,d={left:{start:s,end:l},match:{start:l,end:d.index},right:{start:d.index,end:i},wholeMatch:{start:s,end:i}};if(p.push(d),!c)return p}while(o&&(u.lastIndex=l));return p}function I(e){"use strict";return function(a,i,n,o,l,s,d){var u=n=n.replace(t.helper.regexes.asteriskDashAndColon,t.helper.escapeCharactersCallback),h="",p="",i=i||"",d=d||"";return/^www\./i.test(n)&&(n=n.replace(/^www\./i,"http://www.")),e.excludeTrailingPunctuationFromURLs&&s&&(h=s),i+'"+u+" "+h+d}}function O(e,a){"use strict";return function(r,n,o){var l="mailto:";return n=n||"",o=t.subParser("unescapeSpecialChars")(o,e,a),e.encodeEmails?(l=t.helper.encodeEmailAddress(l+o),o=t.helper.encodeEmailAddress(o)):l+=o,n+''+o+" "}}t.helper.matchRecursiveRegExp=function(e,a,r,n){"use strict";for(var o=q(e,a,r,n),l=[],s=0;s>=0,r=String(r||" "),e.length>a?String(e):((a-=e.length)>r.length&&(r+=r.repeat(a/r.length)),String(e)+r.slice(0,a))},typeof console>"u"&&(console={warn:function(e){"use strict";alert(e)},log:function(e){"use strict";alert(e)},error:function(e){"use strict";throw e}}),t.helper.regexes={asteriskDashAndColon:/([*_:~])/g},t.helper.emojis={"+1":"👍","-1":"👎",100:"💯",1234:"🔢","1st_place_medal":"🥇","2nd_place_medal":"🥈","3rd_place_medal":"🥉","8ball":"🎱",a:"🅰️",ab:"🆎",abc:"🔤",abcd:"🔡",accept:"🉑",aerial_tramway:"🚡",airplane:"✈️",alarm_clock:"⏰",alembic:"⚗️",alien:"👽",ambulance:"🚑",amphora:"🏺",anchor:"⚓️",angel:"👼",anger:"💢",angry:"😠",anguished:"😧",ant:"🐜",apple:"🍎",aquarius:"♒️",aries:"♈️",arrow_backward:"◀️",arrow_double_down:"⏬",arrow_double_up:"⏫",arrow_down:"⬇️",arrow_down_small:"🔽",arrow_forward:"▶️",arrow_heading_down:"⤵️",arrow_heading_up:"⤴️",arrow_left:"⬅️",arrow_lower_left:"↙️",arrow_lower_right:"↘️",arrow_right:"➡️",arrow_right_hook:"↪️",arrow_up:"⬆️",arrow_up_down:"↕️",arrow_up_small:"🔼",arrow_upper_left:"↖️",arrow_upper_right:"↗️",arrows_clockwise:"🔃",arrows_counterclockwise:"🔄",art:"🎨",articulated_lorry:"🚛",artificial_satellite:"🛰",astonished:"😲",athletic_shoe:"👟",atm:"🏧",atom_symbol:"⚛️",avocado:"🥑",b:"🅱️",baby:"👶",baby_bottle:"🍼",baby_chick:"🐤",baby_symbol:"🚼",back:"🔙",bacon:"🥓",badminton:"🏸",baggage_claim:"🛄",baguette_bread:"🥖",balance_scale:"⚖️",balloon:"🎈",ballot_box:"🗳",ballot_box_with_check:"☑️",bamboo:"🎍",banana:"🍌",bangbang:"‼️",bank:"🏦",bar_chart:"📊",barber:"💈",baseball:"⚾️",basketball:"🏀",basketball_man:"⛹️",basketball_woman:"⛹️♀️",bat:"🦇",bath:"🛀",bathtub:"🛁",battery:"🔋",beach_umbrella:"🏖",bear:"🐻",bed:"🛏",bee:"🐝",beer:"🍺",beers:"🍻",beetle:"🐞",beginner:"🔰",bell:"🔔",bellhop_bell:"🛎",bento:"🍱",biking_man:"🚴",bike:"🚲",biking_woman:"🚴♀️",bikini:"👙",biohazard:"☣️",bird:"🐦",birthday:"🎂",black_circle:"⚫️",black_flag:"🏴",black_heart:"🖤",black_joker:"🃏",black_large_square:"⬛️",black_medium_small_square:"◾️",black_medium_square:"◼️",black_nib:"✒️",black_small_square:"▪️",black_square_button:"🔲",blonde_man:"👱",blonde_woman:"👱♀️",blossom:"🌼",blowfish:"🐡",blue_book:"📘",blue_car:"🚙",blue_heart:"💙",blush:"😊",boar:"🐗",boat:"⛵️",bomb:"💣",book:"📖",bookmark:"🔖",bookmark_tabs:"📑",books:"📚",boom:"💥",boot:"👢",bouquet:"💐",bowing_man:"🙇",bow_and_arrow:"🏹",bowing_woman:"🙇♀️",bowling:"🎳",boxing_glove:"🥊",boy:"👦",bread:"🍞",bride_with_veil:"👰",bridge_at_night:"🌉",briefcase:"💼",broken_heart:"💔",bug:"🐛",building_construction:"🏗",bulb:"💡",bullettrain_front:"🚅",bullettrain_side:"🚄",burrito:"🌯",bus:"🚌",business_suit_levitating:"🕴",busstop:"🚏",bust_in_silhouette:"👤",busts_in_silhouette:"👥",butterfly:"🦋",cactus:"🌵",cake:"🍰",calendar:"📆",call_me_hand:"🤙",calling:"📲",camel:"🐫",camera:"📷",camera_flash:"📸",camping:"🏕",cancer:"♋️",candle:"🕯",candy:"🍬",canoe:"🛶",capital_abcd:"🔠",capricorn:"♑️",car:"🚗",card_file_box:"🗃",card_index:"📇",card_index_dividers:"🗂",carousel_horse:"🎠",carrot:"🥕",cat:"🐱",cat2:"🐈",cd:"💿",chains:"⛓",champagne:"🍾",chart:"💹",chart_with_downwards_trend:"📉",chart_with_upwards_trend:"📈",checkered_flag:"🏁",cheese:"🧀",cherries:"🍒",cherry_blossom:"🌸",chestnut:"🌰",chicken:"🐔",children_crossing:"🚸",chipmunk:"🐿",chocolate_bar:"🍫",christmas_tree:"🎄",church:"⛪️",cinema:"🎦",circus_tent:"🎪",city_sunrise:"🌇",city_sunset:"🌆",cityscape:"🏙",cl:"🆑",clamp:"🗜",clap:"👏",clapper:"🎬",classical_building:"🏛",clinking_glasses:"🥂",clipboard:"📋",clock1:"🕐",clock10:"🕙",clock1030:"🕥",clock11:"🕚",clock1130:"🕦",clock12:"🕛",clock1230:"🕧",clock130:"🕜",clock2:"🕑",clock230:"🕝",clock3:"🕒",clock330:"🕞",clock4:"🕓",clock430:"🕟",clock5:"🕔",clock530:"🕠",clock6:"🕕",clock630:"🕡",clock7:"🕖",clock730:"🕢",clock8:"🕗",clock830:"🕣",clock9:"🕘",clock930:"🕤",closed_book:"📕",closed_lock_with_key:"🔐",closed_umbrella:"🌂",cloud:"☁️",cloud_with_lightning:"🌩",cloud_with_lightning_and_rain:"⛈",cloud_with_rain:"🌧",cloud_with_snow:"🌨",clown_face:"🤡",clubs:"♣️",cocktail:"🍸",coffee:"☕️",coffin:"⚰️",cold_sweat:"😰",comet:"☄️",computer:"💻",computer_mouse:"🖱",confetti_ball:"🎊",confounded:"😖",confused:"😕",congratulations:"㊗️",construction:"🚧",construction_worker_man:"👷",construction_worker_woman:"👷♀️",control_knobs:"🎛",convenience_store:"🏪",cookie:"🍪",cool:"🆒",policeman:"👮",copyright:"©️",corn:"🌽",couch_and_lamp:"🛋",couple:"👫",couple_with_heart_woman_man:"💑",couple_with_heart_man_man:"👨❤️👨",couple_with_heart_woman_woman:"👩❤️👩",couplekiss_man_man:"👨❤️💋👨",couplekiss_man_woman:"💏",couplekiss_woman_woman:"👩❤️💋👩",cow:"🐮",cow2:"🐄",cowboy_hat_face:"🤠",crab:"🦀",crayon:"🖍",credit_card:"💳",crescent_moon:"🌙",cricket:"🏏",crocodile:"🐊",croissant:"🥐",crossed_fingers:"🤞",crossed_flags:"🎌",crossed_swords:"⚔️",crown:"👑",cry:"😢",crying_cat_face:"😿",crystal_ball:"🔮",cucumber:"🥒",cupid:"💘",curly_loop:"➰",currency_exchange:"💱",curry:"🍛",custard:"🍮",customs:"🛃",cyclone:"🌀",dagger:"🗡",dancer:"💃",dancing_women:"👯",dancing_men:"👯♂️",dango:"🍡",dark_sunglasses:"🕶",dart:"🎯",dash:"💨",date:"📅",deciduous_tree:"🌳",deer:"🦌",department_store:"🏬",derelict_house:"🏚",desert:"🏜",desert_island:"🏝",desktop_computer:"🖥",male_detective:"🕵️",diamond_shape_with_a_dot_inside:"💠",diamonds:"♦️",disappointed:"😞",disappointed_relieved:"😥",dizzy:"💫",dizzy_face:"😵",do_not_litter:"🚯",dog:"🐶",dog2:"🐕",dollar:"💵",dolls:"🎎",dolphin:"🐬",door:"🚪",doughnut:"🍩",dove:"🕊",dragon:"🐉",dragon_face:"🐲",dress:"👗",dromedary_camel:"🐪",drooling_face:"🤤",droplet:"💧",drum:"🥁",duck:"🦆",dvd:"📀","e-mail":"📧",eagle:"🦅",ear:"👂",ear_of_rice:"🌾",earth_africa:"🌍",earth_americas:"🌎",earth_asia:"🌏",egg:"🥚",eggplant:"🍆",eight_pointed_black_star:"✴️",eight_spoked_asterisk:"✳️",electric_plug:"🔌",elephant:"🐘",email:"✉️",end:"🔚",envelope_with_arrow:"📩",euro:"💶",european_castle:"🏰",european_post_office:"🏤",evergreen_tree:"🌲",exclamation:"❗️",expressionless:"😑",eye:"👁",eye_speech_bubble:"👁🗨",eyeglasses:"👓",eyes:"👀",face_with_head_bandage:"🤕",face_with_thermometer:"🤒",fist_oncoming:"👊",factory:"🏭",fallen_leaf:"🍂",family_man_woman_boy:"👪",family_man_boy:"👨👦",family_man_boy_boy:"👨👦👦",family_man_girl:"👨👧",family_man_girl_boy:"👨👧👦",family_man_girl_girl:"👨👧👧",family_man_man_boy:"👨👨👦",family_man_man_boy_boy:"👨👨👦👦",family_man_man_girl:"👨👨👧",family_man_man_girl_boy:"👨👨👧👦",family_man_man_girl_girl:"👨👨👧👧",family_man_woman_boy_boy:"👨👩👦👦",family_man_woman_girl:"👨👩👧",family_man_woman_girl_boy:"👨👩👧👦",family_man_woman_girl_girl:"👨👩👧👧",family_woman_boy:"👩👦",family_woman_boy_boy:"👩👦👦",family_woman_girl:"👩👧",family_woman_girl_boy:"👩👧👦",family_woman_girl_girl:"👩👧👧",family_woman_woman_boy:"👩👩👦",family_woman_woman_boy_boy:"👩👩👦👦",family_woman_woman_girl:"👩👩👧",family_woman_woman_girl_boy:"👩👩👧👦",family_woman_woman_girl_girl:"👩👩👧👧",fast_forward:"⏩",fax:"📠",fearful:"😨",feet:"🐾",female_detective:"🕵️♀️",ferris_wheel:"🎡",ferry:"⛴",field_hockey:"🏑",file_cabinet:"🗄",file_folder:"📁",film_projector:"📽",film_strip:"🎞",fire:"🔥",fire_engine:"🚒",fireworks:"🎆",first_quarter_moon:"🌓",first_quarter_moon_with_face:"🌛",fish:"🐟",fish_cake:"🍥",fishing_pole_and_fish:"🎣",fist_raised:"✊",fist_left:"🤛",fist_right:"🤜",flags:"🎏",flashlight:"🔦",fleur_de_lis:"⚜️",flight_arrival:"🛬",flight_departure:"🛫",floppy_disk:"💾",flower_playing_cards:"🎴",flushed:"😳",fog:"🌫",foggy:"🌁",football:"🏈",footprints:"👣",fork_and_knife:"🍴",fountain:"⛲️",fountain_pen:"🖋",four_leaf_clover:"🍀",fox_face:"🦊",framed_picture:"🖼",free:"🆓",fried_egg:"🍳",fried_shrimp:"🍤",fries:"🍟",frog:"🐸",frowning:"😦",frowning_face:"☹️",frowning_man:"🙍♂️",frowning_woman:"🙍",middle_finger:"🖕",fuelpump:"⛽️",full_moon:"🌕",full_moon_with_face:"🌝",funeral_urn:"⚱️",game_die:"🎲",gear:"⚙️",gem:"💎",gemini:"♊️",ghost:"👻",gift:"🎁",gift_heart:"💝",girl:"👧",globe_with_meridians:"🌐",goal_net:"🥅",goat:"🐐",golf:"⛳️",golfing_man:"🏌️",golfing_woman:"🏌️♀️",gorilla:"🦍",grapes:"🍇",green_apple:"🍏",green_book:"📗",green_heart:"💚",green_salad:"🥗",grey_exclamation:"❕",grey_question:"❔",grimacing:"😬",grin:"😁",grinning:"😀",guardsman:"💂",guardswoman:"💂♀️",guitar:"🎸",gun:"🔫",haircut_woman:"💇",haircut_man:"💇♂️",hamburger:"🍔",hammer:"🔨",hammer_and_pick:"⚒",hammer_and_wrench:"🛠",hamster:"🐹",hand:"✋",handbag:"👜",handshake:"🤝",hankey:"💩",hatched_chick:"🐥",hatching_chick:"🐣",headphones:"🎧",hear_no_evil:"🙉",heart:"❤️",heart_decoration:"💟",heart_eyes:"😍",heart_eyes_cat:"😻",heartbeat:"💓",heartpulse:"💗",hearts:"♥️",heavy_check_mark:"✔️",heavy_division_sign:"➗",heavy_dollar_sign:"💲",heavy_heart_exclamation:"❣️",heavy_minus_sign:"➖",heavy_multiplication_x:"✖️",heavy_plus_sign:"➕",helicopter:"🚁",herb:"🌿",hibiscus:"🌺",high_brightness:"🔆",high_heel:"👠",hocho:"🔪",hole:"🕳",honey_pot:"🍯",horse:"🐴",horse_racing:"🏇",hospital:"🏥",hot_pepper:"🌶",hotdog:"🌭",hotel:"🏨",hotsprings:"♨️",hourglass:"⌛️",hourglass_flowing_sand:"⏳",house:"🏠",house_with_garden:"🏡",houses:"🏘",hugs:"🤗",hushed:"😯",ice_cream:"🍨",ice_hockey:"🏒",ice_skate:"⛸",icecream:"🍦",id:"🆔",ideograph_advantage:"🉐",imp:"👿",inbox_tray:"📥",incoming_envelope:"📨",tipping_hand_woman:"💁",information_source:"ℹ️",innocent:"😇",interrobang:"⁉️",iphone:"📱",izakaya_lantern:"🏮",jack_o_lantern:"🎃",japan:"🗾",japanese_castle:"🏯",japanese_goblin:"👺",japanese_ogre:"👹",jeans:"👖",joy:"😂",joy_cat:"😹",joystick:"🕹",kaaba:"🕋",key:"🔑",keyboard:"⌨️",keycap_ten:"🔟",kick_scooter:"🛴",kimono:"👘",kiss:"💋",kissing:"😗",kissing_cat:"😽",kissing_closed_eyes:"😚",kissing_heart:"😘",kissing_smiling_eyes:"😙",kiwi_fruit:"🥝",koala:"🐨",koko:"🈁",label:"🏷",large_blue_circle:"🔵",large_blue_diamond:"🔷",large_orange_diamond:"🔶",last_quarter_moon:"🌗",last_quarter_moon_with_face:"🌜",latin_cross:"✝️",laughing:"😆",leaves:"🍃",ledger:"📒",left_luggage:"🛅",left_right_arrow:"↔️",leftwards_arrow_with_hook:"↩️",lemon:"🍋",leo:"♌️",leopard:"🐆",level_slider:"🎚",libra:"♎️",light_rail:"🚈",link:"🔗",lion:"🦁",lips:"👄",lipstick:"💄",lizard:"🦎",lock:"🔒",lock_with_ink_pen:"🔏",lollipop:"🍭",loop:"➿",loud_sound:"🔊",loudspeaker:"📢",love_hotel:"🏩",love_letter:"💌",low_brightness:"🔅",lying_face:"🤥",m:"Ⓜ️",mag:"🔍",mag_right:"🔎",mahjong:"🀄️",mailbox:"📫",mailbox_closed:"📪",mailbox_with_mail:"📬",mailbox_with_no_mail:"📭",man:"👨",man_artist:"👨🎨",man_astronaut:"👨🚀",man_cartwheeling:"🤸♂️",man_cook:"👨🍳",man_dancing:"🕺",man_facepalming:"🤦♂️",man_factory_worker:"👨🏭",man_farmer:"👨🌾",man_firefighter:"👨🚒",man_health_worker:"👨⚕️",man_in_tuxedo:"🤵",man_judge:"👨⚖️",man_juggling:"🤹♂️",man_mechanic:"👨🔧",man_office_worker:"👨💼",man_pilot:"👨✈️",man_playing_handball:"🤾♂️",man_playing_water_polo:"🤽♂️",man_scientist:"👨🔬",man_shrugging:"🤷♂️",man_singer:"👨🎤",man_student:"👨🎓",man_teacher:"👨🏫",man_technologist:"👨💻",man_with_gua_pi_mao:"👲",man_with_turban:"👳",tangerine:"🍊",mans_shoe:"👞",mantelpiece_clock:"🕰",maple_leaf:"🍁",martial_arts_uniform:"🥋",mask:"😷",massage_woman:"💆",massage_man:"💆♂️",meat_on_bone:"🍖",medal_military:"🎖",medal_sports:"🏅",mega:"📣",melon:"🍈",memo:"📝",men_wrestling:"🤼♂️",menorah:"🕎",mens:"🚹",metal:"🤘",metro:"🚇",microphone:"🎤",microscope:"🔬",milk_glass:"🥛",milky_way:"🌌",minibus:"🚐",minidisc:"💽",mobile_phone_off:"📴",money_mouth_face:"🤑",money_with_wings:"💸",moneybag:"💰",monkey:"🐒",monkey_face:"🐵",monorail:"🚝",moon:"🌔",mortar_board:"🎓",mosque:"🕌",motor_boat:"🛥",motor_scooter:"🛵",motorcycle:"🏍",motorway:"🛣",mount_fuji:"🗻",mountain:"⛰",mountain_biking_man:"🚵",mountain_biking_woman:"🚵♀️",mountain_cableway:"🚠",mountain_railway:"🚞",mountain_snow:"🏔",mouse:"🐭",mouse2:"🐁",movie_camera:"🎥",moyai:"🗿",mrs_claus:"🤶",muscle:"💪",mushroom:"🍄",musical_keyboard:"🎹",musical_note:"🎵",musical_score:"🎼",mute:"🔇",nail_care:"💅",name_badge:"📛",national_park:"🏞",nauseated_face:"🤢",necktie:"👔",negative_squared_cross_mark:"❎",nerd_face:"🤓",neutral_face:"😐",new:"🆕",new_moon:"🌑",new_moon_with_face:"🌚",newspaper:"📰",newspaper_roll:"🗞",next_track_button:"⏭",ng:"🆖",no_good_man:"🙅♂️",no_good_woman:"🙅",night_with_stars:"🌃",no_bell:"🔕",no_bicycles:"🚳",no_entry:"⛔️",no_entry_sign:"🚫",no_mobile_phones:"📵",no_mouth:"😶",no_pedestrians:"🚷",no_smoking:"🚭","non-potable_water":"🚱",nose:"👃",notebook:"📓",notebook_with_decorative_cover:"📔",notes:"🎶",nut_and_bolt:"🔩",o:"⭕️",o2:"🅾️",ocean:"🌊",octopus:"🐙",oden:"🍢",office:"🏢",oil_drum:"🛢",ok:"🆗",ok_hand:"👌",ok_man:"🙆♂️",ok_woman:"🙆",old_key:"🗝",older_man:"👴",older_woman:"👵",om:"🕉",on:"🔛",oncoming_automobile:"🚘",oncoming_bus:"🚍",oncoming_police_car:"🚔",oncoming_taxi:"🚖",open_file_folder:"📂",open_hands:"👐",open_mouth:"😮",open_umbrella:"☂️",ophiuchus:"⛎",orange_book:"📙",orthodox_cross:"☦️",outbox_tray:"📤",owl:"🦉",ox:"🐂",package:"📦",page_facing_up:"📄",page_with_curl:"📃",pager:"📟",paintbrush:"🖌",palm_tree:"🌴",pancakes:"🥞",panda_face:"🐼",paperclip:"📎",paperclips:"🖇",parasol_on_ground:"⛱",parking:"🅿️",part_alternation_mark:"〽️",partly_sunny:"⛅️",passenger_ship:"🛳",passport_control:"🛂",pause_button:"⏸",peace_symbol:"☮️",peach:"🍑",peanuts:"🥜",pear:"🍐",pen:"🖊",pencil2:"✏️",penguin:"🐧",pensive:"😔",performing_arts:"🎭",persevere:"😣",person_fencing:"🤺",pouting_woman:"🙎",phone:"☎️",pick:"⛏",pig:"🐷",pig2:"🐖",pig_nose:"🐽",pill:"💊",pineapple:"🍍",ping_pong:"🏓",pisces:"♓️",pizza:"🍕",place_of_worship:"🛐",plate_with_cutlery:"🍽",play_or_pause_button:"⏯",point_down:"👇",point_left:"👈",point_right:"👉",point_up:"☝️",point_up_2:"👆",police_car:"🚓",policewoman:"👮♀️",poodle:"🐩",popcorn:"🍿",post_office:"🏣",postal_horn:"📯",postbox:"📮",potable_water:"🚰",potato:"🥔",pouch:"👝",poultry_leg:"🍗",pound:"💷",rage:"😡",pouting_cat:"😾",pouting_man:"🙎♂️",pray:"🙏",prayer_beads:"📿",pregnant_woman:"🤰",previous_track_button:"⏮",prince:"🤴",princess:"👸",printer:"🖨",purple_heart:"💜",purse:"👛",pushpin:"📌",put_litter_in_its_place:"🚮",question:"❓",rabbit:"🐰",rabbit2:"🐇",racehorse:"🐎",racing_car:"🏎",radio:"📻",radio_button:"🔘",radioactive:"☢️",railway_car:"🚃",railway_track:"🛤",rainbow:"🌈",rainbow_flag:"🏳️🌈",raised_back_of_hand:"🤚",raised_hand_with_fingers_splayed:"🖐",raised_hands:"🙌",raising_hand_woman:"🙋",raising_hand_man:"🙋♂️",ram:"🐏",ramen:"🍜",rat:"🐀",record_button:"⏺",recycle:"♻️",red_circle:"🔴",registered:"®️",relaxed:"☺️",relieved:"😌",reminder_ribbon:"🎗",repeat:"🔁",repeat_one:"🔂",rescue_worker_helmet:"⛑",restroom:"🚻",revolving_hearts:"💞",rewind:"⏪",rhinoceros:"🦏",ribbon:"🎀",rice:"🍚",rice_ball:"🍙",rice_cracker:"🍘",rice_scene:"🎑",right_anger_bubble:"🗯",ring:"💍",robot:"🤖",rocket:"🚀",rofl:"🤣",roll_eyes:"🙄",roller_coaster:"🎢",rooster:"🐓",rose:"🌹",rosette:"🏵",rotating_light:"🚨",round_pushpin:"📍",rowing_man:"🚣",rowing_woman:"🚣♀️",rugby_football:"🏉",running_man:"🏃",running_shirt_with_sash:"🎽",running_woman:"🏃♀️",sa:"🈂️",sagittarius:"♐️",sake:"🍶",sandal:"👡",santa:"🎅",satellite:"📡",saxophone:"🎷",school:"🏫",school_satchel:"🎒",scissors:"✂️",scorpion:"🦂",scorpius:"♏️",scream:"😱",scream_cat:"🙀",scroll:"📜",seat:"💺",secret:"㊙️",see_no_evil:"🙈",seedling:"🌱",selfie:"🤳",shallow_pan_of_food:"🥘",shamrock:"☘️",shark:"🦈",shaved_ice:"🍧",sheep:"🐑",shell:"🐚",shield:"🛡",shinto_shrine:"⛩",ship:"🚢",shirt:"👕",shopping:"🛍",shopping_cart:"🛒",shower:"🚿",shrimp:"🦐",signal_strength:"📶",six_pointed_star:"🔯",ski:"🎿",skier:"⛷",skull:"💀",skull_and_crossbones:"☠️",sleeping:"😴",sleeping_bed:"🛌",sleepy:"😪",slightly_frowning_face:"🙁",slightly_smiling_face:"🙂",slot_machine:"🎰",small_airplane:"🛩",small_blue_diamond:"🔹",small_orange_diamond:"🔸",small_red_triangle:"🔺",small_red_triangle_down:"🔻",smile:"😄",smile_cat:"😸",smiley:"😃",smiley_cat:"😺",smiling_imp:"😈",smirk:"😏",smirk_cat:"😼",smoking:"🚬",snail:"🐌",snake:"🐍",sneezing_face:"🤧",snowboarder:"🏂",snowflake:"❄️",snowman:"⛄️",snowman_with_snow:"☃️",sob:"😭",soccer:"⚽️",soon:"🔜",sos:"🆘",sound:"🔉",space_invader:"👾",spades:"♠️",spaghetti:"🍝",sparkle:"❇️",sparkler:"🎇",sparkles:"✨",sparkling_heart:"💖",speak_no_evil:"🙊",speaker:"🔈",speaking_head:"🗣",speech_balloon:"💬",speedboat:"🚤",spider:"🕷",spider_web:"🕸",spiral_calendar:"🗓",spiral_notepad:"🗒",spoon:"🥄",squid:"🦑",stadium:"🏟",star:"⭐️",star2:"🌟",star_and_crescent:"☪️",star_of_david:"✡️",stars:"🌠",station:"🚉",statue_of_liberty:"🗽",steam_locomotive:"🚂",stew:"🍲",stop_button:"⏹",stop_sign:"🛑",stopwatch:"⏱",straight_ruler:"📏",strawberry:"🍓",stuck_out_tongue:"😛",stuck_out_tongue_closed_eyes:"😝",stuck_out_tongue_winking_eye:"😜",studio_microphone:"🎙",stuffed_flatbread:"🥙",sun_behind_large_cloud:"🌥",sun_behind_rain_cloud:"🌦",sun_behind_small_cloud:"🌤",sun_with_face:"🌞",sunflower:"🌻",sunglasses:"😎",sunny:"☀️",sunrise:"🌅",sunrise_over_mountains:"🌄",surfing_man:"🏄",surfing_woman:"🏄♀️",sushi:"🍣",suspension_railway:"🚟",sweat:"😓",sweat_drops:"💦",sweat_smile:"😅",sweet_potato:"🍠",swimming_man:"🏊",swimming_woman:"🏊♀️",symbols:"🔣",synagogue:"🕍",syringe:"💉",taco:"🌮",tada:"🎉",tanabata_tree:"🎋",taurus:"♉️",taxi:"🚕",tea:"🍵",telephone_receiver:"📞",telescope:"🔭",tennis:"🎾",tent:"⛺️",thermometer:"🌡",thinking:"🤔",thought_balloon:"💭",ticket:"🎫",tickets:"🎟",tiger:"🐯",tiger2:"🐅",timer_clock:"⏲",tipping_hand_man:"💁♂️",tired_face:"😫",tm:"™️",toilet:"🚽",tokyo_tower:"🗼",tomato:"🍅",tongue:"👅",top:"🔝",tophat:"🎩",tornado:"🌪",trackball:"🖲",tractor:"🚜",traffic_light:"🚥",train:"🚋",train2:"🚆",tram:"🚊",triangular_flag_on_post:"🚩",triangular_ruler:"📐",trident:"🔱",triumph:"😤",trolleybus:"🚎",trophy:"🏆",tropical_drink:"🍹",tropical_fish:"🐠",truck:"🚚",trumpet:"🎺",tulip:"🌷",tumbler_glass:"🥃",turkey:"🦃",turtle:"🐢",tv:"📺",twisted_rightwards_arrows:"🔀",two_hearts:"💕",two_men_holding_hands:"👬",two_women_holding_hands:"👭",u5272:"🈹",u5408:"🈴",u55b6:"🈺",u6307:"🈯️",u6708:"🈷️",u6709:"🈶",u6e80:"🈵",u7121:"🈚️",u7533:"🈸",u7981:"🈲",u7a7a:"🈳",umbrella:"☔️",unamused:"😒",underage:"🔞",unicorn:"🦄",unlock:"🔓",up:"🆙",upside_down_face:"🙃",v:"✌️",vertical_traffic_light:"🚦",vhs:"📼",vibration_mode:"📳",video_camera:"📹",video_game:"🎮",violin:"🎻",virgo:"♍️",volcano:"🌋",volleyball:"🏐",vs:"🆚",vulcan_salute:"🖖",walking_man:"🚶",walking_woman:"🚶♀️",waning_crescent_moon:"🌘",waning_gibbous_moon:"🌖",warning:"⚠️",wastebasket:"🗑",watch:"⌚️",water_buffalo:"🐃",watermelon:"🍉",wave:"👋",wavy_dash:"〰️",waxing_crescent_moon:"🌒",wc:"🚾",weary:"😩",wedding:"💒",weight_lifting_man:"🏋️",weight_lifting_woman:"🏋️♀️",whale:"🐳",whale2:"🐋",wheel_of_dharma:"☸️",wheelchair:"♿️",white_check_mark:"✅",white_circle:"⚪️",white_flag:"🏳️",white_flower:"💮",white_large_square:"⬜️",white_medium_small_square:"◽️",white_medium_square:"◻️",white_small_square:"▫️",white_square_button:"🔳",wilted_flower:"🥀",wind_chime:"🎐",wind_face:"🌬",wine_glass:"🍷",wink:"😉",wolf:"🐺",woman:"👩",woman_artist:"👩🎨",woman_astronaut:"👩🚀",woman_cartwheeling:"🤸♀️",woman_cook:"👩🍳",woman_facepalming:"🤦♀️",woman_factory_worker:"👩🏭",woman_farmer:"👩🌾",woman_firefighter:"👩🚒",woman_health_worker:"👩⚕️",woman_judge:"👩⚖️",woman_juggling:"🤹♀️",woman_mechanic:"👩🔧",woman_office_worker:"👩💼",woman_pilot:"👩✈️",woman_playing_handball:"🤾♀️",woman_playing_water_polo:"🤽♀️",woman_scientist:"👩🔬",woman_shrugging:"🤷♀️",woman_singer:"👩🎤",woman_student:"👩🎓",woman_teacher:"👩🏫",woman_technologist:"👩💻",woman_with_turban:"👳♀️",womans_clothes:"👚",womans_hat:"👒",women_wrestling:"🤼♀️",womens:"🚺",world_map:"🗺",worried:"😟",wrench:"🔧",writing_hand:"✍️",x:"❌",yellow_heart:"💛",yen:"💴",yin_yang:"☯️",yum:"😋",zap:"⚡️",zipper_mouth_face:"🤐",zzz:"💤",octocat:' ',showdown:`S `},t.Converter=function(e){"use strict";var a,r,n={},o=[],l=[],s={},c=B,u={parsed:{},raw:"",format:""};for(a in e=e||{},P)P.hasOwnProperty(a)&&(n[a]=P[a]);if(typeof e!="object")throw Error("Converter expects the passed parameter to be an object, but "+typeof e+" was passed instead.");for(r in e)e.hasOwnProperty(r)&&(n[r]=e[r]);function h(i,d){if(d=d||null,t.helper.isString(i)){if(d=i=t.helper.stdExtName(i),t.extensions[i]){console.warn("DEPRECATION WARNING: "+i+" is an old extension that uses a deprecated loading method.Please inform the developer that the extension should be updated!");var _=t.extensions[i],g=i;if(typeof _=="function"&&(_=_(new t.Converter)),t.helper.isArray(_)||(_=[_]),!(g=T(_,g)).valid)throw Error(g.error);for(var m=0;m<_.length;++m)switch(_[m].type){case"lang":o.push(_[m]);break;case"output":l.push(_[m]);break;default:throw Error("Extension loader error: Type unrecognized!!!")}return}if(t.helper.isUndefined(x[i]))throw Error('Extension "'+i+'" could not be loaded. It was either not found or is not a valid extension.');i=x[i]}if(typeof i=="function"&&(i=i()),g=T(i=t.helper.isArray(i)?i:[i],d),!g.valid)throw Error(g.error);for(var f=0;f [ \t]+,">¨NBSP;<"),!d){if(!window||!window.document)throw new Error("HTMLParser is undefined. If in a webworker or nodejs environment, you need to provide a WHATWG DOM and HTML such as JSDOM");d=window.document}for(var d=d.createElement("div"),_=(d.innerHTML=i,{preList:function(C){for(var k=C.querySelectorAll("pre"),j=[],w=0;w'}else j.push(k[w].innerHTML),k[w].innerHTML="",k[w].setAttribute("prenum",w.toString());return j}(d)}),g=(function C(k){for(var j=0;j? ?(['"].*['"])?\)$/m))c="";else if(!c){if(c="#"+(s=s||l.toLowerCase().replace(/ ?\n/g," ")),t.helper.isUndefined(r.gUrls[s]))return o;c=r.gUrls[s],t.helper.isUndefined(r.gTitles[s])||(p=r.gTitles[s])}return o='"+l+" "}return e=(e=(e=(e=(e=r.converter._dispatch("anchors.before",e,a,r)).replace(/\[((?:\[[^\]]*]|[^\[\]])*)] ?(?:\n *)?\[(.*?)]()()()()/g,n)).replace(/\[((?:\[[^\]]*]|[^\[\]])*)]()[ \t]*\([ \t]?<([^>]*)>(?:[ \t]*((["'])([^"]*?)\5))?[ \t]?\)/g,n)).replace(/\[((?:\[[^\]]*]|[^\[\]])*)]()[ \t]*\([ \t]?([\S]+?(?:\([\S]*?\)[\S]*?)?)>?(?:[ \t]*((["'])([^"]*?)\5))?[ \t]?\)/g,n)).replace(/\[([^\[\]]+)]()()()()()/g,n),a.ghMentions&&(e=e.replace(/(^|\s)(\\)?(@([a-z\d]+(?:[a-z\d.-]+?[a-z\d]+)*))/gim,function(o,l,s,c,u){if(s==="\\")return l+c;if(!t.helper.isString(a.ghMentionsLink))throw new Error("ghMentionsLink option must be a string");return s="",l+'"+c+" "})),e=r.converter._dispatch("anchors.after",e,a,r)});var U=/([*~_]+|\b)(((https?|ftp|dict):\/\/|www\.)[^'">\s]+?\.[^'">\s]+?)()(\1)?(?=\s|$)(?!["<>])/gi,G=/([*~_]+|\b)(((https?|ftp|dict):\/\/|www\.)[^'">\s]+\.[^'">\s]+?)([.!?,()\[\]])?(\1)?(?=\s|$)(?!["<>])/gi,F=/()<(((https?|ftp|dict):\/\/|www\.)[^'">\s]+)()>()/gi,W=/(^|\s)(?:mailto:)?([A-Za-z0-9!#$%&'*+-/=?^_`{|}~.]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)(?=$|\s)/gim,K=/<()(?:mailto:)?([-.\w]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi;t.subParser("autoLinks",function(e,a,r){"use strict";return e=(e=(e=r.converter._dispatch("autoLinks.before",e,a,r)).replace(F,I(a))).replace(K,O(a,r)),e=r.converter._dispatch("autoLinks.after",e,a,r)}),t.subParser("simplifiedAutoLinks",function(e,a,r){"use strict";return a.simplifiedAutoLink?(e=r.converter._dispatch("simplifiedAutoLinks.before",e,a,r),e=(e=a.excludeTrailingPunctuationFromURLs?e.replace(G,I(a)):e.replace(U,I(a))).replace(W,O(a,r)),r.converter._dispatch("simplifiedAutoLinks.after",e,a,r)):e}),t.subParser("blockGamut",function(e,a,r){"use strict";return e=r.converter._dispatch("blockGamut.before",e,a,r),e=t.subParser("blockQuotes")(e,a,r),e=t.subParser("headers")(e,a,r),e=t.subParser("horizontalRule")(e,a,r),e=t.subParser("lists")(e,a,r),e=t.subParser("codeBlocks")(e,a,r),e=t.subParser("tables")(e,a,r),e=t.subParser("hashHTMLBlocks")(e,a,r),e=t.subParser("paragraphs")(e,a,r),e=r.converter._dispatch("blockGamut.after",e,a,r)}),t.subParser("blockQuotes",function(e,a,r){"use strict";e=r.converter._dispatch("blockQuotes.before",e,a,r);var n=/(^ {0,3}>[ \t]?.+\n(.+\n)*\n*)+/gm;return a.splitAdjacentBlockquotes&&(n=/^ {0,3}>[\s\S]*?(?:\n\n)/gm),e=(e+=`
+
+`).replace(n,function(o){return o=(o=(o=o.replace(/^[ \t]*>[ \t]?/gm,"")).replace(/¨0/g,"")).replace(/^[ \t]+$/gm,""),o=t.subParser("githubCodeBlocks")(o,a,r),o=(o=(o=t.subParser("blockGamut")(o,a,r)).replace(/(^|\n)/g,"$1 ")).replace(/(\s*[^\r]+?<\/pre>)/gm,function(l,s){return s.replace(/^ /gm,"¨0").replace(/¨0/g,"")}),t.subParser("hashBlock")(`
+`+o+`
+ `,a,r)}),e=r.converter._dispatch("blockQuotes.after",e,a,r)}),t.subParser("codeBlocks",function(e,a,r){"use strict";return e=r.converter._dispatch("codeBlocks.before",e,a,r),e=(e=(e+="¨0").replace(/(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=¨0))/g,function(n,c,l){var s=`
+`,c=t.subParser("outdent")(c,a,r);return c=t.subParser("encodeCode")(c,a,r),c=""+(c=(c=(c=t.subParser("detab")(c,a,r)).replace(/^\n+/g,"")).replace(/\n+$/g,""))+(s=a.omitExtraWLInCodeBlocks?"":s)+"
",t.subParser("hashBlock")(c,a,r)+l})).replace(/¨0/,""),e=r.converter._dispatch("codeBlocks.after",e,a,r)}),t.subParser("codeSpans",function(e,a,r){"use strict";return e=(e=(e=r.converter._dispatch("codeSpans.before",e,a,r))===void 0?"":e).replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,function(n,o,l,s){return s=(s=s.replace(/^([ \t]*)/g,"")).replace(/[ \t]*$/g,""),s=o+""+(s=t.subParser("encodeCode")(s,a,r))+"
",s=t.subParser("hashHTMLSpans")(s,a,r)}),e=r.converter._dispatch("codeSpans.after",e,a,r)}),t.subParser("completeHTMLDocument",function(e,a,r){"use strict";if(!a.completeHTMLDocument)return e;e=r.converter._dispatch("completeHTMLDocument.before",e,a,r);var n,o="html",l=`
+`,s="",c=`
+`,u="",h="";for(n in r.metadata.parsed.doctype!==void 0&&(l="
+`,(o=r.metadata.parsed.doctype.toString().toLowerCase())!=="html"&&o!=="html5"||(c=' ')),r.metadata.parsed)if(r.metadata.parsed.hasOwnProperty(n))switch(n.toLowerCase()){case"doctype":break;case"title":s=""+r.metadata.parsed.title+`
+`;break;case"charset":c=o==="html"||o==="html5"?'
+`:'
+`;break;case"language":case"lang":u=' lang="'+r.metadata.parsed[n]+'"',h+='
+`;break;default:h+='
+`}return e=l+"
+
+`+s+c+h+`
+
+`+e.trim()+`
+
+`,e=r.converter._dispatch("completeHTMLDocument.after",e,a,r)}),t.subParser("detab",function(e,a,r){"use strict";return e=(e=(e=(e=(e=(e=r.converter._dispatch("detab.before",e,a,r)).replace(/\t(?=\t)/g," ")).replace(/\t/g,"¨A¨B")).replace(/¨B(.+?)¨A/g,function(n,o){for(var l=o,s=4-l.length%4,c=0;c/g,">"),e=r.converter._dispatch("encodeAmpsAndAngles.after",e,a,r)}),t.subParser("encodeBackslashEscapes",function(e,a,r){"use strict";return e=(e=(e=r.converter._dispatch("encodeBackslashEscapes.before",e,a,r)).replace(/\\(\\)/g,t.helper.escapeCharactersCallback)).replace(/\\([`*_{}\[\]()>#+.!~=|:-])/g,t.helper.escapeCharactersCallback),e=r.converter._dispatch("encodeBackslashEscapes.after",e,a,r)}),t.subParser("encodeCode",function(e,a,r){"use strict";return e=(e=r.converter._dispatch("encodeCode.before",e,a,r)).replace(/&/g,"&").replace(/ /g,">").replace(/([*_{}\[\]\\=~-])/g,t.helper.escapeCharactersCallback),e=r.converter._dispatch("encodeCode.after",e,a,r)}),t.subParser("escapeSpecialCharsWithinTagAttributes",function(e,a,r){"use strict";return e=(e=(e=r.converter._dispatch("escapeSpecialCharsWithinTagAttributes.before",e,a,r)).replace(/<\/?[a-z\d_:-]+(?:[\s]+[\s\S]+?)?>/gi,function(n){return n.replace(/(.)<\/?code>(?=.)/g,"$1`").replace(/([\\`*_~=|])/g,t.helper.escapeCharactersCallback)})).replace(/-]|-[^>])(?:[^-]|-[^-])*)--)>/gi,function(n){return n.replace(/([\\`*_~=|])/g,t.helper.escapeCharactersCallback)}),e=r.converter._dispatch("escapeSpecialCharsWithinTagAttributes.after",e,a,r)}),t.subParser("githubCodeBlocks",function(e,a,r){"use strict";return a.ghCodeBlocks?(e=r.converter._dispatch("githubCodeBlocks.before",e,a,r),e=(e=(e+="¨0").replace(/(?:^|\n)(?: {0,3})(```+|~~~+)(?: *)([^\s`~]*)\n([\s\S]*?)\n(?: {0,3})\1/g,function(n,o,l,s){var c=a.omitExtraWLInCodeBlocks?"":`
+`;return s=t.subParser("encodeCode")(s,a,r),s=""+(s=(s=(s=t.subParser("detab")(s,a,r)).replace(/^\n+/g,"")).replace(/\n+$/g,""))+c+"
",s=t.subParser("hashBlock")(s,a,r),`
+
+¨G`+(r.ghCodeBlocks.push({text:n,codeblock:s})-1)+`G
+
+`})).replace(/¨0/,""),r.converter._dispatch("githubCodeBlocks.after",e,a,r)):e}),t.subParser("hashBlock",function(e,a,r){"use strict";return e=(e=r.converter._dispatch("hashBlock.before",e,a,r)).replace(/(^\n+|\n+$)/g,""),e=`
+
+¨K`+(r.gHtmlBlocks.push(e)-1)+`K
+
+`,e=r.converter._dispatch("hashBlock.after",e,a,r)}),t.subParser("hashCodeTags",function(e,a,r){"use strict";return e=r.converter._dispatch("hashCodeTags.before",e,a,r),e=t.helper.replaceRecursiveRegExp(e,function(n,o,l,s){return l=l+t.subParser("encodeCode")(o,a,r)+s,"¨C"+(r.gHtmlSpans.push(l)-1)+"C"},"]*>","
","gim"),e=r.converter._dispatch("hashCodeTags.after",e,a,r)}),t.subParser("hashElement",function(e,a,r){"use strict";return function(n,o){return o=(o=(o=o.replace(/\n\n/g,`
+`)).replace(/^\n/,"")).replace(/\n+$/g,""),o=`
+
+¨K`+(r.gHtmlBlocks.push(o)-1)+`K
+
+`}}),t.subParser("hashHTMLBlocks",function(e,a,r){"use strict";e=r.converter._dispatch("hashHTMLBlocks.before",e,a,r);function n(i,d,_,g){return _.search(/\bmarkdown\b/)!==-1&&(i=_+r.converter.makeHtml(d)+g),`
+
+¨K`+(r.gHtmlBlocks.push(i)-1)+`K
+
+`}var o=["pre","div","h1","h2","h3","h4","h5","h6","blockquote","table","dl","ol","ul","script","noscript","form","fieldset","iframe","math","style","section","header","footer","nav","article","aside","address","audio","canvas","figure","hgroup","output","video","p"];a.backslashEscapesHTMLTags&&(e=e.replace(/\\<(\/?[^>]+?)>/g,function(i,d){return"<"+d+">"}));for(var l=0;l]*>)","im"),c="<"+o[l]+"\\b[^>]*>",u=""+o[l]+">";(h=t.helper.regexIndexOf(e,s))!==-1;){var h=t.helper.splitAtIndex(e,h),p=t.helper.replaceRecursiveRegExp(h[1],n,c,u,"im");if(p===h[1])break;e=h[0].concat(p)}return e=e.replace(/(\n {0,3}(<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g,t.subParser("hashElement")(e,a,r)),e=(e=t.helper.replaceRecursiveRegExp(e,function(i){return`
+
+¨K`+(r.gHtmlBlocks.push(i)-1)+`K
+
+`},"^ {0,3}","gm")).replace(/(?:\n\n)( {0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g,t.subParser("hashElement")(e,a,r)),e=r.converter._dispatch("hashHTMLBlocks.after",e,a,r)}),t.subParser("hashHTMLSpans",function(e,a,r){"use strict";function n(o){return"¨C"+(r.gHtmlSpans.push(o)-1)+"C"}return e=(e=(e=(e=(e=r.converter._dispatch("hashHTMLSpans.before",e,a,r)).replace(/<[^>]+?\/>/gi,n)).replace(/<([^>]+?)>[\s\S]*?<\/\1>/g,n)).replace(/<([^>]+?)\s[^>]+?>[\s\S]*?<\/\1>/g,n)).replace(/<[^>]+?>/gi,n),e=r.converter._dispatch("hashHTMLSpans.after",e,a,r)}),t.subParser("unhashHTMLSpans",function(e,a,r){"use strict";e=r.converter._dispatch("unhashHTMLSpans.before",e,a,r);for(var n=0;n]*>\\s*]*>","^ {0,3}
\\s*","gim"),e=r.converter._dispatch("hashPreCodeTags.after",e,a,r)}),t.subParser("headers",function(e,a,r){"use strict";e=r.converter._dispatch("headers.before",e,a,r);var n=isNaN(parseInt(a.headerLevelStart))?1:parseInt(a.headerLevelStart),l=a.smoothLivePreview?/^(.+)[ \t]*\n={2,}[ \t]*\n+/gm:/^(.+)[ \t]*\n=+[ \t]*\n+/gm,o=a.smoothLivePreview?/^(.+)[ \t]*\n-{2,}[ \t]*\n+/gm:/^(.+)[ \t]*\n-+[ \t]*\n+/gm,l=(e=(e=e.replace(l,function(c,p){var h=t.subParser("spanGamut")(p,a,r),p=a.noHeaderId?"":' id="'+s(p)+'"',p=""+h+" ";return t.subParser("hashBlock")(p,a,r)})).replace(o,function(c,i){var h=t.subParser("spanGamut")(i,a,r),i=a.noHeaderId?"":' id="'+s(i)+'"',p=n+1,i=""+h+" ";return t.subParser("hashBlock")(i,a,r)}),a.requireSpaceBeforeHeadingText?/^(#{1,6})[ \t]+(.+?)[ \t]*#*\n+/gm:/^(#{1,6})[ \t]*(.+?)[ \t]*#*\n+/gm);function s(h){var u=h=a.customizedHeaderId&&(u=h.match(/\{([^{]+?)}\s*$/))&&u[1]?u[1]:h,h=t.helper.isString(a.prefixHeaderId)?a.prefixHeaderId:a.prefixHeaderId===!0?"section-":"";return a.rawPrefixHeaderId||(u=h+u),u=(a.ghCompatibleHeaderId?u.replace(/ /g,"-").replace(/&/g,"").replace(/¨T/g,"").replace(/¨D/g,"").replace(/[&+$,\/:;=?@"#{}|^¨~\[\]`\\*)(%.!'<>]/g,""):a.rawHeaderId?u.replace(/ /g,"-").replace(/&/g,"&").replace(/¨T/g,"¨").replace(/¨D/g,"$").replace(/["']/g,"-"):u.replace(/[^\w]/g,"")).toLowerCase(),a.rawPrefixHeaderId&&(u=h+u),r.hashLinkCounts[u]?u=u+"-"+r.hashLinkCounts[u]++:r.hashLinkCounts[u]=1,u}return e=e.replace(l,function(c,i,d){var p=d,p=(a.customizedHeaderId&&(p=d.replace(/\s?\{([^{]+?)}\s*$/,"")),t.subParser("spanGamut")(p,a,r)),d=a.noHeaderId?"":' id="'+s(d)+'"',i=n-1+i.length,d=""+p+" ";return t.subParser("hashBlock")(d,a,r)}),e=r.converter._dispatch("headers.after",e,a,r)}),t.subParser("horizontalRule",function(e,a,r){"use strict";e=r.converter._dispatch("horizontalRule.before",e,a,r);var n=t.subParser("hashBlock")(" ",a,r);return e=(e=(e=e.replace(/^ {0,2}( ?-){3,}[ \t]*$/gm,n)).replace(/^ {0,2}( ?\*){3,}[ \t]*$/gm,n)).replace(/^ {0,2}( ?_){3,}[ \t]*$/gm,n),e=r.converter._dispatch("horizontalRule.after",e,a,r)}),t.subParser("images",function(e,a,r){"use strict";function n(o,l,s,c,u,h,p,i){var d=r.gUrls,_=r.gTitles,g=r.gDimensions;if(s=s.toLowerCase(),i=i||"",-1? ?(['"].*['"])?\)$/m))c="";else if(c===""||c===null){if(c="#"+(s=s!==""&&s!==null?s:l.toLowerCase().replace(/ ?\n/g," ")),t.helper.isUndefined(d[s]))return o;c=d[s],t.helper.isUndefined(_[s])||(i=_[s]),t.helper.isUndefined(g[s])||(u=g[s].width,h=g[s].height)}return l=l.replace(/"/g,""").replace(t.helper.regexes.asteriskDashAndColon,t.helper.escapeCharactersCallback),o=' "}return e=(e=(e=(e=(e=(e=r.converter._dispatch("images.before",e,a,r)).replace(/!\[([^\]]*?)] ?(?:\n *)?\[([\s\S]*?)]()()()()()/g,n)).replace(/!\[([^\]]*?)][ \t]*()\([ \t]?(data:.+?\/.+?;base64,[A-Za-z0-9+/=\n]+?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(["'])([^"]*?)\6)?[ \t]?\)/g,function(o,l,s,c,u,h,p,i){return n(o,l,s,c=c.replace(/\s/g,""),u,h,0,i)})).replace(/!\[([^\]]*?)][ \t]*()\([ \t]?<([^>]*)>(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(?:(["'])([^"]*?)\6))?[ \t]?\)/g,n)).replace(/!\[([^\]]*?)][ \t]*()\([ \t]?([\S]+?(?:\([\S]*?\)[\S]*?)?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(["'])([^"]*?)\6)?[ \t]?\)/g,n)).replace(/!\[([^\[\]]+)]()()()()()/g,n),e=r.converter._dispatch("images.after",e,a,r)}),t.subParser("italicsAndBold",function(e,a,r){"use strict";return e=r.converter._dispatch("italicsAndBold.before",e,a,r),e=a.literalMidWordUnderscores?(e=(e=e.replace(/\b___(\S[\s\S]*?)___\b/g,function(n,o){return""+o+" "})).replace(/\b__(\S[\s\S]*?)__\b/g,function(n,o){return""+o+" "})).replace(/\b_(\S[\s\S]*?)_\b/g,function(n,o){return""+o+" "}):(e=(e=e.replace(/___(\S[\s\S]*?)___/g,function(n,o){return/\S$/.test(o)?""+o+" ":n})).replace(/__(\S[\s\S]*?)__/g,function(n,o){return/\S$/.test(o)?""+o+" ":n})).replace(/_([^\s_][\s\S]*?)_/g,function(n,o){return/\S$/.test(o)?""+o+" ":n}),e=a.literalMidWordAsterisks?(e=(e=e.replace(/([^*]|^)\B\*\*\*(\S[\s\S]*?)\*\*\*\B(?!\*)/g,function(n,o,l){return o+""+l+" "})).replace(/([^*]|^)\B\*\*(\S[\s\S]*?)\*\*\B(?!\*)/g,function(n,o,l){return o+""+l+" "})).replace(/([^*]|^)\B\*(\S[\s\S]*?)\*\B(?!\*)/g,function(n,o,l){return o+""+l+" "}):(e=(e=e.replace(/\*\*\*(\S[\s\S]*?)\*\*\*/g,function(n,o){return/\S$/.test(o)?""+o+" ":n})).replace(/\*\*(\S[\s\S]*?)\*\*/g,function(n,o){return/\S$/.test(o)?""+o+" ":n})).replace(/\*([^\s*][\s\S]*?)\*/g,function(n,o){return/\S$/.test(o)?""+o+" ":n}),e=r.converter._dispatch("italicsAndBold.after",e,a,r)}),t.subParser("lists",function(e,a,r){"use strict";function n(s,c){r.gListLevel++,s=s.replace(/\n{2,}$/,`
+`);var u=/(\n)?(^ {0,3})([*+-]|\d+[.])[ \t]+((\[(x|X| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(¨0| {0,3}([*+-]|\d+[.])[ \t]+))/gm,h=/\n[ \t]*\n(?!¨0)/.test(s+="¨0");return a.disableForced4SpacesIndentedSublists&&(u=/(\n)?(^ {0,3})([*+-]|\d+[.])[ \t]+((\[(x|X| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(¨0|\2([*+-]|\d+[.])[ \t]+))/gm),s=(s=s.replace(u,function(p,i,d,_,b,m,f){f=f&&f.trim()!=="";var b=t.subParser("outdent")(b,a,r),C="";return m&&a.tasklists&&(C=' class="task-list-item" style="list-style-type: none;"',b=b.replace(/^[ \t]*\[(x|X| )?]/m,function(){var k=' "})),b=b.replace(/^([-*+]|\d\.)[ \t]+[\S\n ]*/g,function(k){return"¨A"+k}),b=""+(b=(b=i||-1
+`})).replace(/¨0/g,""),r.gListLevel--,s=c?s.replace(/\s+$/,""):s}function o(s,c){return c==="ol"&&(c=s.match(/^ *(\d+)\./),c&&c[1]!=="1")?' start="'+c[1]+'"':""}function l(s,c,u){var h,p=a.disableForced4SpacesIndentedSublists?/^ ?\d+\.[ \t]/gm:/^ {0,3}\d+\.[ \t]/gm,i=a.disableForced4SpacesIndentedSublists?/^ ?[*+-][ \t]/gm:/^ {0,3}[*+-][ \t]/gm,d=c==="ul"?p:i,_="";return s.search(d)!==-1?function g(m){var f=m.search(d),b=o(s,c);f!==-1?(_+=`
+
+<`+c+b+`>
+`+n(m.slice(0,f),!!u)+""+c+`>
+`,d=(c=c==="ul"?"ol":"ul")=="ul"?p:i,g(m.slice(f))):_+=`
+
+<`+c+b+`>
+`+n(m,!!u)+""+c+`>
+`}(s):(h=o(s,c),_=`
+
+<`+c+h+`>
+`+n(s,!!u)+""+c+`>
+`),_}return e=r.converter._dispatch("lists.before",e,a,r),e+="¨0",e=(e=r.gListLevel?e.replace(/^(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(¨0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm,function(s,c,u){return l(c,-1"),c+="
",o.push(c))}for(l=o.length,s=0;s]*>\s*]*>/.test(h)&&(p=!0)}o[s]=h}return e=(e=(e=o.join(`
+`)).replace(/^\n+/g,"")).replace(/\n+$/g,""),r.converter._dispatch("paragraphs.after",e,a,r)}),t.subParser("runExtension",function(e,a,r,n){"use strict";return e.filter?a=e.filter(a,n.converter,r):e.regex&&((n=e.regex)instanceof RegExp||(n=new RegExp(n,"g")),a=a.replace(n,e.replace)),a}),t.subParser("spanGamut",function(e,a,r){"use strict";return e=r.converter._dispatch("spanGamut.before",e,a,r),e=t.subParser("codeSpans")(e,a,r),e=t.subParser("escapeSpecialCharsWithinTagAttributes")(e,a,r),e=t.subParser("encodeBackslashEscapes")(e,a,r),e=t.subParser("images")(e,a,r),e=t.subParser("anchors")(e,a,r),e=t.subParser("autoLinks")(e,a,r),e=t.subParser("simplifiedAutoLinks")(e,a,r),e=t.subParser("emoji")(e,a,r),e=t.subParser("underline")(e,a,r),e=t.subParser("italicsAndBold")(e,a,r),e=t.subParser("strikethrough")(e,a,r),e=t.subParser("ellipsis")(e,a,r),e=t.subParser("hashHTMLSpans")(e,a,r),e=t.subParser("encodeAmpsAndAngles")(e,a,r),a.simpleLineBreaks?/\n\n¨K/.test(e)||(e=e.replace(/\n+/g,`
+`)):e=e.replace(/ +\n/g,`
+`),e=r.converter._dispatch("spanGamut.after",e,a,r)}),t.subParser("strikethrough",function(e,a,r){"use strict";return a.strikethrough&&(e=(e=r.converter._dispatch("strikethrough.before",e,a,r)).replace(/(?:~){2}([\s\S]+?)(?:~){2}/g,function(n,o){return o=o,""+(o=a.simplifiedAutoLink?t.subParser("simplifiedAutoLinks")(o,a,r):o)+""}),e=r.converter._dispatch("strikethrough.after",e,a,r)),e}),t.subParser("stripLinkDefinitions",function(e,a,r){"use strict";function n(o,l,s,c,u,h,p){return l=l.toLowerCase(),e.toLowerCase().split(l).length-1<2?o:(s.match(/^data:.+?\/.+?;base64,/)?r.gUrls[l]=s.replace(/\s/g,""):r.gUrls[l]=t.subParser("encodeAmpsAndAngles")(s,a,r),h?h+p:(p&&(r.gTitles[l]=p.replace(/"|'/g,""")),a.parseImgDimensions&&c&&u&&(r.gDimensions[l]={width:c,height:u}),""))}return e=(e=(e=(e+="¨0").replace(/^ {0,3}\[([^\]]+)]:[ \t]*\n?[ \t]*(data:.+?\/.+?;base64,[A-Za-z0-9+/=\n]+?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*\n?[ \t]*(?:(\n*)["|'(](.+?)["|')][ \t]*)?(?:\n\n|(?=¨0)|(?=\n\[))/gm,n)).replace(/^ {0,3}\[([^\]]+)]:[ \t]*\n?[ \t]*([^>\s]+)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*\n?[ \t]*(?:(\n*)["|'(](.+?)["|')][ \t]*)?(?:\n+|(?=¨0))/gm,n)).replace(/¨0/,"")}),t.subParser("tables",function(e,a,r){"use strict";if(!a.tables)return e;function n(o){for(var l=o.split(`
+`),s=0;s"+(u=t.subParser("spanGamut")(u,a,r))+`
+`));for(s=0;s"+t.subParser("spanGamut")(i,a,r)+`
+`));b.push(C)}for(var j=m,w=b,z=`
+
+
+`,L=j.length,S=0;S
+
+
+`,S=0;S
+`;for(var E=0;E
+`}return z+=`
+
+`}return e=(e=(e=(e=r.converter._dispatch("tables.before",e,a,r)).replace(/\\(\|)/g,t.helper.escapeCharactersCallback)).replace(/^ {0,3}\|?.+\|.+\n {0,3}\|?[ \t]*:?[ \t]*(?:[-=]){2,}[ \t]*:?[ \t]*\|[ \t]*:?[ \t]*(?:[-=]){2,}[\s\S]+?(?:\n\n|¨0)/gm,n)).replace(/^ {0,3}\|.+\|[ \t]*\n {0,3}\|[ \t]*:?[ \t]*(?:[-=]){2,}[ \t]*:?[ \t]*\|[ \t]*\n( {0,3}\|.+\|[ \t]*\n)*(?:\n|¨0)/gm,n),e=r.converter._dispatch("tables.after",e,a,r)}),t.subParser("underline",function(e,a,r){"use strict";return a.underline?(e=r.converter._dispatch("underline.before",e,a,r),e=(e=a.literalMidWordUnderscores?(e=e.replace(/\b___(\S[\s\S]*?)___\b/g,function(n,o){return""+o+" "})).replace(/\b__(\S[\s\S]*?)__\b/g,function(n,o){return""+o+" "}):(e=e.replace(/___(\S[\s\S]*?)___/g,function(n,o){return/\S$/.test(o)?""+o+" ":n})).replace(/__(\S[\s\S]*?)__/g,function(n,o){return/\S$/.test(o)?""+o+" ":n})).replace(/(_)/g,t.helper.escapeCharactersCallback),r.converter._dispatch("underline.after",e,a,r)):e}),t.subParser("unescapeSpecialChars",function(e,a,r){"use strict";return e=(e=r.converter._dispatch("unescapeSpecialChars.before",e,a,r)).replace(/¨E(\d+)E/g,function(n,o){return o=parseInt(o),String.fromCharCode(o)}),e=r.converter._dispatch("unescapeSpecialChars.after",e,a,r)}),t.subParser("makeMarkdown.blockquote",function(e,a){"use strict";var r="";if(e.hasChildNodes())for(var n=e.childNodes,o=n.length,l=0;l `)}),t.subParser("makeMarkdown.codeBlock",function(n,a){"use strict";var r=n.getAttribute("language"),n=n.getAttribute("precodenum");return"```"+r+`
+`+a.preList[n]+"\n```"}),t.subParser("makeMarkdown.codeSpan",function(e){"use strict";return"`"+e.innerHTML+"`"}),t.subParser("makeMarkdown.emphasis",function(e,a){"use strict";var r="";if(e.hasChildNodes()){r+="*";for(var n=e.childNodes,o=n.length,l=0;l",e.hasAttribute("width")&&e.hasAttribute("height")&&(a+=" ="+e.getAttribute("width")+"x"+e.getAttribute("height")),e.hasAttribute("title")&&(a+=' "'+e.getAttribute("title")+'"'),a+=")"),a}),t.subParser("makeMarkdown.links",function(e,a){"use strict";var r="";if(e.hasChildNodes()&&e.hasAttribute("href")){for(var n=e.childNodes,o=n.length,r="[",l=0;l"),e.hasAttribute("title")&&(r+=' "'+e.getAttribute("title")+'"'),r+=")"}return r}),t.subParser("makeMarkdown.list",function(e,a,r){"use strict";var n="";if(!e.hasChildNodes())return"";for(var o=e.childNodes,l=o.length,s=e.getAttribute("start")||1,c=0;c
+`).trim()}),t.subParser("makeMarkdown.listItem",function(e,a){"use strict";for(var r="",n=e.childNodes,o=n.length,l=0;l
+
+`;if(e.nodeType!==1)return"";switch(e.tagName.toLowerCase()){case"h1":r||(n=t.subParser("makeMarkdown.header")(e,a,1)+`
+
+`);break;case"h2":r||(n=t.subParser("makeMarkdown.header")(e,a,2)+`
+
+`);break;case"h3":r||(n=t.subParser("makeMarkdown.header")(e,a,3)+`
+
+`);break;case"h4":r||(n=t.subParser("makeMarkdown.header")(e,a,4)+`
+
+`);break;case"h5":r||(n=t.subParser("makeMarkdown.header")(e,a,5)+`
+
+`);break;case"h6":r||(n=t.subParser("makeMarkdown.header")(e,a,6)+`
+
+`);break;case"p":r||(n=t.subParser("makeMarkdown.paragraph")(e,a)+`
+
+`);break;case"blockquote":r||(n=t.subParser("makeMarkdown.blockquote")(e,a)+`
+
+`);break;case"hr":r||(n=t.subParser("makeMarkdown.hr")(e,a)+`
+
+`);break;case"ol":r||(n=t.subParser("makeMarkdown.list")(e,a,"ol")+`
+
+`);break;case"ul":r||(n=t.subParser("makeMarkdown.list")(e,a,"ul")+`
+
+`);break;case"precode":r||(n=t.subParser("makeMarkdown.codeBlock")(e,a)+`
+
+`);break;case"pre":r||(n=t.subParser("makeMarkdown.pre")(e,a)+`
+
+`);break;case"table":r||(n=t.subParser("makeMarkdown.table")(e,a)+`
+
+`);break;case"code":n=t.subParser("makeMarkdown.codeSpan")(e,a);break;case"em":case"i":n=t.subParser("makeMarkdown.emphasis")(e,a);break;case"strong":case"b":n=t.subParser("makeMarkdown.strong")(e,a);break;case"del":n=t.subParser("makeMarkdown.strikethrough")(e,a);break;case"a":n=t.subParser("makeMarkdown.links")(e,a);break;case"img":n=t.subParser("makeMarkdown.image")(e,a);break;default:n=e.outerHTML+`
+
+`}return n}),t.subParser("makeMarkdown.paragraph",function(e,a){"use strict";var r="";if(e.hasChildNodes())for(var n=e.childNodes,o=n.length,l=0;l"+a.preList[e]+""}),t.subParser("makeMarkdown.strikethrough",function(e,a){"use strict";var r="";if(e.hasChildNodes()){r+="~~";for(var n=e.childNodes,o=n.length,l=0;ltr>th"),l=e.querySelectorAll("tbody>tr"),s=0;s/g,"\\$1>")).replace(/^#/gm,"\\#")).replace(/^(\s*)([-=]{3,})(\s*)$/,"$1\\$2$3")).replace(/^( {0,3}\d+)\./gm,"$1\\.")).replace(/^( {0,3})([+-])/gm,"$1\\$2")).replace(/]([\s]*)\(/g,"\\]$1\\(")).replace(/^ {0,3}\[([\S \t]*?)]:/gm,"\\[$1]:")}),typeof define=="function"&&define.amd?define(function(){"use strict";return t}):typeof H<"u"&&H.exports?H.exports=t:this.showdown=t}).call(R)});var D=ae(V()),te=new D.default.Converter({omitExtraWLInCodeBlocks:!0,ghCompatibleHeaderId:!0,parseImgDimensions:!0,simplifiedAutoLink:!0,excludeTrailingPunctuationFromURLs:!0,strikethrough:!0,tables:!0,tablesHeaderId:!0,tasklists:!0,disableForced4SpacesIndentedSublists:!0,simpleLineBreaks:!0,requireSpaceBeforeHeadingText:!0});addEventListener("message",async function(v){let t=v.data.id,y=await fetch(`${t}`);y.status>199&&y.status<400?postMessage({id:t,ok:!0,data:te.makeHtml(await y.text())}):postMessage({id:t,ok:!1,data:y.status})});})();
+/*! showdown v 2.1.0 - 21-04-2022 */
diff --git a/ghp/CREDITS.md b/ghp/CREDITS.md
new file mode 120000
index 00000000..d76a3ede
--- /dev/null
+++ b/ghp/CREDITS.md
@@ -0,0 +1 @@
+../CREDITS.md
\ No newline at end of file
diff --git a/ghp/README.md b/ghp/README.md
new file mode 120000
index 00000000..32d46ee8
--- /dev/null
+++ b/ghp/README.md
@@ -0,0 +1 @@
+../README.md
\ No newline at end of file
diff --git a/ghp/dist b/ghp/dist
new file mode 120000
index 00000000..85d8c32f
--- /dev/null
+++ b/ghp/dist
@@ -0,0 +1 @@
+../dist
\ No newline at end of file
diff --git a/ghp/docs b/ghp/docs
new file mode 120000
index 00000000..a9594bfe
--- /dev/null
+++ b/ghp/docs
@@ -0,0 +1 @@
+../docs
\ No newline at end of file
diff --git a/ghp/index.htm b/ghp/index.htm
new file mode 120000
index 00000000..6c227a23
--- /dev/null
+++ b/ghp/index.htm
@@ -0,0 +1 @@
+../index.htm
\ No newline at end of file
diff --git a/ghp/test b/ghp/test
new file mode 120000
index 00000000..419df4f9
--- /dev/null
+++ b/ghp/test
@@ -0,0 +1 @@
+../test
\ No newline at end of file
diff --git a/index.htm b/index.htm
new file mode 100644
index 00000000..06703c90
--- /dev/null
+++ b/index.htm
@@ -0,0 +1,24 @@
+
+
+
+ Octavia by Lightingale
+
+
+
+
+
+
+
+
+
+
+
+
+ Disclaimer
+ The core processing library (state.mjs), basic visualizer template (basic.mjs), MIDI interface middleware (bridge.mjs) and several pre-written visualizers of Octavia are all free libre software under GNU LGPL license. There is absolutely no warranty for using Octavia , to the extent permitted by applicable law.
+ Some files came with Octavia are licensed differently, like the bitmap font and voice bitmaps. Read their respective licenses before using them.
+ Feel free to check the source code out on GitHub . If you like Octavia, don't forget to leave a star!
+ Documentation is also available here .
+ List of Octavia demos
+ See all of the demos available.
+
diff --git a/libs/browser-fs-access@GoogleChromeLabs/browser_fs_access.min.js b/libs/browser-fs-access@GoogleChromeLabs/browser_fs_access.min.js
new file mode 100644
index 00000000..3951dd94
--- /dev/null
+++ b/libs/browser-fs-access@GoogleChromeLabs/browser_fs_access.min.js
@@ -0,0 +1 @@
+var T=Object.defineProperty;var f=(e,t)=>()=>(e&&(t=e(e=0)),t);var d=(e,t)=>{for(var i in t)T(e,i,{get:t[i],enumerable:!0})};var y={};d(y,{default:()=>E});var E,p=f(()=>{E=async(e=[{}])=>(Array.isArray(e)||(e=[e]),new Promise((t,i)=>{let r=document.createElement("input");r.type="file";let l=[...e.map(s=>s.mimeTypes||[]).join(),e.map(s=>s.extensions||[]).join()].join();r.multiple=e[0].multiple||!1,r.accept=l||"";let n=()=>c(i),a=s=>{typeof c=="function"&&c(),t(s)},c=e[0].legacySetup&&e[0].legacySetup(a,n,r);r.addEventListener("change",()=>{a(r.multiple?Array.from(r.files):r.files[0])}),r.click()}))});var w={};d(w,{default:()=>I});var N,I,h=f(()=>{N=async e=>{let t=await e.getFile();return t.handle=e,t},I=async(e=[{}])=>{Array.isArray(e)||(e=[e]);let t=[];e.forEach((l,n)=>{t[n]={description:l.description||"",accept:{}},l.mimeTypes?l.mimeTypes.map(a=>{t[n].accept[a]=l.extensions||[]}):t[n].accept["*/*"]=l.extensions||[]});let i=await window.showOpenFilePicker({id:e[0].id,startIn:e[0].startIn,types:t,multiple:e[0].multiple||!1,excludeAcceptAllOption:e[0].excludeAcceptAllOption||!1}),r=await Promise.all(i.map(N));return e[0].multiple?r:r[0]}});var o={};d(o,{default:()=>M});var M,A=f(()=>{M=async(e=[{}])=>(Array.isArray(e)||(e=[e]),e[0].recursive=e[0].recursive||!1,new Promise((t,i)=>{let r=document.createElement("input");r.type="file",r.webkitdirectory=!0;let l=()=>a(i),n=c=>{typeof a=="function"&&a(),t(c)},a=e[0].legacySetup&&e[0].legacySetup(n,l,r);r.addEventListener("change",()=>{let c=Array.from(r.files);e[0].recursive?e[0].recursive&&e[0].skipDirectory&&(c=c.filter(s=>s.webkitRelativePath.split("/").every(S=>!e[0].skipDirectory({name:S,kind:"directory"})))):c=c.filter(s=>s.webkitRelativePath.split("/").length===2),n(c)}),r.click()}))});var x={};d(x,{default:()=>B});var v,B,g=f(()=>{v=async(e,t,i=e.name,r)=>{let l=[],n=[];for await(let a of e.values()){let c=`${i}/${a.name}`;a.kind==="file"?n.push(a.getFile().then(s=>(s.directoryHandle=e,s.handle=a,Object.defineProperty(s,"webkitRelativePath",{configurable:!0,enumerable:!0,get:()=>c})))):a.kind==="directory"&&t&&(!r||!r(a))&&l.push(v(a,t,c,r))}return[...(await Promise.all(l)).flat(),...await Promise.all(n)]},B=async(e={})=>{e.recursive=e.recursive||!1;let t=await window.showDirectoryPicker({id:e.id,startIn:e.startIn});return v(t,e.recursive,void 0,e.skipDirectory)}});var k={};d(k,{default:()=>W});async function $(e,t){let i=e.getReader(),r=new ReadableStream({start(n){return a();async function a(){return i.read().then(({done:c,value:s})=>{if(c){n.close();return}return n.enqueue(s),a()})}}}),l=new Response(r);return i.releaseLock(),new Blob([await l.blob()],{type:t})}var W,P=f(()=>{W=async(e,t={})=>{Array.isArray(t)&&(t=t[0]);let i=document.createElement("a"),r=e;"body"in e&&(r=await $(e.body,e.headers.get("content-type"))),i.download=t.fileName||"Untitled",i.href=URL.createObjectURL(r);let l=()=>a(reject),n=()=>{typeof a=="function"&&a()},a=t.legacySetup&&t.legacySetup(n,l,i);return i.addEventListener("click",()=>{setTimeout(()=>URL.revokeObjectURL(i.href),30*1e3),n(null)}),i.click(),null}});var j={};d(j,{default:()=>q});var q,L=f(()=>{q=async(e,t=[{}],i=null,r=!1)=>{Array.isArray(t)||(t=[t]),t[0].fileName=t[0].fileName||"Untitled";let l=[];if(t.forEach((c,s)=>{l[s]={description:c.description||"",accept:{}},c.mimeTypes?(s===0&&(e.type?c.mimeTypes.push(e.type):e.headers&&e.headers.get("content-type")&&c.mimeTypes.push(e.headers.get("content-type"))),c.mimeTypes.map(m=>{l[s].accept[m]=c.extensions||[]})):e.type&&(l[s].accept[e.type]=c.extensions||[])}),i)try{await i.getFile()}catch(c){if(i=null,r)throw c}let n=i||await window.showSaveFilePicker({suggestedName:t[0].fileName,id:t[0].id,startIn:t[0].startIn,types:l,excludeAcceptAllOption:t[0].excludeAcceptAllOption||!1}),a=await n.createWritable();return"stream"in e?(await e.stream().pipeTo(a),n):"body"in e?(await e.body.pipeTo(a),n):(await a.write(blob),await a.close(),n)}});var F=(()=>{if(typeof self=="undefined")return!1;if("top"in self&&self!==top)try{top.location+""}catch{return!1}else if("showOpenFilePicker"in self)return"showOpenFilePicker";return!1})(),u=F;var U=u?Promise.resolve().then(()=>(h(),w)):Promise.resolve().then(()=>(p(),y));async function _(...e){return(await U).default(...e)}var D=u?Promise.resolve().then(()=>(g(),x)):Promise.resolve().then(()=>(A(),o));async function O(...e){return(await D).default(...e)}var z=u?Promise.resolve().then(()=>(L(),j)):Promise.resolve().then(()=>(P(),k));async function C(...e){return(await z).default(...e)}export{O as directoryOpen,_ as fileOpen,C as fileSave,u as supported};
diff --git a/libs/lightfelt@ltgcgo/ext/binMatch.js b/libs/lightfelt@ltgcgo/ext/binMatch.js
new file mode 100644
index 00000000..86b496ba
--- /dev/null
+++ b/libs/lightfelt@ltgcgo/ext/binMatch.js
@@ -0,0 +1,113 @@
+"use strict";
+
+let compArr = function (a, b) {
+ let minL = Math.min(a.length, b.length),
+ c = a.slice(0, minL),
+ d = b.slice(0, minL);
+ let result = 0, pointer = 0;
+ while (pointer < minL && result == 0) {
+ result = Math.sign(c[pointer] - d[pointer]);
+ pointer ++;
+ };
+ return result;
+};
+
+let BinaryMatch = function (name = "") {
+ this.name = name;
+ this.pool = [];
+ this.point = function (prefix, insert = false) {
+ if (this.pool.length > 0) {
+ let bound = this.pool.length, // boundary
+ bs = 1 << Math.floor(Math.log2(bound)), // block size
+ pp = bs, // position pointer
+ ttl = 64; // time to live
+ // Binary search
+ while (bs >= 1 && ttl >= 0) {
+ // Status report
+ if (ttl <= 0) {
+ throw(new Error("TTL reached."));
+ };
+ if (pp == bound) {
+ pp -= bs;
+ } else {
+ let result = compArr(prefix, this.pool[pp]);
+ switch (result) {
+ case 0: {
+ ttl = 0;
+ break;
+ };
+ case 1: {
+ if (pp + bs <= bound) {
+ pp += bs;
+ };
+ break;
+ };
+ case -1: {
+ if (pp != 0) {
+ pp -= bs;
+ };
+ break;
+ };
+ default: {
+ console.warn(`Unexpected result ${result}.`);
+ };
+ };
+ };
+ bs = bs >> 1;
+ ttl --;
+ };
+ // After match
+ let match = true;
+ if (pp >= this.pool.length) {
+ match = false;
+ } else {
+ let upThis = this;
+ this.pool[pp].forEach(function (e, i, a) {
+ if (match) {
+ if (e != prefix[i]) {
+ match = false;
+ };
+ };
+ });
+ if (!match && compArr(prefix, this.pool[pp]) > 0) {
+ pp ++;
+ };
+ };
+ return (match || insert) ? pp : -1;
+ } else {
+ return insert ? 0 : -1;
+ };
+ };
+ this.add = function (prefix, data) {
+ prefix.data = data;
+ this.pool.splice(this.point(prefix, true), 0, prefix);
+ return this;
+ };
+ this.default = function (info) {
+ console.warn(`No match in "${this.name || '(unknown)'}" for "${info}". Default action not defined.`);
+ };
+ this.get = function (prefix) {
+ let idx = this.point(prefix);
+ if (idx > -1) {
+ return this.pool[idx].data;
+ } else {
+ this.default(prefix);
+ };
+ };
+ this.run = function (prefix, ...additional) {
+ let idx = this.point(prefix);
+ if (idx > -1) {
+ if (prefix.subarray) {
+ this.pool[idx].data(prefix.subarray(this.pool[idx].length), ...additional);
+ } else {
+ this.pool[idx].data(prefix.slice(this.pool[idx].length), ...additional);
+ };
+ } else {
+ this.default(prefix, ...additional);
+ };
+ };
+};
+
+export {
+ BinaryMatch
+};
diff --git a/libs/lightfelt@ltgcgo/ext/customEvents.js b/libs/lightfelt@ltgcgo/ext/customEvents.js
new file mode 100644
index 00000000..422b5568
--- /dev/null
+++ b/libs/lightfelt@ltgcgo/ext/customEvents.js
@@ -0,0 +1,44 @@
+"use strict";
+
+let CustomEventSource = class {
+ #eventListeners = {};
+ addEventListener(type, callback) {
+ if (!this.#eventListeners[type]) {
+ this.#eventListeners[type] = [];
+ };
+ this.#eventListeners[type].unshift(callback);
+ };
+ removeEventListener(type, callback) {
+ if (this.#eventListeners[type]) {
+ let index = this.#eventListeners[type].indexOf(callback);
+ if (index > -1) {
+ this.#eventListeners[type].splice(index, 1);
+ };
+ if (this.#eventListeners[type].length < 1) {
+ delete this.#eventListeners[type];
+ };
+ };
+ };
+ dispatchEvent(type, data) {
+ // Can add a proxy to allow stopping propagation
+ let eventObj = new Event(type),
+ upThis = this;
+ eventObj.data = data;
+ if (this.#eventListeners[type]?.length > 0) {
+ this.#eventListeners[type].forEach(function (e) {
+ try {
+ e?.call(upThis, eventObj);
+ } catch (err) {
+ console.error(err);
+ };
+ });
+ };
+ if (this[`on${type}`]) {
+ this[`on${type}`](eventObj);
+ };
+ };
+};
+
+export {
+ CustomEventSource
+};
diff --git a/libs/lightfelt@ltgcgo/ext/timedEvents.js b/libs/lightfelt@ltgcgo/ext/timedEvents.js
new file mode 100644
index 00000000..1caa2a45
--- /dev/null
+++ b/libs/lightfelt@ltgcgo/ext/timedEvents.js
@@ -0,0 +1,187 @@
+"use strict";
+
+let TimedEvent = class {
+ #ranged = false;
+ constructor (ranged, start, end, data) {
+ this.#ranged = ranged;
+ this.start = start;
+ this.end = end;
+ this.data = data;
+ };
+ get duration () {
+ if (this.ranged) {
+ return (this.end - this.start);
+ } else {
+ return 0;
+ };
+ };
+ get ranged () {
+ return this.#ranged;
+ };
+};
+let RangeEvent = class extends TimedEvent {
+ constructor (start, end, data) {
+ super(true, start, end, data);
+ };
+};
+let PointEvent = class extends TimedEvent {
+ constructor (start, data) {
+ super(false, start, start, data);
+ };
+};
+
+let TimedEvents = class extends Array {
+ #index = -1;
+ constructor() {
+ super(...arguments);
+ };
+ resetIndex(pointer) {
+ this.#index = -1;
+ };
+ fresh() {
+ this.sort(function (a, b) {
+ if (a.start == b.start) {
+ return 0
+ } else {
+ return (+(a.start > b.start) << 1) - 1;
+ };
+ });
+ this.forEach(function (e, i) {
+ e.index = i;
+ });
+ };
+ step(time, allowRepeat = false) {
+ // Optimizing required
+ let array = [];
+ if (allowRepeat) {
+ for (let index = 0; index < this.length; index ++) {
+ if (this[index].start > time) {
+ break;
+ } else if (this[index].end < time) {
+ continue;
+ } else {
+ array.push(this[index]);
+ };
+ };
+ } else {
+ let rawArray = this.getRange(this.#index == -1 ? 0 : (time - 1), time);
+ let upThis = this;
+ rawArray.forEach(function (e) {
+ if (e.index > upThis.#index) {
+ array.push(e);
+ upThis.#index = e.index;
+ };
+ });
+ };
+ return array;
+ };
+ getRange(start, end) {
+ if (start > end) {
+ [start, end] = [end, start];
+ };
+ // Must optimize
+ let array = [];
+ let index = -1, chunk = Math.ceil(Math.sqrt(this.length)), working = true;
+ for (let c = 0; c < this.length; c += chunk) {
+ // Chunk compare
+ if (this[c + chunk]) {
+ // Previous chunks
+ if (index < 0) {
+ if (this[c + chunk].start >= start) {
+ index = c;
+ } ;
+ };
+ } else {
+ // The last chunk
+ index = index < 0 ? c : index;
+ };
+ };
+ while (working) {
+ if (this[index]?.end < end) {
+ if (this[index].start >= start) {
+ array.push(this[index]);
+ };
+ } else {
+ working = false;
+ }
+ index ++;
+ };
+ return array;
+ };
+};
+
+export {
+ RangeEvent,
+ PointEvent,
+ TimedEvents
+};
+
+/*self.TimedEventsCollection = class extends self.Array {
+ #maxAllowedPointSpan = 1;
+ #lastTime = 0;
+ constructor () {
+ super(...arguments);
+ };
+ resetPointer (pointer) {
+ this.forEach(function (e) {
+ e.resetPointer(pointer);
+ });
+ };
+ finalize () {
+ this.forEach(function (e) {
+ e.finalize();
+ });
+ };
+ set pointSpan (value) {
+ value = Math.abs(value);
+ this.#maxAllowedPointSpan = value;
+ this.forEach(function (e) {
+ e.pointSpan = value;
+ });
+ return this.#maxAllowedPointSpan;
+ };
+ get pointSpan () {
+ return this.#maxAllowedPointSpan;
+ };
+ point (start) {
+ // Must optimize
+ let array = [], joined = new TimedEvents();
+ this.forEach(function (e) {
+ if (e.point) {
+ array.push(e.point(start));
+ };
+ });
+ array.forEach(function (e) {
+ e.forEach(function (e1) {
+ joined.push(e1);
+ });
+ });
+ joined.finalize();
+ return joined;
+ };
+ during (start, end) {
+ if (start == end) {
+ start = this.#lastTime;
+ };
+ if (start > end) {
+ [start, end] = [end, start];
+ };
+ // Must optimize
+ let array = [], joined = new TimedEvents();
+ this.forEach(function (e) {
+ if (e.during) {
+ array.push(e.during(start, end));
+ };
+ });
+ array.forEach(function (e) {
+ e.forEach(function (e1) {
+ joined.push(e1);
+ });
+ });
+ joined.finalize();
+ return joined;
+ };
+ at (time) {
+ return this.during((Math.abs(time - this.#lastTime > this.#maxAllowedPointSpan) ? time - this.#maxAllowedPointSpan : this.#lastTime), time);
+ };
+};*/
diff --git a/libs/lightfelt@ltgcgo/main/blobPlay.js b/libs/lightfelt@ltgcgo/main/blobPlay.js
new file mode 100644
index 00000000..0f83aa69
--- /dev/null
+++ b/libs/lightfelt@ltgcgo/main/blobPlay.js
@@ -0,0 +1,8 @@
+"use strict";
+
+{
+ let thrower = function (e) {
+ throw(e);
+ };
+ let fileReader = new FileReader();
+};
diff --git a/libs/lightfelt@ltgcgo/main/cssClass.js b/libs/lightfelt@ltgcgo/main/cssClass.js
new file mode 100644
index 00000000..fee4192d
--- /dev/null
+++ b/libs/lightfelt@ltgcgo/main/cssClass.js
@@ -0,0 +1,8 @@
+"use strict";
+
+DOMTokenList.prototype.on = function (classNme) {
+ !this.contains(classNme) && this.toggle(classNme);
+};
+DOMTokenList.prototype.off = function (classNme) {
+ this.contains(classNme) && this.toggle(classNme);
+};
diff --git a/libs/lightfelt@ltgcgo/main/quickPath.js b/libs/lightfelt@ltgcgo/main/quickPath.js
new file mode 100644
index 00000000..51bff140
--- /dev/null
+++ b/libs/lightfelt@ltgcgo/main/quickPath.js
@@ -0,0 +1,13 @@
+"use strict";
+
+let $e = function (selector, source = document) {
+ return source?.querySelector(selector);
+};
+let $a = function (selector, source = document) {
+ return Array.from(source?.querySelectorAll(selector));
+};
+
+export {
+ $e,
+ $a
+};
diff --git a/libs/midi-parser@colxi/main.min.js b/libs/midi-parser@colxi/main.min.js
new file mode 100644
index 00000000..a91a5f54
--- /dev/null
+++ b/libs/midi-parser@colxi/main.min.js
@@ -0,0 +1 @@
+!function(){"use strict";const tdo={fatal:true},tda=[new TextDecoder("iso-8859-15",tdo),new TextDecoder("sjis",tdo),new TextDecoder("euc-jp",tdo),new TextDecoder("utf-8",tdo),new TextDecoder("utf-16",tdo),new TextDecoder("ascii")];const n={debug:!1,parse:function(e,t){if(e instanceof Uint8Array)return n.Uint8(e);if("string"==typeof e)return n.Base64(e);if(e instanceof HTMLElement&&"file"===e.type)return n.addListener(e,t);throw new Error("MidiParser.parse() : Invalid input provided")},addListener:function(e,r){if(!File||!FileReader)throw new Error("The File|FileReader APIs are not supported in this browser. Use instead MidiParser.Base64() or MidiParser.Uint8()");if(void 0===e||!(e instanceof HTMLElement)||"INPUT"!==e.tagName||"file"!==e.type.toLowerCase())return console.warn("MidiParser.addListener() : Provided element is not a valid FILE INPUT element"),!1;r=r||function(){},e.addEventListener("change",function(e){if(!e.target.files.length)return!1;console.log("MidiParser.addListener() : File detected in INPUT ELEMENT processing data..");let t=new FileReader;t.readAsArrayBuffer(e.target.files[0]),t.onload=function(e){r(n.Uint8(new Uint8Array(e.target.result)))}})},Base64:function(e){let t=function(e){var t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";if(e=e.replace(/^.*?base64,/,""),e=String(e).replace(/[\t\n\f\r ]+/g,""),!/^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/.test(e))throw new TypeError("Failed to execute _atob() : The string to be decoded is not correctly encoded.");e+="==".slice(2-(3&e.length));let r,a="",n,i,d=0;for(;d>16&255):64===i?String.fromCharCode(r>>16&255,r>>8&255):String.fromCharCode(r>>16&255,r>>8&255,255&r);return a}(e=String(e));var r=t.length;let a=new Uint8Array(new ArrayBuffer(r));for(let e=0;e{r[i]=this.readInt(1)});for(let i=0;i191||P>127&&P<160){throw(new RangeError(`Invalid code point: ${P}`))}}};suc=true;console.debug(`String byte sequence in ${tda[i].encoding}`)}catch(err){console.debug(`SMF string ${err}`)}};};return txt||"String byte sequence read failed."},backOne:function(){this.pointer--;},readIntVLV:function(){let r=0;if(this.pointer>=this.data.byteLength)return-1;if(this.data.getUint8(this.pointer)<128)r=this.readInt(1);else{let t=[];for(;128<=this.data.getUint8(this.pointer);)t.push(this.readInt(1)-128);var e=this.readInt(1);for(let e=1;e<=t.length;e++)r+=t[t.length-e]*Math.pow(128,e);r+=e}return r}};if(i.data=new DataView(e.buffer,e.byteOffset,e.byteLength),1297377380!==i.readInt(4))return console.warn("Header validation failed (not MIDI standard or file corrupt.)"),!1;i.readInt(4);let d={};d.formatType=i.readInt(2),d.tracks=i.readInt(2),d.track=[];var e=i.readInt(1),t=i.readInt(1);128<=e?(d.timeDivision=[],d.timeDivision[0]=e-128,d.timeDivision[1]=t):d.timeDivision=256*e+t;for(let n=1;n<=d.tracks;n++){d.track[n-1]={event:[]};var s,o=i.readInt(4);if(-1===o)break;if(1297379947!==o)return!1;i.readInt(4);let e=0,t=!1,r,a;for(;!t&&(e++,d.track[n-1].event[e-1]={},d.track[n-1].event[e-1].deltaTime=i.readIntVLV(),-1!==(r=i.readInt(1)));)if(128<=r?a=r:(r=a,i.movePointer(-1)),255===r){d.track[n-1].event[e-1].type=255,d.track[n-1].event[e-1].metaType=i.readInt(1);var c=i.readIntVLV();switch(d.track[n-1].event[e-1].metaType){case 47:case-1:t=!0;break;case 1:case 2:case 3:case 4:case 5:case 7:case 6:d.track[n-1].event[e-1].data=i.readStr(c);break;case 33:case 89:case 81:d.track[n-1].event[e-1].data=i.readInt(c);break;case 84:d.track[n-1].event[e-1].data=[],d.track[n-1].event[e-1].data[0]=i.readInt(1),d.track[n-1].event[e-1].data[1]=i.readInt(1),d.track[n-1].event[e-1].data[2]=i.readInt(1),d.track[n-1].event[e-1].data[3]=i.readInt(1),d.track[n-1].event[e-1].data[4]=i.readInt(1);break;case 88:d.track[n-1].event[e-1].data=[],d.track[n-1].event[e-1].data[0]=i.readInt(1),d.track[n-1].event[e-1].data[1]=i.readInt(1),d.track[n-1].event[e-1].data[2]=i.readInt(1),d.track[n-1].event[e-1].data[3]=i.readInt(1);break;default:null!==this.customInterpreter&&(d.track[n-1].event[e-1].data=this.customInterpreter(d.track[n-1].event[e-1].metaType,i,c)),null!==this.customInterpreter&&!1!==d.track[n-1].event[e-1].data||(i.readInt(c),d.track[n-1].event[e-1].data=i.readInt(c),this.debug&&console.info("Unimplemented 0xFF meta event! data block readed as Integer"))}}else switch((r=r.toString(16).split(""))[1]||r.unshift("0"),d.track[n-1].event[e-1].type=parseInt(r[0],16),d.track[n-1].event[e-1].channel=parseInt(r[1],16),d.track[n-1].event[e-1].type){case 15:null!==this.customInterpreter&&(d.track[n-1].event[e-1].data=this.customInterpreter(d.track[n-1].event[e-1].type,i,!1)),null!==this.customInterpreter&&!1!==d.track[n-1].event[e-1].data||(s=i.readIntVLV(),d.track[n-1].event[e-1].data=i.readInt(s),this.debug&&console.info("Unimplemented 0xF exclusive events! data block readed as Integer"));break;case 10:case 11:case 14:case 8:case 9:d.track[n-1].event[e-1].data=[],d.track[n-1].event[e-1].data[0]=i.readInt(1),d.track[n-1].event[e-1].data[1]=i.readInt(1);break;case 12:case 13:d.track[n-1].event[e-1].data=i.readInt(1);break;case-1:t=!0;break;default:if(null!==this.customInterpreter&&(d.track[n-1].event[e-1].data=this.customInterpreter(d.track[n-1].event[e-1].metaType,i,!1)),null===this.customInterpreter||!1===d.track[n-1].event[e-1].data)return console.log("Unknown EVENT detected... reading cancelled!"),!1}}return d},customInterpreter:null};if("undefined"!=typeof module)module.exports=n;else{let e="object"==typeof window&&window.self===window&&window||"object"==typeof self&&self.self===self&&self||"object"==typeof global&&global.global===global&&global;e.MidiParser=n}}();
diff --git a/libs/snowy@ltgcgo/bc.js b/libs/snowy@ltgcgo/bc.js
new file mode 100644
index 00000000..9a7192ef
--- /dev/null
+++ b/libs/snowy@ltgcgo/bc.js
@@ -0,0 +1 @@
+"use strict";(function(){var d=function(s,a,t){var n;var i;if(self.MessageEvent)switch(s){case"message":{i=new MessageEvent(s,{data:a,ports:t==null?void 0:t.ports}),Object.defineProperty(i,"source",{value:t==null?void 0:t.source});break}default:i=new Event(s)}else i=document.createEvent("Event"),i.initEvent(s,!1,!1),t&&s=="message"&&(i.data=a,t.source&&Object.defineProperty(i,"source",{value:t.source}),(n=t.ports)!=null&&n.length&&Object.defineProperty(i,"ports",{value:t.ports}));return i};self.BroadcastChannel?console.info("[Snowy] Snowy is disabled."):(console.info("[Snowy] Snowy is enabled. Path: ".concat(self.SNOWY_PATH||"/snowy.js")),h=[],c={},E=function(s){var b;var a=this;if((this==null?void 0:this.constructor)!=E)throw new TypeError("Illegal constructor");h.push(this),(b=c[s])!=null&&b.constructor||(c[s]=[]),c[s].push(this);var t=Math.floor(Math.random()*281474976710656),i=[],n=0,u=[],g=!0,w=!1;Object.defineProperty(this,"id",{get:function(){return t}}),Object.defineProperty(this,"name",{value:s}),this.close=function(){var o;var e=h.indexOf(a);e>-1?(f.postMessage({t:"d",c:s,i:t}),h.splice(e,1),(o=c[s])!=null&&o.constructor&&(e=c[s].indexOf(a),e>-1&&c[s].splice(e,1)),c[s].length||delete c[s],console.debug("[Snowy] BroadcastChannel closed."),w=!0):console.debug("[Snowy] BroadcastChannel already closed.")},this.postMessage=function(e){if(f){if(w)throw new Error("Channel already closed");f.postMessage({t:"m",c:s,i:t,m:n,d:e}),n++,n>4294967295&&(n=0)}else u.push(e),console.debug("[Snowy] Message is cached.")},this.flush=function(){if(f){if(g){for(f.postMessage({t:"r",c:s,i:t}),console.debug("[Snowy] ".concat(u.length," message(s) in cache."));u.length;){var e=u.shift();a.postMessage(e)}g=!1,console.debug("[Snowy] All cached messages are flushed away.")}}else throw new Error("Tried to flush when the ports are not ready")},this.receiveMessage=function(e){e.c==s?e.i!=t&&a.dispatchEvent(d("message",e.d,{source:a})):console.debug("[Snowy] Channel ID mismatch. Instance ".concat(t," receives from ").concat(s,", not ").concat(e.c,"."))};var r={};this.dispatchEvent=function(e){var v,y;if(Object.defineProperty(e,"target",{value:a}),Object.defineProperty(e,"currentTarget",{value:a}),(v=r[e.type])!=null&&v.length)for(var o=r[e.type],l=0;l-1&&r[e].splice(l,1)}!((y=r[e])!=null&&y.length)&&r[e].constructor&&delete r[e]}},self.BroadcastChannel=E,M=function(){if(f){f.addEventListener("message",function(a){var t=a.data,i=!1;switch(t.t){case"k":{i=!1,f.postMessage({t:"k"});break}case"m":{var n=c[t.c];if(n!=null&&n.length)for(var u=0;u-1&&r[o].splice(c,1),r[o].length||delete r[o]}if((f=e==null?void 0:e.ch)!=null&&f.constructor){var c=e.ch.indexOf(o);c>-1&&e.ch.splice(c,1)}console.debug("[Snowy] Unsubscribed tab from channel ".concat(o,"."))};addEventListener("connect",function(o){var e=o.source;e.postMessage({t:"swc"}),e.onmessage=function(c){var i,t;var s=c.data,f=!0;switch(s.t){case"k":{var g=a.indexOf(e);for(g<0&&a.push(e),e.lastKa=Date.now();(i=s==null?void 0:s.c)!=null&&i.length;){var d=s.c.pop();u(d,e)}f=!1;break}case"m":{for(var n=0;n<((t=r[s.c])==null?void 0:t.length);n++)r[s.c][n].postMessage(s);break}case"r":{u(s.c,e);break}case"d":{v(s.c,e);break}default:console.error('[Snowy] Unknown message type "'.concat(s.t,'"'))}f&&console.info("SharedWorkerMessage",s)}});setInterval(function(){var f;for(var o=a.length-1;o>=0;o--){var e=a[o];e.postMessage({t:"k"});var c=Date.now();if(e.lastKa+hfooter{font-style:normal;border:0}address,blockquote cite{font-style:normal}a[href^=mailto\:]:before{content:"📧 "}a[href^=tel\:]:before{content:"📞 "}a[href^=sms\:]:before{content:"💬 "}mark{background-color:#ff0;background-color:var(--highlight);border-radius:2px;padding:0 2px;color:#000}@media (prefers-color-scheme:dark){mark{background-color:#efdb43;background-color:var(--highlight)}}a>code,a>strong{color:inherit}button,input[type=button],input[type=checkbox],input[type=radio],input[type=range],input[type=reset],input[type=submit],select{cursor:pointer}input,select{display:block}[type=checkbox],[type=radio]{display:initial}input{color:#1d1d1d;color:var(--form-text);background-color:#efefef;background-color:var(--background);font-family:inherit;font-size:inherit;margin-right:6px;margin-bottom:6px;padding:10px;border:none;border-radius:6px;outline:none}@media (prefers-color-scheme:dark){input{background-color:#161f27;background-color:var(--background);color:#fff;color:var(--form-text)}}button{color:#1d1d1d;color:var(--form-text);background-color:#efefef;background-color:var(--background);font-family:inherit;font-size:inherit;margin-right:6px;margin-bottom:6px;padding:10px;border:none;border-radius:6px;outline:none}@media (prefers-color-scheme:dark){button{background-color:#161f27;background-color:var(--background);color:#fff;color:var(--form-text)}}textarea{color:#1d1d1d;color:var(--form-text);background-color:#efefef;background-color:var(--background);font-family:inherit;font-size:inherit;margin-right:6px;margin-bottom:6px;padding:10px;border:none;border-radius:6px;outline:none}@media (prefers-color-scheme:dark){textarea{background-color:#161f27;background-color:var(--background);color:#fff;color:var(--form-text)}}select{color:#1d1d1d;color:var(--form-text);background-color:#efefef;background-color:var(--background);font-family:inherit;font-size:inherit;margin-right:6px;margin-bottom:6px;padding:10px;border:none;border-radius:6px;outline:none}@media (prefers-color-scheme:dark){select{background-color:#161f27;background-color:var(--background);color:#fff;color:var(--form-text)}}button{background-color:#d0cfcf;background-color:var(--button-base);padding-right:30px;padding-left:30px}@media (prefers-color-scheme:dark){button{background-color:#0c151c;background-color:var(--button-base)}}input[type=submit]{background-color:#d0cfcf;background-color:var(--button-base);padding-right:30px;padding-left:30px}@media (prefers-color-scheme:dark){input[type=submit]{background-color:#0c151c;background-color:var(--button-base)}}input[type=reset]{background-color:#d0cfcf;background-color:var(--button-base);padding-right:30px;padding-left:30px}@media (prefers-color-scheme:dark){input[type=reset]{background-color:#0c151c;background-color:var(--button-base)}}input[type=button]{background-color:#d0cfcf;background-color:var(--button-base);padding-right:30px;padding-left:30px}@media (prefers-color-scheme:dark){input[type=button]{background-color:#0c151c;background-color:var(--button-base)}}button:hover{background:#9b9b9b;background:var(--button-hover)}@media (prefers-color-scheme:dark){button:hover{background:#040a0f;background:var(--button-hover)}}input[type=submit]:hover{background:#9b9b9b;background:var(--button-hover)}@media (prefers-color-scheme:dark){input[type=submit]:hover{background:#040a0f;background:var(--button-hover)}}input[type=reset]:hover{background:#9b9b9b;background:var(--button-hover)}@media (prefers-color-scheme:dark){input[type=reset]:hover{background:#040a0f;background:var(--button-hover)}}input[type=button]:hover{background:#9b9b9b;background:var(--button-hover)}@media (prefers-color-scheme:dark){input[type=button]:hover{background:#040a0f;background:var(--button-hover)}}input[type=color]{min-height:2rem;padding:8px;cursor:pointer}input[type=checkbox],input[type=radio]{height:1em;width:1em}input[type=radio]{border-radius:100%}input{vertical-align:top}label{vertical-align:middle;margin-bottom:4px;display:inline-block}button,input:not([type=checkbox]):not([type=radio]),input[type=range],select,textarea{-webkit-appearance:none}textarea{display:block;margin-right:0;box-sizing:border-box;resize:vertical}textarea:not([cols]){width:100%}textarea:not([rows]){min-height:40px;height:140px}select{background:#efefef url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' height='63' width='117' fill='%23161f27'%3E%3Cpath d='M115 2c-1-2-4-2-5 0L59 53 7 2a4 4 0 00-5 5l54 54 2 2 3-2 54-54c2-1 2-4 0-5z'/%3E%3C/svg%3E") calc(100% - 12px) 50%/12px no-repeat;background:var(--background) var(--select-arrow) calc(100% - 12px) 50%/12px no-repeat;padding-right:35px}@media (prefers-color-scheme:dark){select{background:#161f27 url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' height='63' width='117' fill='%23efefef'%3E%3Cpath d='M115 2c-1-2-4-2-5 0L59 53 7 2a4 4 0 00-5 5l54 54 2 2 3-2 54-54c2-1 2-4 0-5z'/%3E%3C/svg%3E") calc(100% - 12px) 50%/12px no-repeat;background:var(--background) var(--select-arrow) calc(100% - 12px) 50%/12px no-repeat}}select::-ms-expand{display:none}select[multiple]{padding-right:10px;background-image:none;overflow-y:auto}input:focus{box-shadow:0 0 0 2px rgba(0,150,191,.67);box-shadow:0 0 0 2px var(--focus)}@media (prefers-color-scheme:dark){input:focus{box-shadow:0 0 0 2px rgba(0,150,191,.67);box-shadow:0 0 0 2px var(--focus)}}select:focus{box-shadow:0 0 0 2px rgba(0,150,191,.67);box-shadow:0 0 0 2px var(--focus)}@media (prefers-color-scheme:dark){select:focus{box-shadow:0 0 0 2px rgba(0,150,191,.67);box-shadow:0 0 0 2px var(--focus)}}button:focus{box-shadow:0 0 0 2px rgba(0,150,191,.67);box-shadow:0 0 0 2px var(--focus)}@media (prefers-color-scheme:dark){button:focus{box-shadow:0 0 0 2px rgba(0,150,191,.67);box-shadow:0 0 0 2px var(--focus)}}textarea:focus{box-shadow:0 0 0 2px rgba(0,150,191,.67);box-shadow:0 0 0 2px var(--focus)}@media (prefers-color-scheme:dark){textarea:focus{box-shadow:0 0 0 2px rgba(0,150,191,.67);box-shadow:0 0 0 2px var(--focus)}}button:active,input[type=button]:active,input[type=checkbox]:active,input[type=radio]:active,input[type=range]:active,input[type=reset]:active,input[type=submit]:active{transform:translateY(2px)}button:disabled,input:disabled,select:disabled,textarea:disabled{cursor:not-allowed;opacity:.5}::-moz-placeholder{color:#949494;color:var(--form-placeholder)}:-ms-input-placeholder{color:#949494;color:var(--form-placeholder)}::-ms-input-placeholder{color:#949494;color:var(--form-placeholder)}::placeholder{color:#949494;color:var(--form-placeholder)}@media (prefers-color-scheme:dark){::-moz-placeholder{color:#a9a9a9;color:var(--form-placeholder)}:-ms-input-placeholder{color:#a9a9a9;color:var(--form-placeholder)}::-ms-input-placeholder{color:#a9a9a9;color:var(--form-placeholder)}::placeholder{color:#a9a9a9;color:var(--form-placeholder)}}fieldset{border:1px solid rgba(0,150,191,.67);border:1px solid var(--focus);border-radius:6px;margin:0 0 12px;padding:10px}@media (prefers-color-scheme:dark){fieldset{border:1px solid rgba(0,150,191,.67);border:1px solid var(--focus)}}legend{font-size:.9em;font-weight:600}input[type=range]{margin:10px 0;padding:10px 0;background:transparent}input[type=range]:focus{outline:none}input[type=range]::-webkit-slider-runnable-track{width:100%;height:9.5px;-webkit-transition:.2s;transition:.2s;background:#efefef;background:var(--background);border-radius:3px}@media (prefers-color-scheme:dark){input[type=range]::-webkit-slider-runnable-track{background:#161f27;background:var(--background)}}input[type=range]::-webkit-slider-thumb{box-shadow:0 1px 1px #000,0 0 1px #0d0d0d;height:20px;width:20px;border-radius:50%;background:#dbdbdb;background:var(--border);-webkit-appearance:none;margin-top:-7px}@media (prefers-color-scheme:dark){input[type=range]::-webkit-slider-thumb{background:#526980;background:var(--border)}}input[type=range]:focus::-webkit-slider-runnable-track{background:#efefef;background:var(--background)}@media (prefers-color-scheme:dark){input[type=range]:focus::-webkit-slider-runnable-track{background:#161f27;background:var(--background)}}input[type=range]::-moz-range-track{width:100%;height:9.5px;-moz-transition:.2s;transition:.2s;background:#efefef;background:var(--background);border-radius:3px}@media (prefers-color-scheme:dark){input[type=range]::-moz-range-track{background:#161f27;background:var(--background)}}input[type=range]::-moz-range-thumb{box-shadow:1px 1px 1px #000,0 0 1px #0d0d0d;height:20px;width:20px;border-radius:50%;background:#dbdbdb;background:var(--border)}@media (prefers-color-scheme:dark){input[type=range]::-moz-range-thumb{background:#526980;background:var(--border)}}input[type=range]::-ms-track{width:100%;height:9.5px;background:transparent;border-color:transparent;border-width:16px 0;color:transparent}input[type=range]::-ms-fill-lower{background:#efefef;background:var(--background);border:.2px solid #010101;border-radius:3px;box-shadow:1px 1px 1px #000,0 0 1px #0d0d0d}@media (prefers-color-scheme:dark){input[type=range]::-ms-fill-lower{background:#161f27;background:var(--background)}}input[type=range]::-ms-fill-upper{background:#efefef;background:var(--background);border:.2px solid #010101;border-radius:3px;box-shadow:1px 1px 1px #000,0 0 1px #0d0d0d}@media (prefers-color-scheme:dark){input[type=range]::-ms-fill-upper{background:#161f27;background:var(--background)}}input[type=range]::-ms-thumb{box-shadow:1px 1px 1px #000,0 0 1px #0d0d0d;border:1px solid #000;height:20px;width:20px;border-radius:50%;background:#dbdbdb;background:var(--border)}@media (prefers-color-scheme:dark){input[type=range]::-ms-thumb{background:#526980;background:var(--border)}}input[type=range]:focus::-ms-fill-lower{background:#efefef;background:var(--background)}@media (prefers-color-scheme:dark){input[type=range]:focus::-ms-fill-lower{background:#161f27;background:var(--background)}}input[type=range]:focus::-ms-fill-upper{background:#efefef;background:var(--background)}@media (prefers-color-scheme:dark){input[type=range]:focus::-ms-fill-upper{background:#161f27;background:var(--background)}}a{text-decoration:none;color:#0076d1;color:var(--links)}@media (prefers-color-scheme:dark){a{color:#41adff;color:var(--links)}}a:hover{text-decoration:underline}code{background:#efefef;background:var(--background);color:#000;color:var(--code);padding:2.5px 5px;border-radius:6px;font-size:1em}@media (prefers-color-scheme:dark){code{color:#ffbe85;color:var(--code);background:#161f27;background:var(--background)}}samp{background:#efefef;background:var(--background);color:#000;color:var(--code);padding:2.5px 5px;border-radius:6px;font-size:1em}@media (prefers-color-scheme:dark){samp{color:#ffbe85;color:var(--code);background:#161f27;background:var(--background)}}time{background:#efefef;background:var(--background);color:#000;color:var(--code);padding:2.5px 5px;border-radius:6px;font-size:1em}@media (prefers-color-scheme:dark){time{color:#ffbe85;color:var(--code);background:#161f27;background:var(--background)}}pre>code{padding:10px;display:block;overflow-x:auto}var{color:#39a33c;color:var(--variable);font-style:normal;font-family:monospace}@media (prefers-color-scheme:dark){var{color:#d941e2;color:var(--variable)}}kbd{background:#efefef;background:var(--background);border:1px solid #dbdbdb;border:1px solid var(--border);border-radius:2px;color:#363636;color:var(--text-main);padding:2px 4px}@media (prefers-color-scheme:dark){kbd{color:#dbdbdb;color:var(--text-main);border:1px solid #526980;border:1px solid var(--border);background:#161f27;background:var(--background)}}img,video{max-width:100%;height:auto}hr{border:none;border-top:1px solid #dbdbdb;border-top:1px solid var(--border)}@media (prefers-color-scheme:dark){hr{border-top:1px solid #526980;border-top:1px solid var(--border)}}table{border-collapse:collapse;margin-bottom:10px;width:100%;table-layout:fixed}table caption,td,th{text-align:left}td,th{padding:6px;vertical-align:top;word-wrap:break-word}thead{border-bottom:1px solid #dbdbdb;border-bottom:1px solid var(--border)}@media (prefers-color-scheme:dark){thead{border-bottom:1px solid #526980;border-bottom:1px solid var(--border)}}tfoot{border-top:1px solid #dbdbdb;border-top:1px solid var(--border)}@media (prefers-color-scheme:dark){tfoot{border-top:1px solid #526980;border-top:1px solid var(--border)}}tbody tr:nth-child(2n){background-color:#efefef;background-color:var(--background)}@media (prefers-color-scheme:dark){tbody tr:nth-child(2n){background-color:#161f27;background-color:var(--background)}}tbody tr:nth-child(2n) button{background-color:#f7f7f7;background-color:var(--background-alt)}@media (prefers-color-scheme:dark){tbody tr:nth-child(2n) button{background-color:#1a242f;background-color:var(--background-alt)}}tbody tr:nth-child(2n) button:hover{background-color:#fff;background-color:var(--background-body)}@media (prefers-color-scheme:dark){tbody tr:nth-child(2n) button:hover{background-color:#202b38;background-color:var(--background-body)}}::-webkit-scrollbar{height:10px;width:10px}::-webkit-scrollbar-track{background:#efefef;background:var(--background);border-radius:6px}@media (prefers-color-scheme:dark){::-webkit-scrollbar-track{background:#161f27;background:var(--background)}}::-webkit-scrollbar-thumb{background:#aaa;background:var(--scrollbar-thumb);border-radius:6px}@media (prefers-color-scheme:dark){::-webkit-scrollbar-thumb{background:#040a0f;background:var(--scrollbar-thumb)}}::-webkit-scrollbar-thumb:hover{background:#9b9b9b;background:var(--scrollbar-thumb-hover)}@media (prefers-color-scheme:dark){::-webkit-scrollbar-thumb:hover{background:#000;background:var(--scrollbar-thumb-hover)}}::-moz-selection{background-color:#9e9e9e;background-color:var(--selection);color:#000;color:var(--text-bright)}::selection{background-color:#9e9e9e;background-color:var(--selection);color:#000;color:var(--text-bright)}@media (prefers-color-scheme:dark){::-moz-selection{color:#fff;color:var(--text-bright)}::selection{color:#fff;color:var(--text-bright)}}@media (prefers-color-scheme:dark){::-moz-selection{background-color:#1c76c5;background-color:var(--selection)}::selection{background-color:#1c76c5;background-color:var(--selection)}}details{display:flex;flex-direction:column;align-items:flex-start;background-color:#f7f7f7;background-color:var(--background-alt);padding:10px 10px 0;margin:1em 0;border-radius:6px;overflow:hidden}@media (prefers-color-scheme:dark){details{background-color:#1a242f;background-color:var(--background-alt)}}details[open]{padding:10px}details>:last-child{margin-bottom:0}details[open] summary{margin-bottom:10px}summary{display:list-item;background-color:#efefef;background-color:var(--background);padding:10px;margin:-10px -10px 0;cursor:pointer;outline:none}@media (prefers-color-scheme:dark){summary{background-color:#161f27;background-color:var(--background)}}summary:focus,summary:hover{text-decoration:underline}details>:not(summary){margin-top:0}summary::-webkit-details-marker{color:#363636;color:var(--text-main)}@media (prefers-color-scheme:dark){summary::-webkit-details-marker{color:#dbdbdb;color:var(--text-main)}}dialog{background-color:#f7f7f7;background-color:var(--background-alt);color:#363636;color:var(--text-main);border-radius:6px;border:#dbdbdb;border-color:var(--border);padding:10px 30px}@media (prefers-color-scheme:dark){dialog{border-color:#526980;border-color:var(--border);color:#dbdbdb;color:var(--text-main);background-color:#1a242f;background-color:var(--background-alt)}}dialog>header:first-child{background-color:#efefef;background-color:var(--background);border-radius:6px 6px 0 0;margin:-10px -30px 10px;padding:10px;text-align:center}@media (prefers-color-scheme:dark){dialog>header:first-child{background-color:#161f27;background-color:var(--background)}}dialog::-webkit-backdrop{background:rgba(0,0,0,.61);-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}dialog::backdrop{background:rgba(0,0,0,.61);-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}footer{border-top:1px solid #dbdbdb;border-top:1px solid var(--border);padding-top:10px;color:#70777f;color:var(--text-muted)}@media (prefers-color-scheme:dark){footer{color:#a9b1ba;color:var(--text-muted);border-top:1px solid #526980;border-top:1px solid var(--border)}}body>footer{margin-top:40px}@media print{body,button,code,details,input,pre,summary,textarea{background-color:#fff}button,input,textarea{border:1px solid #000}body,button,code,footer,h1,h2,h3,h4,h5,h6,input,pre,strong,summary,textarea{color:#000}summary::marker{color:#000}summary::-webkit-details-marker{color:#000}tbody tr:nth-child(2n){background-color:#f2f2f2}a{color:#00f;text-decoration:underline}}
diff --git a/sh/build.sh b/sh/build.sh
new file mode 100644
index 00000000..a77a0073
--- /dev/null
+++ b/sh/build.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+mkdir -p dist
+#mkdir -p proxy
+# Remove the dev files
+rm -r dist/*.js
+rm -r dist/*.map
+rm -r dist/*.mjs
+# Using esbuild to build all JS files
+#esbuild --bundle src/index.js --outfile=dist/index.js --minify --sourcemap
+#esbuild --bundle src/index.js --target=es6 --outfile=dist/index.es6.js --minify --sourcemap
+ls -1 src | while IFS= read -r dir ; do
+ if [ -e "src/${dir}/index.js" ] ; then
+ shx live $dir --minify $1 > /dev/null
+ fi
+ if [ -e "src/${dir}/index.mjs" ] ; then
+ shx live $dir --minify $1 > /dev/null
+ fi
+done
+#rm -rv proxy/*.map
+# Finalizing most builds
+#ls -1 src | while IFS= read -r dir ; do
+ #if [ -e "src/${dir}/prefixer.js" ] ; then
+ #cat src/${dir}/prefixer.js > dist/${dir}.js
+ #fi
+ #if [ -e "proxy/${dir}.js" ] ; then
+ #cat proxy/${dir}.js >> dist/${dir}.js
+ #fi
+#done
+# Node specific
+#mkdir -p proxy/node
+#mv dist/node.js proxy/node/index.js
+#rm proxy/node.js
+exit
diff --git a/sh/commit.sh b/sh/commit.sh
new file mode 100644
index 00000000..9aed7ea9
--- /dev/null
+++ b/sh/commit.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+git stage -A && git commit && git push
+exit
diff --git a/sh/denoServe b/sh/denoServe
new file mode 100755
index 00000000..1fcd2c4b
--- /dev/null
+++ b/sh/denoServe
@@ -0,0 +1,4 @@
+#!/bin/bash
+args=( "$@" )
+deno run --allow-net --allow-read deno/std/http/file_server.js ${args[@]}
+exit
\ No newline at end of file
diff --git a/sh/denoTest.sh b/sh/denoTest.sh
new file mode 100644
index 00000000..b039de4b
--- /dev/null
+++ b/sh/denoTest.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+export BACKENDS=browserleaks.com
+export DEBUGGER=1
+export FOLLOW_REDIR=1
+export FORCE_OUT_TLS=plain
+export STRIP_HEADERS_UP=Sec-Fetch-User,Sec-Fetch-Site,Sec-Fetch-Mode,Sec-Fetch-Dest
+export STRIP_HEADERS=expect-ct,nel,report-to
+export SET_HEADERS_UP=upgrade-insecure-requests=1
+export SET_HEADERS=x-cloudhop-debug=experimental
+export HEALTH_MAX_TRIES=4
+export HEALTH_CRITERIA=loose
+export MASK_UA=noBracket
+export MASK_IP=spoof
+export MATCH_LANG=en-US,en,*
+export TIMEOUT_MS=4000
+export IDLE_SHUTDOWN=0
+deno run --allow-net --allow-env dist/deno.js
+exit
\ No newline at end of file
diff --git a/sh/esbuild b/sh/esbuild
new file mode 100755
index 00000000..54d4dea0
--- /dev/null
+++ b/sh/esbuild
@@ -0,0 +1,4 @@
+#!/bin/bash
+args=( "$@" )
+deno run --allow-env --allow-net --allow-read --allow-write --allow-run deno/esbuild/mod.js ${args[@]}
+exit
\ No newline at end of file
diff --git a/sh/live.sh b/sh/live.sh
new file mode 100644
index 00000000..0876489e
--- /dev/null
+++ b/sh/live.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+#rm -rv dist/${1:default}*
+inject=" "
+prepend=" "
+append=" "
+buildOpt=" "
+format="iife"
+ext="js"
+if [ -e "src/${1:-default}/inject.js" ] ; then
+ inject="--inject:src/${1:-default}/inject.js"
+fi
+if [ -e "src/${1:-default}/buildOpt.txt" ] ; then
+ buildOpt="$(cat src/${1:-default}/buildOpt.txt)"
+fi
+if [ -e "src/${1:-default}/prefix.js" ] ; then
+ prepend="--prepend:src/${1:-default}/prefix.js"
+fi
+if [ -e "src/${1:-default}/affix.js" ] ; then
+ append="--append:src/${1:-default}/affix.js"
+fi
+if [ -e "src/${1:-default}/.node" ] ; then
+ platform="--platform=node"
+fi
+if [ -e "src/${1:-default}/.cjs" ] ; then
+ format="cjs"
+fi
+if [ -e "src/${1:-default}/index.mjs" ] ; then
+ format="esm"
+ ext="mjs"
+fi
+esbuild --bundle src/${1:-default}/index.${ext} $platform $prepend $append $inject $buildOpt --format=$format --charset=utf8 --outfile=dist/${1:-default}.${ext} ${2:---minify-whitespace --minify-syntax --sourcemap --watch} $3
+#cat proxy/${1:-default}.js
+exit
diff --git a/sh/push.sh b/sh/push.sh
new file mode 100644
index 00000000..2fed183a
--- /dev/null
+++ b/sh/push.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+shx build
+shx commit
+exit
\ No newline at end of file
diff --git a/sh/sitemap.sh b/sh/sitemap.sh
new file mode 100644
index 00000000..5aebe8ff
--- /dev/null
+++ b/sh/sitemap.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+domain=$(cat conf/domain.txt)
+printf '' > ghp/sitemap.xml
+cat conf/sitemap.txt | while IFS= read -r path ; do
+ printf "${domain}${path//index.htm/} $(date -u '+%Y-%m-%d %H:%M:%S' -r .${path}) " >> ghp/sitemap.xml
+done
+printf ' ' >> ghp/sitemap.xml
+exit
\ No newline at end of file
diff --git a/sh/srcMap.sh b/sh/srcMap.sh
new file mode 100644
index 00000000..9367d255
--- /dev/null
+++ b/sh/srcMap.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+cd test/js
+ls -1 ../../dist/*js | while IFS= read -r file; do
+ ln -s "$file"
+ ln -s "$file".map
+done
+exit
\ No newline at end of file
diff --git a/sh/updateDeno.sh b/sh/updateDeno.sh
new file mode 100644
index 00000000..8506a5d8
--- /dev/null
+++ b/sh/updateDeno.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+cd deno
+cat ../conf/denoDeps.txt | while IFS= read -r depLine; do
+ IFS=" " read -ra depSrc <<< $depLine
+ case "${depSrc[0]}" in
+ "dir")
+ printf "Directory: ${depSrc[1]}... "
+ mkdir -p "${depSrc[1]}"
+ echo "OK."
+ ;;
+ *)
+ printf "Downloading \"${depSrc[0]}\" from \"${depSrc[1]}\"... "
+ #curl -Lso "${depSrc[0]}" "${depSrc[1]}"
+ deno bundle "${depSrc[1]}" "${depSrc[0]}"
+ echo "OK."
+ ;;
+ esac
+done
+echo "Deno dependency fetching complete."
+exit
diff --git a/sh/web.sh b/sh/web.sh
new file mode 100644
index 00000000..3b98db76
--- /dev/null
+++ b/sh/web.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+#cd test
+cd ..
+case "$1" in
+ "deno")
+ denoServe -p 8010
+ ;;
+ *)
+ python3 -m http.server 8010
+ ;;
+esac
+exit
\ No newline at end of file
diff --git a/shx b/shx
new file mode 100755
index 00000000..cb23d2c7
--- /dev/null
+++ b/shx
@@ -0,0 +1,20 @@
+#!/bin/bash
+arg="$@"
+args=( "$@" )
+if [ "$arg" == "" ] ; then
+ echo "All available actions:"
+ ls -1 sh | while IFS= read -r file; do
+ echo "${file/.sh/}"
+ done
+ exit
+fi
+if [ -e "sh/$1.sh" ] ; then
+ export PATH=./:./sh/:$PATH
+ bash "sh/$1.sh" "${args[@]:1}"
+elif [ -e "sh/$1" ] ; then
+ export PATH=./:./sh/:$PATH
+ bash "sh/$1" "${args[@]:1}"
+else
+ echo "No action found as \"$1\". Command: \"${args[@]:1}\"".
+fi
+exit
diff --git a/src/basic/index.mjs b/src/basic/index.mjs
new file mode 100644
index 00000000..090b2eb3
--- /dev/null
+++ b/src/basic/index.mjs
@@ -0,0 +1,261 @@
+"use strict";
+
+import {CustomEventSource} from "../../libs/lightfelt@ltgcgo/ext/customEvents.js";
+import {ccToPos, dnToPos} from "../state/index.mjs";
+import MidiParser from "../../libs/midi-parser@colxi/main.min.js";
+import {rawToPool} from "./transform.js";
+import {customInterpreter} from "../state/utils.js";
+
+MidiParser.customInterpreter = customInterpreter;
+
+let RootDisplay = class extends CustomEventSource {
+ device;
+ #midiPool;
+ #titleName = "";
+ #metaRun = [];
+ #mimicStrength = new Uint8ClampedArray(128);
+ #beforeStrength = new Uint8ClampedArray(128);
+ // Used to provide tempo, tSig and bar information
+ #noteBInt = 0.5;
+ #noteTempo = 120;
+ #noteNomin = 4;
+ #noteDenom = 4;
+ #noteBarOffset = 0;
+ #noteTime = 0;
+ smoothingAtk = 0;
+ smoothingDcy = 0;
+ reset() {
+ // Dispatching the event
+ this.dispatchEvent("reset");
+ // Clearing all MIDI instructions up
+ this.#midiPool?.resetIndex();
+ // And set all controllers to blank
+ this.device.init();
+ // Clear titleName
+ this.#titleName = "";
+ // Timing info reset;
+ this.#noteBInt = 0.5;
+ this.#noteTempo = 120;
+ this.#noteNomin = 4;
+ this.#noteDenom = 4;
+ this.#noteBarOffset = 0;
+ this.#noteTime = 0;
+ };
+ async loadFile(blob) {
+ this.#midiPool = rawToPool(MidiParser.parse(new Uint8Array(await blob.arrayBuffer())));
+ };
+ switchMode(modeName, forced = false) {
+ this.device.switchMode(modeName, forced);
+ };
+ getMode() {
+ return this.device.getMode();
+ };
+ getVoice() {
+ return this.device.getVoice(...arguments);
+ };
+ getChVoice(ch) {
+ return this.device.getChVoice(ch);
+ };
+ get noteProgress() {
+ return this.#noteTime / this.#noteBInt;
+ };
+ get noteOverall() {
+ return this.noteProgress - this.#noteBarOffset;
+ };
+ get noteBar() {
+ return Math.floor(this.noteOverall / this.#noteNomin);
+ };
+ get noteBeat() {
+ let beat = this.noteOverall % this.#noteNomin;
+ if (beat < 0) {
+ beat += this.#noteNomin;
+ };
+ return beat;
+ };
+ getTimeSig() {
+ return [this.#noteNomin, this.#noteDenom];
+ };
+ getTempo() {
+ return this.#noteTempo;
+ };
+ sendCmd(raw) {
+ this.device.runJson(raw);
+ };
+ render(time) {
+ if (time > this.#noteTime) {
+ this.#noteTime = time;
+ };
+ let events = this.#midiPool?.step(time) || [];
+ let extraPoly = 0, notes = new Set();
+ let upThis = this;
+ let metaReplies = [];
+ // Reset strength for a new frame
+ this.device.getStrength().forEach((e, i) => {
+ this.#beforeStrength[i] = e;
+ });
+ upThis.device.newStrength();
+ events.forEach(function (e) {
+ let raw = e.data;
+ if (raw.type == 9) {
+ if (raw.data[1] > 0) {
+ notes.add(raw.part * 128 + raw.data[0]);
+ /*if (writeStrength[raw.part] == 0) {
+ upThis.#mimicStrength[raw.part] = raw.data[1];
+ };*/
+ } else {
+ if (notes.has(raw.part * 128 + raw.data[0])) {
+ extraPoly ++;
+ };
+ };
+ };
+ if (e.data.type == 8) {
+ if (notes.has(raw.part * 128 + raw.data[0])) {
+ extraPoly ++;
+ };
+ };
+ let reply = upThis.device.runJson(raw);
+ switch (reply?.reply) {
+ case "meta": {
+ metaReplies.push(reply);
+ break;
+ };
+ };
+ if (reply?.reply) {
+ delete reply.reply;
+ };
+ });
+ if (metaReplies?.length > 0) {
+ this.dispatchEvent("meta", metaReplies);
+ };
+ // Pass params to actual displays
+ let chInUse = this.device.getActive(); // Active channels
+ let chKeyPr = []; // Pressed keys and their pressure
+ let chPitch = upThis.device.getPitch(); // All pitch bends
+ let chContr = upThis.device.getCcAll(); // All CC values
+ let chProgr = upThis.device.getProgram(); // All program values
+ let chType = upThis.device.getChType(); // All channel types
+ // Mimic strength variation
+ let writeStrength = this.device.getStrength();
+ writeStrength.forEach(function (e, i, a) {
+ a[i] = Math.max(upThis.#beforeStrength[i], e);
+ let diff = a[i] - upThis.#mimicStrength[i];
+ let chOff = ccToPos.length * i;
+ if (diff >= 0) {
+ // cc73 = 0, atkPower = 4
+ // cc73 = 127, atkPower = 0.25
+ let atkPower = 4 * (0.25 ** (chContr[chOff + ccToPos[73]] / 64));
+ upThis.#mimicStrength[i] += Math.ceil(diff - (diff * (upThis.smoothingAtk ** atkPower)));
+ } else {
+ let rlsPower = 4 * (0.25 ** (chContr[chOff + ccToPos[72]] / 64));
+ upThis.#mimicStrength[i] += Math.floor(diff - (diff * (upThis.smoothingDcy ** rlsPower)));
+ };
+ });
+ let curPoly = 0;
+ chInUse.forEach(function (e, i) {
+ if (e) {
+ chKeyPr[i] = upThis.device.getVel(i);
+ curPoly += chKeyPr[i].size;
+ };
+ });
+ let repObj = {
+ extraPoly,
+ curPoly,
+ chInUse,
+ chKeyPr,
+ chPitch,
+ chProgr,
+ chContr,
+ chType,
+ eventCount: events.length,
+ title: this.#titleName,
+ bitmap: this.device.getBitmap(),
+ letter: this.device.getLetter(),
+ texts: this.device.getTexts(),
+ master: this.device.getMaster(),
+ mode: this.device.getMode(),
+ strength: this.#mimicStrength.slice(),
+ velo: writeStrength,
+ rpn: this.device.getRpn(),
+ tSig: this.getTimeSig(),
+ tempo: this.getTempo(),
+ noteBar: this.noteBar,
+ noteBeat: this.noteBeat,
+ ace: this.device.getAce()
+ };
+ return repObj;
+ };
+ constructor(device, atk = 0.5, dcy = 0.5) {
+ super();
+ let upThis = this;
+ this.smoothingAtk = atk;
+ this.smoothingDcy = dcy;
+ this.device = device;
+ this.addEventListener("meta", function (raw) {
+ raw?.data?.forEach(function (e) {
+ (upThis.#metaRun[e.meta] || console.debug).call(upThis, e.meta, e.data);
+ });
+ });
+ this.device.addEventListener("mode", function (ev) {
+ upThis.dispatchEvent("mode", ev.data);
+ });
+ this.device.addEventListener("channelactive", function (ev) {
+ upThis.dispatchEvent("channelactive", ev.data);
+ });
+ this.device.addEventListener("channelmin", function (ev) {
+ upThis.dispatchEvent("channelmin", ev.data);
+ });
+ this.device.addEventListener("channelmax", function (ev) {
+ upThis.dispatchEvent("channelmax", ev.data);
+ });
+ this.device.addEventListener("channelreset", function (ev) {
+ upThis.dispatchEvent("channelreset");
+ });
+ this.device.addEventListener("screen", function (ev) {
+ upThis.dispatchEvent("screen", ev.data);
+ });
+ this.#metaRun[3] = function (type, data) {
+ if (upThis.#titleName?.length < 1) {
+ upThis.#titleName = data;
+ };
+ };
+ this.#metaRun[81] = function (type, data) {
+ let noteProgress = upThis.noteProgress;
+ // Change tempo
+ let lastBInt = upThis.#noteBInt || 0.5;
+ upThis.#noteTempo = 60000000 / data;
+ upThis.#noteBInt = data / 1000000;
+ upThis.#noteBarOffset += noteProgress * (lastBInt / upThis.#noteBInt) - noteProgress;
+ };
+ this.#metaRun[88] = function (type, data) {
+ let noteProgress = upThis.noteProgress;
+ let noteOverall = upThis.noteOverall;
+ let curBar = upThis.noteBar;
+ let curBeat = upThis.noteBeat;
+ // Change time signature
+ let oldNomin = upThis.#noteNomin;
+ let oldDenom = upThis.#noteDenom;
+ upThis.#noteNomin = data[0];
+ upThis.#noteDenom = 1 << data[1];
+ let metroClick = 24 * (32 / data[3]) / data[2];
+ if (oldNomin != upThis.#noteNomin) {
+ let targetBar = curBar;
+ upThis.#noteBarOffset -= targetBar * (upThis.#noteNomin - oldNomin);
+ if (curBeat + 1 >= oldNomin) {
+ if (oldNomin < upThis.#noteNomin) {
+ // For example, 4/4 > 6/4
+ upThis.#noteBarOffset -= Math.ceil(upThis.#noteNomin - curBeat - 1);
+ } else {
+ // For example, 6/4 > 4/4
+ upThis.#noteBarOffset += upThis.#noteNomin;
+ };
+ };
+ };
+ };
+ };
+};
+
+export {
+ RootDisplay,
+ ccToPos,
+ dnToPos
+};
diff --git a/src/basic/mxReader.js b/src/basic/mxReader.js
new file mode 100644
index 00000000..4b3d2e25
--- /dev/null
+++ b/src/basic/mxReader.js
@@ -0,0 +1,164 @@
+"use strict";
+
+let blankFont = new Uint8Array(40);
+
+let shiftIndex = 0, shiftLoading, shiftLoader = setInterval(() => {
+ if (shiftLoading) {
+ blankFont[shiftIndex] = !blankFont[shiftIndex];
+ shiftIndex ++;
+ if (shiftIndex > 34) {
+ shiftIndex = 0;
+ };
+ };
+}, 1000 / 50);
+
+Uint8Array.prototype.render = function (receiveFunc) {
+ let x = 0, y = 0,
+ w = this.width || 5, h = this.height || 8;
+ for (let i = 0; i < this.length; i ++) {
+ receiveFunc(this[i], x, y, this);
+ x ++;
+ if (x >= w) {
+ x = 0;
+ y ++;
+ };
+ };
+};
+
+let MxFont40 = class {
+ #fonts = [];
+ async load(text, allowOverwrite = false) {
+ let upThis = this;
+ let loadCount = 0, allCount = 0;
+ text.split("\n").forEach(function (e, i) {
+ if (i > 0 && e?.length > 0) {
+ let arr = e.split("\t");
+ let codePoint = parseInt(arr[0], 16);
+ allCount ++;
+ if (upThis.#fonts[codePoint] && !allowOverwrite) {
+ return;
+ };
+ let bm = new Uint8Array(40);
+ Array.from(arr[1]).forEach(async function (e, i) {
+ let verOff = i % 2 ? 4 : 0,
+ horOff = Math.floor(i / 2),
+ proxy = parseInt(e, 16), dp = 3;
+ while (proxy > 0 || dp >= 0) {
+ let pos = (verOff + dp) * 5 + horOff;
+ bm[pos] = proxy & 1;
+ proxy = proxy >> 1;
+ dp --;
+ };
+ });
+ upThis.#fonts[codePoint] = bm;
+ loadCount ++;
+ };
+ });
+ console.debug(`Font "${"(internal)"}": ${allCount} total, ${loadCount} loaded.`);
+ };
+ async loadFile(fileSrc, allowOverwrite = false) {
+ let upThis = this;
+ console.debug(`Requested font file from "${fileSrc}".`);
+ await upThis.load(await (await fetch(fileSrc)).text(), allowOverwrite);
+ shiftLoading = false;
+ };
+ constructor(...fileSrc) {
+ shiftLoading = true;
+ fileSrc.forEach(async (e) => {
+ await this.loadFile(e);
+ });
+ };
+ getCP(codePoint) {
+ return this.#fonts[codePoint];
+ };
+ getStr(codePoint) {
+ let arr = [],
+ upThis = this;
+ Array.from(codePoint).forEach(function (e) {
+ arr.push(upThis.#fonts[e.charCodeAt(0)] || upThis.#fonts[32] || blankFont);
+ });
+ return arr;
+ };
+};
+let MxBm256 = class {
+ #bm = {};
+ async loadFile(fileSrc) {
+ let upThis = this;
+ console.debug(`Requested fixed 256 bitmap file from "${fileSrc}".`);
+ (await (await fetch(fileSrc)).text()).split("\n").forEach(function (e, i) {
+ if (i > 0 && e?.length > 0) {
+ let arr = e.split("\t");
+ if (arr[1][0] != "@") {
+ let bm = new Uint8Array(256);
+ Array.from(arr[1]).forEach(function (e, i) {
+ let iOff = i * 4,
+ proxy = parseInt(e, 16), dp = 3;
+ while (proxy > 0 || dp >= 0) {
+ let pos = iOff + dp;
+ bm[pos] = proxy & 1;
+ proxy = proxy >> 1;
+ dp --;
+ };
+ });
+ upThis.#bm[arr[0]] = bm;
+ } else {
+ upThis.#bm[arr[0]] = upThis.#bm[arr[1].slice(1)];
+ };
+ };
+ });
+ };
+ constructor(fileSrc) {
+ this.loadFile(fileSrc);
+ };
+ getBm(rscNme) {
+ return this.#bm[rscNme]?.slice();
+ };
+};
+let MxBmDef = class {
+ #bm = {};
+ async loadFile(fileSrc) {
+ let upThis = this;
+ console.debug(`Requested pre-defined bitmap file from "${fileSrc}".`);
+ (await (await fetch(fileSrc)).text()).split("\n").forEach(function (e, i) {
+ if (i > 0 && e?.length > 0) {
+ let arr = e.split("\t");
+ if (arr[1][0] != "@") {
+ let bmWidth = parseInt(arr[1].slice(0, 4), 16),
+ bmHeight = parseInt(arr[1].slice(4, 8), 16);
+ let bm = new Uint8Array(bmWidth * bmHeight);
+ Array.from(arr[1]).slice(8).forEach(function (e, i) {
+ let iOff = i * 4,
+ proxy = parseInt(e, 16), dp = 3;
+ while (proxy > 0 || dp >= 0) {
+ let pos = iOff + dp;
+ if (pos <= bm.length) {
+ bm[pos] = proxy & 1;
+ proxy = proxy >> 1;
+ };
+ dp --;
+ };
+ });
+ bm.width = bmWidth;
+ bm.height = bmHeight;
+ upThis.#bm[arr[0]] = bm;
+ //console.debug(`W:${bmWidth} H:${bmHeight} L:${bm.length} ${arr[0]}`);
+ } else {
+ upThis.#bm[arr[0]] = upThis.#bm[arr[1].slice(1)];
+ };
+ };
+ });
+ self.mxDef = upThis;
+ };
+ constructor(fileSrc) {
+ this.loadFile(fileSrc);
+ };
+ getBm(rscNme) {
+ return this.#bm[rscNme];
+ };
+};
+
+export {
+ MxFont40,
+ MxBm256,
+ MxBmDef
+};
diff --git a/src/basic/sheetLoad.js b/src/basic/sheetLoad.js
new file mode 100644
index 00000000..64723c2c
--- /dev/null
+++ b/src/basic/sheetLoad.js
@@ -0,0 +1,45 @@
+"use strict";
+
+let SheetData = class {
+ #conf;
+ data = [];
+ reset() {
+ this.data = [];
+ };
+ async load(text) {
+ let lines = text.split("\n");
+ let fields;
+ lines.forEach((e, i) => {
+ if (e?.length) {
+ let cells = e.split("\t");
+ cells.forEach((e0, i0, a0) => {
+ let data = e0;
+ try {
+ data = JSON.parse(`"${e0}"`);
+ } catch (err) {
+ console.warn(`TSV decode failed on line ${i + 1} cell ${i0 + 1}\n${err.message}`);
+ };
+ a0[i0] = data || undefined;
+ });
+ if (i) {
+ let data = {};
+ cells.forEach((e0, i0) => {
+ if (fields[i0] && e0) {
+ data[fields[i0]] = e0;
+ };
+ });
+ this.data.push(data);
+ } else {
+ fields = cells;
+ };
+ };
+ });
+ };
+ constructor(conf) {
+ this.#conf = conf;
+ };
+};
+
+export {
+ SheetData
+};
diff --git a/src/basic/transform.js b/src/basic/transform.js
new file mode 100644
index 00000000..8e7e2847
--- /dev/null
+++ b/src/basic/transform.js
@@ -0,0 +1,109 @@
+"use strict";
+
+const veryBig = 281474976710655;
+
+import {
+ PointEvent,
+ RangeEvent,
+ TimedEvents
+} from "../../libs/lightfelt@ltgcgo/ext/timedEvents.js";
+
+let rawToPool = function (midiJson) {
+ //console.debug(midiJson);
+ let list = new TimedEvents();
+ let upThis = this;
+ let timeDiv = midiJson.timeDivision,
+ tempo = 120,
+ tempoChanges = new TimedEvents(),
+ pointer = 0,
+ pointerOffset = 0;
+ // Initiate a default tempo change
+ tempoChanges.push(new RangeEvent(0, veryBig, [120, 0]));
+ // First pass: get all tempo changes
+ midiJson.track.forEach(function (e0) {
+ pointer = 0;
+ e0.event.forEach(function (e1) {
+ pointer += e1.deltaTime;
+ if (e1.type == 255 && e1?.metaType == 81) {
+ tempo = 60000000 / e1.data;
+ let lastChange = tempoChanges[tempoChanges.length - 1];
+ if (lastChange) {
+ tempoChanges.push(new RangeEvent(pointer, 281474976710655, [tempo, 0]));
+ };
+ };
+ });
+ });
+ // Sort tempo changes into a correct order
+ tempoChanges.fresh();
+ // Sets correct ending time.
+ tempoChanges.forEach(function (e, i, a) {
+ if (i > 0) {
+ a[i - 1].end = e.start;
+ };
+ });
+ // Removes changes being too frequent
+ let tTempo = 120;
+ tempoChanges.forEach(function (e, i, a) {
+ if (i > 0) {
+ if (e.end == e.start) {
+ // Unneeded change
+ a.splice(a.indexOf(e), 1);
+ } else if (tTempo == e.data[0]) {
+ a[i - 1].end = e.end;
+ a.splice(a.indexOf(e), 1);
+ };
+ tTempo = e.data[0];
+ };
+ });
+ // Calculates offsets
+ let cOffset = 0, cTempo = 120;
+ tempoChanges.forEach(function (e) {
+ let cPointer = e.start;
+ let curTime = cPointer / cTempo / timeDiv * 60 + cOffset;
+ cTempo = e.data[0];
+ cOffset = curTime - cPointer / cTempo / timeDiv * 60;
+ e.data[1] = cOffset;
+ });
+ console.debug("All tempo changes: ", tempoChanges);
+ // Reset for the second pass
+ tempo = 120,
+ pointer = 0,
+ pointerOffset = 0;
+ // Second pass: convert deltaTime into actual time stamps
+ midiJson.track.forEach(function (e0, i0) {
+ pointer = 0,
+ pointerOffset = 0;
+ let movedTrk = i0 + 1;
+ e0.event.forEach(function (e1, i1) {
+ pointer += e1.deltaTime;
+ // Load the correct tempo changes and offsets
+ let changeData = tempoChanges.step(pointer, true)[0];
+ if (changeData) {
+ tempo = changeData.data[0];
+ pointerOffset = changeData.data[1];
+ };
+ let appendObj = {
+ type: e1.type,
+ data: e1.data,
+ track: movedTrk,
+ part: 0
+ };
+ if (e1.type > 14) {
+ appendObj.meta = e1.metaType;
+ } else {
+ appendObj.part = e1.channel;
+ };
+ list.push(new PointEvent(pointer / tempo / timeDiv * 60 + pointerOffset, appendObj));
+ });
+ });
+ list.fresh();
+ //console.debug("All MIDI events: ", list);
+ self.midiEvents = list;
+ // Give back the processed events
+ console.debug(`Parsed a type ${midiJson.formatType} MIDI sequence.`);
+ return list;
+};
+
+export {
+ rawToPool
+};
diff --git a/src/bridge/index.mjs b/src/bridge/index.mjs
new file mode 100644
index 00000000..d65bd1cc
--- /dev/null
+++ b/src/bridge/index.mjs
@@ -0,0 +1,144 @@
+// Middleware!
+"use strict";
+
+import {CustomEventSource} from "../../libs/lightfelt@ltgcgo/ext/customEvents.js";
+import MidiParser from "../../libs/midi-parser@colxi/main.min.js";
+import {rawToPool} from "../basic/transform.js";
+import {customInterpreter} from "../state/utils.js";
+
+MidiParser.customInterpreter = customInterpreter;
+
+// Use track 240 to 255 for middleware.
+let toJson = function (data, track = 0) {
+ let type = data[0] >> 4, part = data[0] & 15;
+ let replyObj = {
+ track: (track & 15) + 240,
+ type,
+ data: data.slice(1)
+ };
+ if (type < 15) {
+ replyObj.part = part;
+ return replyObj;
+ } if (type == 12) {
+ replyObj.data = data[1];
+ } else {
+ if (part == 0) {
+ // SysEx
+ return replyObj;
+ } else {
+ console.warn(`Unknown special event channel ${part}.`)
+ };
+ };
+};
+let fromJson = function (json) {
+ let type = json.type, part = json.part;
+ if (type == 255) {
+ // Directly reject sending meta events
+ return;
+ };
+ let binLength = 3;
+ if (type == 12) {
+ binLength = 2;
+ } else if (type == 15) {
+ binLength = json.data.length + 1;
+ };
+ let newInstr = new Uint8Array(binLength);
+ if (type != 15) {
+ newInstr[0] = json.type * 16 + json.part;
+ } else {
+ newInstr[0] = 240;
+ };
+ if (type == 12) {
+ newInstr[1] = json.data;
+ } else {
+ if (json.data.forEach) {
+ json.data.forEach((e, i) => {
+ newInstr[i + 1] = e;
+ });
+ } else {
+ console.debug(`Type ${type} value ${json.data.constructor.name} cannot be iterated.`);
+ };
+ };
+ return newInstr;
+};
+
+let getBridge = function () {
+ return new BroadcastChannel("cc.ltgc.octavia:MainInput");
+};
+let getBridgeOut = function () {
+ return new BroadcastChannel("cc.ltgc.octavia:MainOutput");
+};
+
+let SimpleMidiEventEmitter = class extends CustomEventSource {
+ #pool;
+ #paused = true;
+ #currentTime = 0;
+ #lastEventTs = 0;
+ #threadId = -1;
+ get currentTime() {
+ return this.#currentTime / 1000;
+ };
+ get duration() {
+ if (!this.#pool) {
+ return 0;
+ } else {
+ return this.#pool[this.#pool.length - 1].end + 4;
+ };
+ };
+ async load(blob) {
+ if (blob) {
+ this.#pool = rawToPool(MidiParser.parse(new Uint8Array(await blob.arrayBuffer())));
+ } else {
+ this.pause();
+ this.#currentTime = 0;
+ };
+ };
+ pause() {
+ if (this.#threadId > -1) {
+ clearInterval(this.#threadId);
+ // All notes off
+ for (let part = 0; part < 16; part ++) {
+ this.dispatchEvent("midi", {
+ delay: 0,
+ data: {part, "type": 11, "data": [123, 0]}
+ });
+ };
+ this.dispatchEvent("pause");
+ this.#threadId = -1;
+ };
+ };
+ async play() {
+ if (this.#threadId < 0) {
+ this.#lastEventTs = Date.now();
+ this.#threadId = setInterval(() => {
+ let timeNow = Date.now(),
+ timeLast = this.#currentTime,
+ timeDiff = timeNow - this.#lastEventTs;
+ this.#currentTime += timeDiff;
+ let events = this.#pool.step(this.currentTime);
+ events?.forEach((e) => {
+ this.dispatchEvent("midi", {
+ delay: Math.round(e.start * 1000 - timeLast),
+ data: e.data
+ });
+ });
+ this.#lastEventTs = timeNow;
+ }, 12.5);
+ this.dispatchEvent("play");
+ };
+ };
+ constructor(pool) {
+ super();
+ if (pool) {
+ this.load(pool);
+ };
+ };
+};
+
+export {
+ toJson,
+ fromJson,
+ getBridge,
+ getBridgeOut,
+ SimpleMidiEventEmitter
+};
diff --git a/src/cambiare/index.mjs b/src/cambiare/index.mjs
new file mode 100644
index 00000000..c4fb4c4d
--- /dev/null
+++ b/src/cambiare/index.mjs
@@ -0,0 +1,156 @@
+"use strict";
+
+import {RootDisplay} from "../basic/index.mjs";
+import {OctaviaDevice, ccToPos} from "../state/index.mjs";
+
+let Cambiare = class Cambiare extends RootDisplay {
+ context;
+ mode = 0;
+ startPort = 0;
+ fontPadding = 4;
+ #lineHeights = [];
+ #noteWidths = [];
+ #noteHeights = [];
+ #noteRegW = [];
+ noteTops = [1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1];
+ noteLefts = [[], [], []];
+ eventBuffer = {}; // Track if there are hidden notes
+ eventQueue = []; // Add back hidden notes
+ get lineHeight() {
+ return this.#lineHeights[this.mode];
+ };
+ get noteWidth() {
+ return this.#noteWidths[this.mode];
+ };
+ get noteHeight() {
+ return this.#noteHeights[this.mode];
+ };
+ get noteRegW() {
+ return this.#noteRegW[this.mode];
+ };
+ get noteOutline() {
+ return Math.ceil(2 * devicePixelRatio);
+ };
+ resizeCanvas(width, height) {
+ this.context.canvas.width = width;
+ this.context.canvas.height = height;
+ for (let mode = 0; mode < 3; mode ++) {
+ this.#lineHeights[mode] = Math.floor(height / [24, 24, 40][mode]);
+ this.#noteHeights[mode] = Math.floor(height / [48, 48, 80][mode]);
+ this.#noteWidths[mode] = Math.floor(width / ([104, 208, 208][mode] + 32));
+ this.#noteRegW[mode] = Math.floor(width / ([104, 208, 208][mode] + 32) * 7);
+ for (let key = 0; key < 12; key ++) {
+ this.noteLefts[mode][key] = Math.round(this.#noteWidths[mode] * [0, 0.5, 1, 1.5, 2, 3, 3.5, 4, 4.5, 5, 5.5, 6][key]);
+ };
+ };
+ };
+ drawNote(part, note, velo, state) {
+ let context = this.context;
+ //let startX = (data.note + (data.part >> (this.mode > 1 ? 5 : 4) << 7)) * this.noteWidth;
+ let startX = Math.floor(2 + note / 12) * this.noteRegW + this.noteLefts[this.mode][note % 12] + 14 * this.noteWidth + (context.canvas.width >> 1) * (part >> (this.mode > 1 ? 5 : 4)) + (this.device.getPitchShift(part) / 12) * this.noteRegW;
+ let startY = (3 + part % (this.mode > 1 ? 32 : 16)) * this.lineHeight + this.noteTops[note % 12] * this.noteHeight;
+ if (velo > 0) {
+ context.fillStyle = `#ffffff${(velo * 2).toString(16).padStart(2, "0")}`;
+ context.fillRect(startX + 1, startY + 1, this.noteWidth - 2, this.noteHeight - 2);
+ switch (state) {
+ case this.device.NOTE_HELD:
+ case this.device.NOTE_SOSTENUTO_HELD: {
+ context.clearRect(startX + 1 + this.noteOutline, startY + 1 + this.noteOutline, this.noteWidth - 2 * (1 + this.noteOutline), this.noteHeight - 2 * (1 + this.noteOutline));
+ break;
+ };
+ };
+ };
+ };
+ render(time) {
+ let sum = super.render(time),
+ upThis = this,
+ context = this.context,
+ timeNow = Date.now();
+ // Global reset
+ context.globalCompositeOperation = "source-over";
+ context.clearRect(0, 0, context.canvas.width, context.canvas.height);
+ // Set font size and get font metrics
+ context.font = `${this.lineHeight - this.fontPadding * 2}px "Noto Sans Mono", "Noto Sans Mono Web", mono`;
+ self.metrics = context.measureText("Op");
+ let fontLeft = metrics.actualBoundingBoxLeft,
+ fontTop = metrics.actualBoundingBoxAscent;
+ // Information section
+ context.fillStyle = "#fff";
+ context.fillText(`${sum.eventCount.toString().padStart(3, "0")} ${(sum.curPoly + sum.extraPoly).toString().padStart(3, "0")}/512 ${sum.tSig[0].toString().padStart(2, " ")}/${sum.tSig[1].toString().padEnd(2, " ")} ${(sum.noteBar + 1).toString().padStart(3, " ")}:${Math.floor(sum.noteBeat + 1).toString().padEnd(2, " ")} ${Math.floor(sum.tempo).toString().padStart(3, " ")}.${Math.floor(sum.tempo * 100 % 100).toString().padStart(2, "0")}bpm ${Math.floor(sum.master.volume).toString().padStart(3, " ")}.${Math.floor(sum.master.volume * 100 % 100).toString().padStart(2, "0")}%`, upThis.fontPadding + fontLeft, fontTop + upThis.fontPadding);
+ context.fillText("Voices VEMRCDBP12", upThis.fontPadding + fontLeft, fontTop + upThis.fontPadding + upThis.lineHeight * 2);
+ // Key press section
+ // Use available states
+ sum.chKeyPr.forEach((e, part) => {
+ e.forEach((e, note) => {
+ let minPart = upThis.startPort << 4,
+ maxPart = (upThis.startPort << 4) + (16 << upThis.mode);
+ if (part >= minPart && part < maxPart) {
+ upThis.drawNote(part - minPart, note, e.v, e.s);
+ };
+ });
+ });
+ // Also show hidden notes
+ upThis.eventQueue.forEach((e) => {
+ let minPart = upThis.startPort << 4,
+ maxPart = (upThis.startPort << 4) + (16 << upThis.mode);
+ if (e.part >= minPart && e.part < maxPart) {
+ upThis.drawNote(e.part, e.note, e.velo, e.state);
+ };
+ });
+ context.fillStyle = "#fff";
+ for (let part = 0; part < (16 << upThis.mode); part ++) {
+ let ch = part + (upThis.startPort << 4);
+ if (sum.chInUse[ch]) {
+ let lineTop = 2 + fontTop + upThis.fontPadding + upThis.lineHeight * (3 + (part % (this.mode > 1 ? 32 : 16)));
+ // Channel voices
+ let voice = upThis.device.getChVoice(ch);
+ context.fillText(`${ch + 1}`.padStart(2, "0"), upThis.fontPadding + fontLeft + (part >> (this.mode > 1 ? 5 : 4)) * (context.canvas.width >> 1), lineTop, upThis.noteWidth * 2.5);
+ context.fillText(voice.name, upThis.fontPadding + fontLeft + (part >> (this.mode > 1 ? 5 : 4)) * (context.canvas.width >> 1) + upThis.noteWidth * 3, lineTop, upThis.noteWidth * 13);
+ // Params
+ let chOff = ccToPos.length * ch;
+ [7, 11, 1, 91, 93, 94, 74, 5, 12, 13].forEach((e, i) => {
+ context.fillRect(upThis.fontPadding * 2 + upThis.noteWidth * (16 + i) + (part >> (this.mode > 1 ? 5 : 4)) * (context.canvas.width >> 1), upThis.lineHeight * (4 + (part % (this.mode > 1 ? 32 : 16))), upThis.noteWidth - upThis.noteOutline, (upThis.lineHeight - 1) * (sum.chContr[chOff + ccToPos[e]] / -127));
+ });
+ };
+ };
+ // Letter display
+ if (sum.letter.expire <= timeNow) {
+ //context.fillText(voice.name, upThis.fontPadding + fontLeft + (part >> (this.mode > 1 ? 5 : 4)) * (context.canvas.width >> 1), 2 + fontTop + upThis.fontPadding + upThis.lineHeight * (3 + (part % (this.mode > 1 ? 32 : 16))), upThis.noteWidth * 8);
+ };
+ // Bitmap display
+ // Draw strength metres
+ context.globalCompositeOperation = "xor";
+ context.fillStyle = "#fff";
+ for (let part = 0; part < (16 << upThis.mode); part ++) {
+ let ch = part + (upThis.startPort << 4);
+ context.fillRect(upThis.fontPadding + (part >> (this.mode > 1 ? 5 : 4)) * (context.canvas.width >> 1), upThis.lineHeight * (3 + (part % (this.mode > 1 ? 32 : 16))), upThis.noteWidth * 16 * (sum.strength[ch] / 255), (upThis.lineHeight - 1));
+ };
+ // Clean event buffer up
+ for (let rawNote in upThis.eventBuffer) {
+ delete upThis.eventBuffer[rawNote];
+ };
+ // Clean event queue up
+ while (upThis.eventQueue.length > 0) {
+ delete upThis.eventQueue[0];
+ upThis.eventQueue.shift();
+ };
+ };
+ constructor(context) {
+ super(new OctaviaDevice(), 0.1, 0.75);
+ let upThis = this;
+ this.context = context;
+ this.resizeCanvas(1280, 720);
+ this.device.addEventListener("note", (ev) => {
+ let data = ev.data;
+ let noteId = data.part * 128 + data.note;
+ let oldEvent = this.eventBuffer[noteId];
+ this.eventBuffer[noteId] = data;
+ // Schedule a hidden note in event queue
+ if (oldEvent?.velo > 0 && data.velo == 0) {
+ this.eventQueue.push(oldEvent);
+ };
+ });
+ };
+};
+
+export default Cambiare;
diff --git a/src/cambiare_wa/index.js b/src/cambiare_wa/index.js
new file mode 100644
index 00000000..746d548a
--- /dev/null
+++ b/src/cambiare_wa/index.js
@@ -0,0 +1,304 @@
+"use strict";
+
+import {} from "../../libs/lightfelt@ltgcgo/main/cssClass.js";
+import {$e, $a} from "../../libs/lightfelt@ltgcgo/main/quickPath.js";
+import Cambiare from "../cambiare/index.mjs";
+import {fileOpen} from "../../libs/browser-fs-access@GoogleChromeLabs/browser_fs_access.min.js";
+import {
+ getBridge
+} from "../bridge/index.mjs";
+import {SheetData} from "../basic/sheetLoad.js";
+
+let demoBlobs = {};
+let demoPerfs = {};
+let demoInfo = {};
+let demoModes = [];
+demoModes[9] = "gm";
+let currentPerformance;
+let currentAnimation;
+let useMidiBus = false;
+
+// Standard switching
+let stSwitch = $a("b.mode");
+let stSwitchMode = [];
+stSwitch.to = function (i) {
+ stSwitch.forEach(function (e) {
+ e.classList.off("active");
+ });
+ if (i > -1) {
+ stSwitch[i].classList.on("active");
+ };
+};
+stSwitch.forEach(function (e, i, a) {
+ stSwitchMode[i] = e.title;
+ e.addEventListener("click", function () {
+ visualizer.switchMode(e.title, true);
+ stSwitch.to(i);
+ });
+});
+
+// Standard demo switching
+let demoPool = new SheetData();
+let stList = $e("span#demo-list"), stDemo = [];
+const srcPaths = ['../../midi-demo-data/collection/octavia/', './demo/'];
+let getBlobFrom = async function (filename) {
+ let i = 0;
+ while (i < srcPaths.length) {
+ let e = srcPaths[i];
+ let response = await fetch(`${e}${filename}`);
+ if (response.status < 400) {
+ return response;
+ };
+ i ++;
+ };
+ console.error(`Loading of data ${filename} failed.`);
+};
+getBlobFrom(`list.tsv`).then(async (response) => {
+ await demoPool.load(await response.text());
+ //console.info(demoPool.data);
+ demoPool.data.forEach((e, i) => {
+ if (i) {
+ let space = document.createElement("span");
+ space.innerHTML = " ";
+ stList.appendChild(space);
+ } else {
+ stList.innerText = "";
+ };
+ let demoChoice = document.createElement("b");
+ demoChoice.innerText = e.text;
+ demoChoice.title = e.file;
+ demoChoice.classList.on("demo");
+ stDemo.push(demoChoice);
+ stList.appendChild(demoChoice);
+ });
+ stDemo.to = function (i) {
+ stDemo.forEach(function (e) {
+ e.classList.off("active");
+ });
+ if (i > -1) {
+ stDemo[i].classList.on("active");
+ };
+ };
+ stDemo.forEach(function (e, i, a) {
+ e.addEventListener("click", async function () {
+ audioPlayer.pause();
+ if (!demoBlobs[e.title]?.midi) {
+ demoBlobs[e.title] = {};
+ audioPlayer.src = "about:blank";
+ demoBlobs[e.title].midi = await (await getBlobFrom(`${e.title}.mid`)).blob();
+ demoBlobs[e.title].wave = await (await getBlobFrom(`${e.title}.opus`)).blob();
+ };
+ currentPerformance = demoPerfs[e.title];
+ currentPerformance?.resetIndex();
+ currentAnimation = demoInfo[e.title];
+ audioPlayer.currentTime = 0;
+ visualizer.reset();
+ visualizer.loadFile(demoBlobs[e.title].midi);
+ if (audioBlob) {
+ URL.revokeObjectURL(audioBlob);
+ };
+ audioBlob = demoBlobs[e.title].wave;
+ audioPlayer.src = URL.createObjectURL(audioBlob);
+ if (demoModes[i]?.length > 0) {
+ visualizer.switchMode(demoModes[i]);
+ };
+ stDemo.to(i);
+ });
+ });
+});
+
+// Open the files
+let midwIndicator = $e("#openMidw");
+let audioBlob;
+const propsMid = JSON.parse('{"extensions":[".mid",".MID",".kar",".KAR",".syx",".SYX",".s7e",".S7E"],"startIn":"music","id":"midiOpener","description":"Open a MIDI file"}'),
+propsAud = JSON.parse('{"mimeTypes":["audio/*"],"startIn":"music","id":"audioOpener","description":"Open an audio file"}');
+$e("#openMidi").addEventListener("click", async function () {
+ useMidiBus = false;
+ midwIndicator.classList.off("active");
+ let file = await fileOpen(propsMid);
+ let fileSplit = file.name.lastIndexOf("."), ext = "";
+ if (fileSplit > -1) {
+ ext = file.name.slice(fileSplit + 1).toLowerCase();
+ };
+ switch (ext) {
+ case "syx": {
+ // Load SysEx blobs
+ visualizer.sendCmd({type: 15, track: 0, data: new Uint8Array(await file.arrayBuffer())});
+ break;
+ };
+ case "s7e": {
+ // Load sound banks
+ visualizer.device.loadBank(ext, file);
+ break;
+ };
+ default: {
+ // Load MIDI files
+ stDemo.to(-1);
+ visualizer.reset();
+ visualizer.loadFile(file);
+ visualizer.device.initOnReset = false;
+ };
+ };
+});
+$e("#openAudio").addEventListener("click", async function () {
+ useMidiBus = false;
+ midwIndicator.classList.off("active");
+ if (audioBlob) {
+ URL.revokeObjectURL(audioBlob);
+ };
+ audioBlob = await fileOpen(propsAud);
+ audioPlayer.src = URL.createObjectURL(audioBlob);
+});
+midwIndicator.addEventListener("click", function () {
+ stDemo.to(-1);
+ if (audioBlob) {
+ URL.revokeObjectURL(audioBlob);
+ };
+ audioBlob = null;
+ audioPlayer.src = "";
+ visualizer.reset();
+ useMidiBus = true;
+ midwIndicator.classList.on("active");
+});
+
+// Get canvas
+let targetWidth, targetHeight;
+let dispCanv = $e("#cambiare-stage");
+let dispCtx = dispCanv.getContext("2d");
+
+// Start the visualizers
+self.visualizer = new Cambiare(dispCtx);
+visualizer.addEventListener("reset", function (e) {
+ console.info("Processor reset.");
+});
+
+// Listen to mode switches
+visualizer.addEventListener("mode", function (ev) {
+ stSwitch.to(stSwitchMode.indexOf(ev.data));
+});
+
+let canvFull = async function () {
+ if (document.fullscreenElement) {
+ document.exitFullscreen();
+ visualizer.resizeCanvas(targetWidth, targetHeight);
+ } else {
+ dispCanv.requestFullscreen();
+ visualizer.resizeCanvas(screen.width, screen.height);
+ };
+};
+dispCanv.addEventListener("dblclick", canvFull);
+dispCanv.addEventListener("contextmenu", (ev) => {
+ if (document.fullscreenElement) {
+ ev.preventDefault();
+ ev.stopPropagation();
+ canvFull();
+ };
+});
+
+// Resize the canvas and calculate critical positioning
+let winResize = function (ev) {
+ let tabHeight = document.children[0].clientHeight,
+ tabWidth = document.children[0].clientWidth;
+ targetWidth = Math.floor(tabWidth / 10) * 10,
+ targetHeight = Math.floor(tabHeight / 10) * 10;
+ dispCanv.style.position = `absolute`;
+ dispCanv.style.top = `180px`;
+ visualizer.resizeCanvas(Math.max(targetWidth, 960), Math.max(540, Math.min(targetHeight, targetWidth)));
+};
+addEventListener("resize", winResize);
+winResize();
+
+document.addEventListener("keydown", function (ev) {
+ let scamKey = (+ev.shiftKey << 3) + (+ev.ctrlKey << 2) + (+ev.altKey << 1) + +ev.metaKey;
+ switch (scamKey) {
+ case 0: {
+ switch (ev.key) {
+ case "Enter": {
+ // Enter or exit fullscreen
+ canvFull();
+ ev.preventDefault();
+ break;
+ };
+ case " ": {
+ // Play or pause
+ if (audioPlayer.paused) {
+ audioPlayer.play();
+ } else {
+ audioPlayer.pause();
+ };
+ ev.preventDefault();
+ break;
+ };
+ case "ArrowLeft": {
+ audioPlayer.currentTime -= 1;
+ break;
+ };
+ case "ArrowRight": {
+ audioPlayer.currentTime += 1;
+ break;
+ };
+ case "1":
+ case "2":
+ case "3":
+ case "4":
+ case "5":
+ case "6":
+ case "7":
+ case "8": {
+ // Switch start port
+ visualizer.startPort = "12345678".indexOf(ev.key);
+ break;
+ };
+ case "j": {
+ visualizer.mode = 0;
+ break;
+ };
+ case "k": {
+ visualizer.mode = 1;
+ break;
+ };
+ case "l": {
+ visualizer.mode = 2;
+ break;
+ };
+ };
+ break;
+ };
+ };
+});
+
+// Render frames
+let audioPlayer = $e("#audioPlayer");
+audioPlayer.onended = function () {
+ visualizer.reset();
+ audioPlayer.currentTime = 0;
+};
+(async function () {
+ visualizer.reset();
+ let midiBlob = await (await fetch("./demo/KANDI8.mid")).blob();
+ demoBlobs.KANDI8 = {};
+ demoBlobs.KANDI8.midi = midiBlob;
+ visualizer.loadFile(midiBlob);
+ if (audioBlob) {
+ URL.revokeObjectURL(audioBlob);
+ };
+ audioBlob = await (await fetch("./demo/KANDI8.opus")).blob();
+ demoBlobs.KANDI8.wave = audioBlob;
+ audioPlayer.src = URL.createObjectURL(audioBlob);
+})();
+let lastTime = 0;
+let renderThread = setInterval(function () {
+ if (/*!audioPlayer.paused*/true) {
+ let curTime = audioPlayer.currentTime - (self.audioDelay || 0);
+ if (curTime < lastTime) {
+ };
+ visualizer.render(curTime);
+ lastTime = curTime;
+ };
+}, 20);
+
+getBridge().addEventListener("message", function (ev) {
+ if (useMidiBus) {
+ visualizer.sendCmd(ev.data);
+ };
+});
diff --git a/src/compat/buildOpt.txt b/src/compat/buildOpt.txt
new file mode 100644
index 00000000..a4359c95
--- /dev/null
+++ b/src/compat/buildOpt.txt
@@ -0,0 +1 @@
+--target=chrome59
diff --git a/src/compat/inject.js b/src/compat/inject.js
new file mode 100644
index 00000000..7e3dce27
--- /dev/null
+++ b/src/compat/inject.js
@@ -0,0 +1,81 @@
+"use strict";
+
+import {} from "../../libs/snowy@ltgcgo/bc.js";
+
+// Compatibility for Windows XP (FF 52 ESR, GC 59)
+{
+ // Direct blob reads
+ let fileReadAs = function (blob, target) {
+ let reader = new FileReader();
+ return new Promise((success, failure) => {
+ reader.addEventListener("abort", () => {
+ failure(new Error("Blob read aborted"));
+ });
+ reader.addEventListener("error", (ev) => {
+ failure(reader.error || ev.data || new Error("Blob read error"));
+ });
+ reader.addEventListener("load", () => {
+ success(reader.result);
+ });
+ switch (target.toLowerCase()) {
+ case "arraybuffer":
+ case "buffer": {
+ reader.readAsArrayBuffer(blob);
+ break;
+ };
+ case "string":
+ case "text": {
+ reader.readAsText(blob);
+ break;
+ };
+ default: {
+ failure(new Error(`Unknown target ${target}`));
+ };
+ };
+ });
+ };
+ Blob.prototype.arrayBuffer = Blob.prototype.arrayBuffer || function () {
+ return fileReadAs(this, "buffer");
+ };
+ Blob.prototype.text = Blob.prototype.text || function () {
+ return fileReadAs(this, "text");
+ };
+};
+{
+ // A working replaceAll implementation
+ String.prototype.replaceAll = String.prototype.replaceAll || function (source, target) {
+ let antiLoop = 0, maxSafe = 16;
+ let indexFinder = this, indexes = [];
+ while (antiLoop < maxSafe && indexFinder.lastIndexOf(source) > -1) {
+ let index = indexFinder.lastIndexOf(source);
+ indexes.unshift(indexFinder.slice(index + source.length));
+ indexFinder = indexFinder.slice(0, index);
+ if (index == 0) {
+ indexes.unshift("");
+ };
+ antiLoop ++;
+ };
+ if (indexFinder.length) {
+ indexes.unshift(indexFinder);
+ };
+ return indexes.join(target) || "";
+ };
+ String.prototype.padStart = String.prototype.padStart || function (length, filler) {
+ if (filler) {
+ let result = this;
+ while (result.length < length) {
+ result = `${filler}${result}`;
+ };
+ return result;
+ };
+ };
+ String.prototype.padEnd = String.prototype.padEnd || function (length, filler) {
+ if (filler) {
+ let result = this;
+ while (result.length < length) {
+ result += filler;
+ };
+ return result;
+ };
+ };
+};
diff --git a/src/demoMw/index.js b/src/demoMw/index.js
new file mode 100644
index 00000000..f55fe157
--- /dev/null
+++ b/src/demoMw/index.js
@@ -0,0 +1,129 @@
+"use strict";
+
+import {} from "../../libs/lightfelt@ltgcgo/main/cssClass.js";
+import {$e, $a} from "../../libs/lightfelt@ltgcgo/main/quickPath.js";
+import {fileOpen} from "../../libs/browser-fs-access@GoogleChromeLabs/browser_fs_access.min.js";
+import {
+ toJson,
+ fromJson,
+ getBridge,
+ SimpleMidiEventEmitter
+} from "../bridge/index.mjs";
+
+let globalAudioCtx;
+let getGAC = function () {
+ if (!globalAudioCtx) {
+ globalAudioCtx = new AudioContext();
+ };
+};
+let switchList = function (list, index) {
+ list?.forEach((e, i) => {
+ if (i == index) {
+ e.classList.on("active");
+ } else {
+ e.classList.off("active");
+ };
+ });
+};
+
+let inPortMap = {};
+
+let activeIn, activeInPort = 0, activeOut, activeOutPort = 0;
+
+let midiInBox = $e("#midi-in-list"), midiOutBox = $e("#midi-out-list");
+let midiInSw = $e(".actor-port-in"), midiOutSw = $e(".actor-port-out");
+let midiInSel = $a(".selector-port-in"), midiOutSel = $a(".selector-port-out");
+let portInList = [], portOutList = [];
+
+let refreshPortIn = function () {
+ while (portInList > 0) {
+ portInList.pop().remove();
+ };
+ midiAccess.inputs.forEach((port, id) => {
+ let midin = document.createElement("li");
+ midin.innerText = port.name;
+ midin.id = `mw-in-${id}`;
+ midin.setAttribute("mw-port-id", id);
+ midin.addEventListener("click", inputSel);
+ midiInBox.appendChild(midin);
+ portInList.push(midin);
+ });
+};
+
+let inputConv = function (ev) {
+ midiLine.postMessage(toJson(ev.data, inPortMap[ev.target.id]));
+};
+let inputSel = function () {
+ activeIn = midiAccess.inputs.get(this.getAttribute("mw-port-id"));
+ midiInSw.innerText = activeIn.connection == "closed" ? "Closed" : "Opened";
+ if (inPortMap[activeIn.id] || activeIn.connection == "open") {
+ switchList(midiInSel, inPortMap[activeIn.id]);
+ };
+ portInList.forEach((e) => {
+ let elId = e.getAttribute("mw-port-id");
+ if (elId == activeIn.id) {
+ e.classList.on("active");
+ } else {
+ e.classList.off("active");
+ };
+ });
+};
+midiInSw.addEventListener("click", function () {
+ if (activeIn.connection == "closed") {
+ activeIn.open();
+ inPortMap[activeIn.id] = activeInPort;
+ activeIn.addEventListener("midimessage", inputConv);
+ midiLine.postMessage({
+ type: 255,
+ meta: 33,
+ track: 240 + activeInPort,
+ data: activeInPort
+ });
+ midiInSw.innerText = "Opened";
+ } else {
+ activeIn.close();
+ activeIn.removeEventListener("midimessage", inputConv);
+ midiInSw.innerText = "Closed";
+ };
+});
+midiInSel.forEach((e, i) => {
+ e.addEventListener("click", function () {
+ activeInPort = i;
+ switchList(midiInSel, i);
+ });
+});
+
+(async function () {
+ self.midiAccess = await navigator.requestMIDIAccess({"sysex": true, "software": true});
+ self.fromJson = fromJson;
+ self.toJson = toJson;
+ self.MEE = SimpleMidiEventEmitter;
+ midiAccess.addEventListener("statechange", (ev) => {
+ console.debug(ev.port);
+ });
+ refreshPortIn();
+ midiAccess.outputs.forEach((port, id) => {
+ let midout = document.createElement("li");
+ midout.innerText = port.name;
+ midout.id = `mw-in-${id}`;
+ midout.setAttribute("mw-port-id", id);
+ midiOutBox.appendChild(midout);
+ });
+ self.midiLine = getBridge();
+ const propsMid = JSON.parse('{"extensions":[".mid",".MID",".kar",".KAR",".syx",".SYX"],"startIn":"music","id":"midiOpener","description":"Open a MIDI file"}');
+ $e("#openMidi").addEventListener("click", async function () {
+ let file = await fileOpen(propsMid);
+ let fileSplit = file.name.lastIndexOf("."), ext = "";
+ if (fileSplit > -1) {
+ ext = file.name.slice(fileSplit + 1).toLowerCase();
+ };
+ if (ext == "syx") {
+ // Load SysEx blobs
+ //tuiVis.sendCmd({type: 15, track: 0, data: new Uint8Array(await file.arrayBuffer())});
+ } else {
+ //tuiVis.reset();
+ //tuiVis.loadFile(file);
+ self.midiBlob = file;
+ };
+ });
+})();
diff --git a/src/demoTui/index.js b/src/demoTui/index.js
new file mode 100644
index 00000000..e15c7579
--- /dev/null
+++ b/src/demoTui/index.js
@@ -0,0 +1,242 @@
+"use strict";
+
+import {} from "../../libs/lightfelt@ltgcgo/main/cssClass.js";
+import {$e, $a} from "../../libs/lightfelt@ltgcgo/main/quickPath.js";
+import TuiDisplay from "../disp/disp_tui.mjs";
+import {fileOpen} from "../../libs/browser-fs-access@GoogleChromeLabs/browser_fs_access.min.js";
+import {
+ getBridge
+} from "../bridge/index.mjs";
+import {SheetData} from "../basic/sheetLoad.js";
+
+let demoBlobs = {};
+let demoModes = [];
+demoModes[9] = "gm";
+let useMidiBus = false;
+
+self.minCh = 0;
+
+// Standard switching
+let stSwitch = $a("b.mode");
+let stSwitchMode = [];
+stSwitch.to = function (i) {
+ stSwitch.forEach(function (e) {
+ e.classList.off("active");
+ });
+ if (i > -1) {
+ stSwitch[i].classList.on("active");
+ };
+};
+stSwitch.forEach(function (e, i, a) {
+ stSwitchMode[i] = e.title;
+ e.addEventListener("click", function () {
+ visualizer.switchMode(e.title, true);
+ stSwitch?.to(i);
+ });
+});
+
+// Standard demo switching
+let demoPool = new SheetData();
+let stList = $e("span#demo-list"), stDemo = [];
+const srcPaths = ['../../midi-demo-data/collection/octavia/', './demo/'];
+let getBlobFrom = async function (filename) {
+ let i = 0;
+ while (i < srcPaths.length) {
+ let e = srcPaths[i];
+ let response = await fetch(`${e}${filename}`);
+ if (response.status < 400) {
+ return response;
+ };
+ i ++;
+ };
+ console.error(`Loading of data ${filename} failed.`);
+};
+getBlobFrom(`list.tsv`).then(async (response) => {
+ await demoPool.load(await response.text());
+ //console.info(demoPool.data);
+ demoPool.data.forEach((e, i) => {
+ if (i) {
+ let space = document.createElement("span");
+ space.innerHTML = " ";
+ stList.appendChild(space);
+ } else {
+ stList.innerText = "";
+ };
+ let demoChoice = document.createElement("b");
+ demoChoice.innerText = e.text;
+ demoChoice.title = e.file;
+ demoChoice.classList.on("demo");
+ stDemo.push(demoChoice);
+ stList.appendChild(demoChoice);
+ });
+ stDemo.to = function (i) {
+ stDemo.forEach(function (e) {
+ e.classList.off("active");
+ });
+ if (i > -1) {
+ stDemo[i].classList.on("active");
+ };
+ };
+ stDemo.forEach(function (e, i, a) {
+ e.addEventListener("click", async function () {
+ useMidiBus = false;
+ midwIndicator.classList.off("active");
+ audioPlayer.pause();
+ if (!demoBlobs[e.title]?.midi) {
+ demoBlobs[e.title] = {};
+ textDisplay.innerHTML = `Loading demo ${e.innerText.toUpperCase()}.${" ".repeat(23)}`;
+ demoBlobs[e.title].midi = await (await getBlobFrom(`${e.title}.mid`)).blob();
+ demoBlobs[e.title].wave = await (await getBlobFrom(`${e.title}.opus`)).blob();
+ };
+ textDisplay.innerHTML = `Demo ${e.innerText.toUpperCase()} ready.${" ".repeat(23)}`;
+ audioPlayer.currentTime = 0;
+ visualizer.reset();
+ visualizer.loadFile(demoBlobs[e.title].midi);
+ if (audioBlob) {
+ URL.revokeObjectURL(audioBlob);
+ };
+ audioBlob = demoBlobs[e.title].wave;
+ audioPlayer.src = URL.createObjectURL(audioBlob);
+ if (demoModes[i]?.length > 0) {
+ visualizer.switchMode(demoModes[i]);
+ };
+ stDemo?.to(i);
+ visualizer.device.initOnReset = false;
+ });
+ });
+});
+
+// Start the visualizers
+self.visualizer = new TuiDisplay();
+visualizer.addEventListener("reset", function (e) {
+ minCh = 0;
+});
+
+// Listen to mode switches
+visualizer.addEventListener("mode", function (ev) {
+ stSwitch?.to(stSwitchMode.indexOf(ev.data));
+});
+
+// Open the files
+let midwIndicator = $e("#openMidw");
+let audioBlob;
+const propsMid = JSON.parse('{"extensions":[".mid",".MID",".kar",".KAR",".syx",".SYX",".s7e",".S7E"],"startIn":"music","id":"midiOpener","description":"Open a MIDI file"}'),
+propsAud = JSON.parse('{"mimeTypes":["audio/*"],"startIn":"music","id":"audioOpener","description":"Open an audio file"}');
+$e("#openMidi").addEventListener("click", async function () {
+ useMidiBus = false;
+ midwIndicator.classList.off("active");
+ let file = await fileOpen(propsMid);
+ let fileSplit = file.name.lastIndexOf("."), ext = "";
+ if (fileSplit > -1) {
+ ext = file.name.slice(fileSplit + 1).toLowerCase();
+ };
+ switch (ext) {
+ case "syx": {
+ // Load SysEx blobs
+ visualizer.sendCmd({type: 15, track: 0, data: new Uint8Array(await file.arrayBuffer())});
+ break;
+ };
+ case "s7e": {
+ // Load sound banks
+ visualizer.device.loadBank(ext, file);
+ break;
+ };
+ default: {
+ // Load MIDI files
+ stDemo?.to(-1);
+ visualizer.reset();
+ visualizer.loadFile(file);
+ visualizer.device.initOnReset = false;
+ };
+ };
+});
+$e("#openAudio").addEventListener("click", async function () {
+ useMidiBus = false;
+ midwIndicator.classList.off("active");
+ if (audioBlob) {
+ URL.revokeObjectURL(audioBlob);
+ };
+ audioBlob = await fileOpen(propsAud);
+ audioPlayer.src = URL.createObjectURL(audioBlob);
+});
+midwIndicator.addEventListener("click", function () {
+ stDemo?.to(-1);
+ if (audioBlob) {
+ URL.revokeObjectURL(audioBlob);
+ };
+ audioBlob = null;
+ audioPlayer.src = "";
+ visualizer.reset();
+ useMidiBus = true;
+ midwIndicator.classList.on("active");
+ visualizer.device.initOnReset = true;
+});
+
+// Get the canvas
+let dispCanvas = $e("#bmDisp"),
+dispCtx = dispCanvas.getContext("2d");
+dispCanvas.addEventListener("wheel", function (ev) {
+ ev.preventDefault();
+ if (ev.deltaY > 0) {
+ if (minCh < 112) {
+ minCh ++;
+ };
+ } else {
+ if (minCh > 0) {
+ minCh --;
+ };
+ };
+});
+dispCanvas.addEventListener("mouseup", function (ev) {
+ if (ev.layerY > 47) {
+ if (minCh < 112) {
+ minCh = (1 + (minCh >> 4)) << 4;
+ };
+ } else if (ev.layerY < 47) {
+ if (minCh > 0) {
+ if (minCh < 16) {
+ minCh = 16;
+ };
+ minCh = ((minCh >> 4) - 1) << 4;
+ };
+ };
+});
+
+// Render frames
+let audioPlayer = $e("#audioPlayer");
+let textDisplay = $e("#display");
+dispCanvas.style.left = `${textDisplay.offsetLeft + textDisplay.offsetWidth - dispCanvas.offsetWidth}px`;
+dispCanvas.style.top = `${textDisplay.offsetTop}px`;
+audioPlayer.onended = function () {
+ visualizer.reset();
+};
+(async function () {
+ visualizer.reset();
+ let midiBlob = await (await fetch("./demo/KANDI8.mid")).blob();
+ demoBlobs.KANDI8 = {};
+ demoBlobs.KANDI8.midi = midiBlob;
+ visualizer.loadFile(midiBlob);
+ if (audioBlob) {
+ URL.revokeObjectURL(audioBlob);
+ };
+ audioBlob = await (await fetch("./demo/KANDI8.opus")).blob();
+ demoBlobs.KANDI8.wave = audioBlob;
+ audioPlayer.src = URL.createObjectURL(audioBlob);
+ textDisplay.innerHTML = `${" ".repeat(23)}`;
+})();
+let renderThread = setInterval(function () {
+ if (!audioPlayer.paused || useMidiBus) {
+ textDisplay.innerHTML = visualizer.render(audioPlayer.currentTime - (self.audioDelay || 0), dispCtx);
+ };
+}, 20);
+getBridge().addEventListener("message", function (ev) {
+ if (useMidiBus) {
+ visualizer.sendCmd(ev.data);
+ };
+ //console.debug(ev.data);
+});
+
+addEventListener("resize", function () {
+ dispCanvas.style.left = `${textDisplay.offsetLeft + textDisplay.offsetWidth - dispCanvas.offsetWidth}px`;
+ dispCanvas.style.top = `${textDisplay.offsetTop}px`;
+});
diff --git a/src/disp/colour.js b/src/disp/colour.js
new file mode 100644
index 00000000..77e10ebf
--- /dev/null
+++ b/src/disp/colour.js
@@ -0,0 +1,46 @@
+"use strict";
+
+let backlight = {
+ red: "#ff7986",
+ orange: "#fca022",
+ grYellow: "#c9e10a",
+ green: "#c1ff0a",
+ white: "#b7e5e3",
+ blue: "#2280ff"
+},
+lcdPixel = {
+ black: "#000000",
+ blue: "#0516bb",
+ purple: "#48009a"
+};
+
+// Generate caches for easier implementation
+let lcdCache = {}, lcdCacheTransparency = "06,68,2a,16,aa,3b".split(",");
+for (let colour in lcdPixel) {
+ lcdCache[colour] = [];
+ lcdCacheTransparency.forEach((e) => {
+ lcdCache[colour].push(`${lcdPixel[colour]}${e}`);
+ });
+};
+
+// For backwards compatibility
+let bgOrange = `${backlight.orange}64`,
+bgGreen = `${backlight.green}64`,
+bgWhite = `${backlight.white}64`,
+bgRed = `${backlight.red}64`;
+let inactivePixel = lcdCache.black[0],
+mediumPixel = lcdCache.black[2],
+activePixel = lcdCache.black[1];
+
+export {
+ bgOrange,
+ bgGreen,
+ bgWhite,
+ bgRed,
+ inactivePixel,
+ mediumPixel,
+ activePixel,
+ backlight,
+ lcdPixel,
+ lcdCache
+};
diff --git a/src/disp/common.js b/src/disp/common.js
new file mode 100644
index 00000000..ca85f115
--- /dev/null
+++ b/src/disp/common.js
@@ -0,0 +1,20 @@
+"use strict";
+
+// The common values used in all example screens.
+
+let noteNames = [
+ "C~", "C#", "D~", "Eb",
+ "E~", "F~", "F#", "G~",
+ "Ab", "A~", "Bb", "B~"
+], noteRegion = "!0123456789",
+hexMap = "0123456789ABCDEF",
+map = "0123456789_aAbBcCdDeEfFgGhHiIjJ-kKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ",
+waveMap = ["-", "~", "+", "|"];
+
+export {
+ noteNames,
+ noteRegion,
+ hexMap,
+ map,
+ waveMap
+};
diff --git a/src/disp/disp_mu.mjs b/src/disp/disp_mu.mjs
new file mode 100644
index 00000000..4e449caf
--- /dev/null
+++ b/src/disp/disp_mu.mjs
@@ -0,0 +1,434 @@
+"use strict";
+
+import {OctaviaDevice} from "../state/index.mjs";
+import {RootDisplay, ccToPos} from "../basic/index.mjs";
+import {MxFont40, MxBm256} from "../basic/mxReader.js";
+
+import {
+ backlight,
+ inactivePixel,
+ activePixel
+} from "./colour.js";
+
+let mprWidth = 8,
+mpaWidth = 7,
+mprHeight = 4,
+mpaHeight = 3;
+let normParamPaint = function (sup, offsetX, ctx) {
+ let paramW = mprWidth * 4 - 1;
+ let paramH = mprHeight * 1.5 - 1;
+ let sub = sup >> 4;
+ for (let i = 0; i < 8; i ++) {
+ if (sub > 0 || (sub == 0 && i != 0)) {
+ ctx.fillStyle = activePixel;
+ } else {
+ ctx.fillStyle = inactivePixel;
+ };
+ sub --;
+ let invI = 7 - i;
+ ctx.fillRect(offsetX, 181 + invI * mprWidth, paramW, paramH);
+ };
+};
+let startA = Math.PI * 255 / 180;
+let endA = Math.PI * 285 / 180;
+let efxParamPaint = function (sup, offsetX, ctx, useWB, wbArr) {
+ let paramW = mprWidth * 4 - 1;
+ let paramH = mprHeight * 1.5 - 1;
+ let sub = sup >> 4;
+ for (let i = 0; i < 8; i ++) {
+ if (useWB) {
+ if (wbArr[i]) {
+ ctx.strokeStyle = activePixel;
+ } else {
+ ctx.strokeStyle = inactivePixel;
+ };
+ } else {
+ if (sub > 0 || (sub == 0 && i != 0)) {
+ ctx.strokeStyle = activePixel;
+ } else {
+ ctx.strokeStyle = inactivePixel;
+ };
+ sub --;
+ };
+ let invI = 7 - i;
+ ctx.beginPath();
+ ctx.arc(offsetX, 256, (9 - invI) * mprWidth, startA, endA);
+ ctx.lineWidth = paramH;
+ ctx.stroke();
+ };
+};
+
+Math.sum = function (...args) {
+ let sum = 0;
+ args.forEach((e) => {
+ sum += e;
+ });
+ return sum;
+};
+
+CanvasRenderingContext2D.prototype.radial = function (centreX, centreY, angle, startR, stopR) {
+ let adjAngle = angle - 1.5707963267948966;
+ let vSin = Math.sin(adjAngle);
+ let vCos = Math.cos(adjAngle);
+ this.beginPath();
+ this.moveTo(centreX + (vSin * startR), centreY + (vCos * startR));
+ this.lineTo(centreX + (vSin * stopR), centreY + (vCos * stopR));
+ this.stroke();
+};
+
+let MuDisplay = class extends RootDisplay {
+ #mmdb = new Uint8Array(1360);
+ #pmdb = new Uint8Array(200);
+ #bmdb = new Uint8Array(256);
+ #bmst = 0; // 0 for voice bank, 2 for standard, 1 for sysex
+ #bmex = 0; // state expiration
+ #ch = 0;
+ #minCh = 0;
+ #maxCh = 0;
+ inWB = false;
+ #waveBuffer = new Uint8Array(8);
+ #panStrokes = new Uint8Array(7);
+ xgFont = new MxFont40("./data/bitmaps/xg/font.tsv");
+ sysBm = new MxBm256("./data/bitmaps/xg/system.tsv");
+ voxBm = new MxBm256("./data/bitmaps/xg/voices.tsv");
+ aniBm = new MxBm256("./data/bitmaps/xg/animation.tsv");
+ constructor() {
+ super(new OctaviaDevice());
+ let upThis = this;
+ this.addEventListener("mode", function (ev) {
+ (upThis.sysBm.getBm(`st_${({"gm":"gm1","g2":"gm2","?":"gm1","ns5r":"korg","ag10":"korg","x5d":"korg","05rw":"korg","krs":"korg","sg":"gm1","k11":"gm1"})[ev.data] || ev.data}`) || []).forEach(function (e, i) {
+ upThis.#bmdb[i] = e;
+ });
+ upThis.#bmst = 2;
+ upThis.#bmex = Date.now() + 1600;
+ });
+ this.addEventListener("channelactive", (ev) => {
+ this.#ch = ev.data;
+ });
+ this.addEventListener("channelmin", (ev) => {
+ if (ev.data >= 0) {
+ this.#minCh = ev.data + 1;
+ };
+ });
+ this.addEventListener("channelmax", (ev) => {
+ if (ev.data > this.#minCh - 1) {
+ this.#maxCh = ev.data + 1;
+ } else {
+ this.#minCh = 0;
+ this.#maxCh = 0;
+ };
+ });
+ this.addEventListener("channelreset", () => {
+ this.#minCh = 0;
+ this.#maxCh = 0;
+ this.#waveBuffer.fill(0);
+ this.demoInfo = false;
+ });
+ };
+ setCh(ch) {
+ this.#ch = ch;
+ };
+ getCh() {
+ return this.#ch;
+ };
+ reset() {
+ super.reset();
+ this.#minCh = 0;
+ this.#maxCh = 0;
+ if (this.demoInfo) {
+ delete this.demoInfo;
+ };
+ };
+ render(time, ctx) {
+ let sum = super.render(time);
+ let upThis = this;
+ let timeNow = Date.now();
+ // Fill with green
+ //ctx.fillStyle = "#af2";
+ ctx.fillStyle = `${backlight.grYellow}64`;
+ ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+ // Main matrix display
+ this.#mmdb.forEach((e, i, a) => {a[i] = 0});
+ // Part display
+ this.#pmdb.forEach((e, i, a) => {a[i] = 0});
+ // Strength
+ let alreadyMin = false;
+ let minCh = 0, maxCh = 0;
+ sum.chInUse.forEach(function (e, i) {
+ if (e) {
+ if (!alreadyMin) {
+ alreadyMin = true;
+ minCh = i;
+ };
+ maxCh = i;
+ };
+ });
+ let part = minCh >> 4;
+ minCh = part << 4;
+ maxCh = ((maxCh >> 4) << 4) + 15;
+ if (this.#ch > maxCh) {
+ this.#ch = minCh + this.#ch & 15;
+ };
+ if (this.#ch < minCh) {
+ this.#ch = maxCh - 15 + (this.#ch & 15);
+ };
+ if (this.#minCh && this.#minCh > 0) {
+ minCh = this.#minCh - 1;
+ };
+ if (this.#maxCh && this.#maxCh <= 128) {
+ maxCh = this.#maxCh - 1;
+ };
+ let chOff = this.#ch * ccToPos.length;
+ let rendMode = Math.ceil(Math.log2(maxCh - minCh + 1) - 4),
+ rendPos = 0;
+ let showLsb = !sum.chContr[chOff + ccToPos[0]];
+ if (timeNow <= sum.letter.expire && sum.letter.text.length > 0) {
+ // Show display text
+ upThis.xgFont.getStr(sum.letter.text.padEnd(32, " ")).forEach(function (e0, i0) {
+ let regionX = (i0 % 16) * 5 + 5,
+ regionY = Math.floor(i0 / 16) * 8;
+ e0.forEach(function (e1, i1) {
+ let partX = i1 % 5,
+ partY = Math.floor(i1 / 5);
+ upThis.#mmdb[(regionY + partY) * 85 + regionX + partX] = e1;
+ });
+ });
+ } else {
+ // Show strength metre
+ upThis.#mmdb[1275] = 1;
+ upThis.#mmdb[1276] = 1;
+ upThis.#mmdb[1278] = 1;
+ upThis.#mmdb[1279] = 1;
+ for (let ch = minCh; ch <= maxCh; ch ++) {
+ let curStrn = sum.strength[ch];
+ if (rendMode) {
+ curStrn = curStrn >> 5;
+ } else {
+ curStrn = curStrn >> 4;
+ };
+ if (rendMode == 0 || rendMode == 1) {
+ // 16 channel
+ for (let pI = 0; pI <= curStrn; pI ++) {
+ let pR = 5 + rendPos * 3 + (15 - pI) * 85 - Math.floor(rendPos / 2);
+ upThis.#mmdb[pR] = 1;
+ upThis.#mmdb[pR + 1] = 1;
+ };
+ } else {
+ // 64 channel
+ for (let pI = 0; pI <= curStrn; pI ++) {
+ let pR = 5 + rendPos * 3 + (15 - pI) * 85 - Math.floor(rendPos / 2);
+ if (rendPos > 31) {
+ pR -= 760;
+ };
+ upThis.#mmdb[pR] = 1;
+ upThis.#mmdb[pR + 1] = 1;
+ };
+ };
+ rendPos ++;
+ };
+ // Render fonts
+ if (rendMode < 2) {
+ let voiceName = (upThis.getChVoice(this.#ch).name).slice(0, 8).padEnd(8, " ");
+ let bnkSel = (sum.chContr[chOff + ccToPos[0]] == 64 ? "SFX" : sum.chContr[chOff + ccToPos[0]] || sum.chContr[chOff + ccToPos[32]] || 0).toString().padStart(3, "0");
+ if (upThis.getMode() == "xg") {
+ if ([80, 81, 82, 83, 84, 96, 97, 98, 99, 100].indexOf(sum.chContr[chOff + ccToPos[0]]) > -1) {
+ bnkSel = `${sum.chContr[chOff + ccToPos[32]] || 0}`.padStart(3, "0");
+ showLsb = true;
+ };
+ };
+ let bnkInfo = `\u0080${bnkSel}\u0081${((sum.chProgr[this.#ch] || 0) + 1).toString().padStart(3, "0")}`;
+ let bitSeq = upThis.xgFont.getStr(bnkInfo + voiceName);
+ bitSeq.forEach(function (e0, i0) {
+ let regionX = 0, regionY = 0;
+ if (rendMode == 1) {
+ regionX = i0 * 5;
+ } else if (!rendMode) {
+ regionX = (i0 % 8) * 5 + 45,
+ regionY = 8 - Math.floor(i0 / 8) * 8;
+ };
+ e0.forEach(function (e1, i1) {
+ let partX = i1 % 5,
+ partY = Math.floor(i1 / 5);
+ if (rendMode == 1 && i0 > 7) {
+ partX = partX + 5;
+ };
+ upThis.#mmdb[(regionY + partY) * 85 + regionX + partX] = e1;
+ });
+ });
+ };
+ };
+ // Commit to main screen
+ for (let i = 0; i < 1360; i ++) {
+ let pX = i % 85;
+ let pY = Math.floor(i / 85);
+ ctx.fillStyle = inactivePixel;
+ if (upThis.#mmdb[i]) {
+ ctx.fillStyle = activePixel;
+ };
+ ctx.fillRect(16 + (pX + Math.floor(pX / 5)) * mprWidth, 12 + pY * mprWidth, mpaWidth, mpaWidth);
+ };
+ ctx.textAlign = "center";
+ ctx.font = '12px "Arial Web"';
+ // Display parts under strengths
+ {
+ let initOff = 71.5;
+ for (let c = -2; c < 32; c ++) {
+ ctx.fillStyle = activePixel;
+ if (c + minCh == this.#ch) {
+ ctx.fillStyle = inactivePixel;
+ };
+ let filler = "";
+ if (c >= 0) {
+ filler = (c + 1).toString().padStart(2, "0");
+ } else {
+ filler = `A${c + 3}`;
+ };
+ ctx.fillText(filler, initOff + 24 * c, 150);
+ };
+ };
+ // Show bottom caps
+ ctx.fillStyle = showLsb ? inactivePixel : activePixel;
+ ctx.fillText("MSB", 515, 164);
+ ctx.fillStyle = showLsb ? activePixel : inactivePixel;
+ ctx.fillText("LSB", 564, 164);
+ ctx.fillStyle = activePixel;
+ ctx.fillText("BANK", 467.5, 164);
+ ctx.fillText("PRG#", 660, 164);
+ ctx.fillText("CHANNEL SEC PART", 118, 254);
+ ctx.fillText("VOL", 420, 254);
+ ctx.fillText("EXP", 468, 254);
+ ctx.fillText("BRT", 516, 254);
+ ctx.fillText("REV", 648, 254);
+ ctx.fillText("CHO", 696.5, 254);
+ ctx.fillText("VAR", 745, 254);
+ ctx.fillText("KEY", 801, 254);
+ ctx.fillText("PAN", 583, 254);
+ // Show parts
+ upThis.xgFont.getStr(`${(this.#ch + 1).toString().padStart(2, "0")}${"ABCDEFGH"[this.#ch >> 4]}${(this.#ch % 16 + 1).toString().padStart(2, "0")}`).forEach(function (e0, i0) {
+ let regionX = i0 * 5;
+ e0.forEach(function (e1, i1) {
+ let partX = i1 % 5,
+ partY = Math.floor(i1 / 5);
+ upThis.#pmdb[partY * 25 + regionX + partX] = e1;
+ });
+ });
+ // Commit to part screen
+ for (let i = 0; i < 200; i ++) {
+ let pX = i % 25;
+ let pY = Math.floor(i / 25);
+ ctx.fillStyle = inactivePixel;
+ if (upThis.#pmdb[i]) {
+ ctx.fillStyle = activePixel;
+ };
+ ctx.fillRect(16 + (pX + Math.floor(pX / 5)) * mprWidth, 180 + pY * mprWidth, mpaWidth, mpaWidth);
+ };
+ // Fetch voice bitmap
+ // Commit to bitmap screen
+ let useBm;
+ if (timeNow <= sum.bitmap.expire) {
+ // Use provided bitmap
+ useBm = sum.bitmap.bitmap;
+ } else if (this.demoInfo && time > 0) {
+ let sequence = this.demoInfo.class || "boot";
+ let stepTime = this.demoInfo.fps || 2;
+ let stepSize = this.demoInfo.size || 4;
+ let stepId = `${sequence}_${Math.floor(time * stepTime % stepSize)}`;
+ useBm = this.aniBm?.getBm(stepId) || this.sysBm?.getBm(stepId) || this.sysBm?.getBm("no_abm");
+ if (!useBm) {
+ useBm = this.#bmdb.slice();
+ };
+ } else {
+ // Use stored pic
+ useBm = this.#bmdb.slice();
+ if (timeNow >= this.#bmex) {
+ this.#bmst = 0;
+ let standard = upThis.getChVoice(this.#ch).standard.toLowerCase();
+ useBm = this.voxBm.getBm(upThis.getChVoice(this.#ch).name) || this.voxBm.getBm(upThis.getVoice(sum.chContr[chOff] + ccToPos[0], sum.chProgr[this.#ch], 0, sum.mode).name);
+ if (["an", "ap", "dr", "dx", "pc", "pf", "sg", "vl"].indexOf(standard) > -1) {
+ useBm = this.sysBm.getBm(`ext_${standard}`);
+ };
+ if (!useBm && (sum.chContr[chOff + ccToPos[0]] < 48 || sum.chContr[chOff + ccToPos[0]] == 56)) {
+ useBm = this.voxBm.getBm(upThis.getVoice(0, sum.chProgr[this.#ch], 0, sum.mode).name)
+ };
+ if (!useBm && (sum.chContr[chOff] + ccToPos[0]) == 126) {
+ useBm = this.sysBm.getBm("cat_smpl");
+ };
+ if (!useBm && (sum.chContr[chOff] + ccToPos[0]) == 64) {
+ useBm = this.sysBm.getBm("cat_sfx");
+ };
+ if (!useBm) {
+ useBm = this.sysBm.getBm("no_abm");
+ };
+ } else {
+ if (this.#bmst == 2) {
+ useBm.forEach((e, i, a) => {
+ let crit = Math.floor((this.#bmex - timeNow) / 400);
+ a[i] = crit % 2 == e;
+ });
+ };
+ };
+ };
+ for (let i = 0; i < 256; i ++) {
+ let pX = i % 16;
+ let pY = Math.floor(i / 16);
+ ctx.fillStyle = inactivePixel;
+ if (useBm && useBm[i]) {
+ ctx.fillStyle = activePixel;
+ };
+ ctx.fillRect(260 + pX * mprWidth, 180 + pY * mprHeight, mpaWidth, mpaHeight);
+ };
+ // Move waveBuffer
+ let useWB = time && this.demoInfo;
+ if (useWB && Math.floor(time * 25) & 1) {
+ for (let i = 6; i >= 0; i --) {
+ this.#waveBuffer[i + 1] = this.#waveBuffer[i];
+ };
+ this.#waveBuffer[0] = +(sum.velo[this.#ch] > 159);
+ };
+ // Show param
+ normParamPaint(sum.chContr[chOff + ccToPos[7]], 404, ctx); // vol
+ normParamPaint(sum.chContr[chOff + ccToPos[11]], 452, ctx); // exp
+ normParamPaint(sum.chContr[chOff + ccToPos[74]], 500, ctx); // bri
+ efxParamPaint(sum.chContr[chOff + ccToPos[91]], 648, ctx, useWB, this.#waveBuffer); // rev
+ efxParamPaint(sum.chContr[chOff + ccToPos[93]], 696, ctx, useWB, this.#waveBuffer); // cho
+ efxParamPaint(sum.chContr[chOff + ccToPos[94]], 744, ctx, useWB, this.#waveBuffer); // var
+ // Show pan
+ ctx.beginPath();
+ ctx.arc(582, 216, 34, 2.356194490192345, 7.068583470577034);
+ ctx.lineWidth = 2;
+ ctx.strokeStyle = "#000f";
+ ctx.stroke();
+ let pan = sum.chContr[chOff + ccToPos[10]];
+ this.#panStrokes.forEach((e, i, a) => {a[i] = 0});
+ if (pan == 0) {
+ this.#panStrokes[0] = 1;
+ } else if (pan == 64) {
+ this.#panStrokes[3] = 1;
+ } else if (pan == 128) {
+ this.#panStrokes[1] = 1;
+ this.#panStrokes[5] = 1;
+ } else if (pan < 64) {
+ this.#panStrokes[Math.floor(pan / 21)] = 1;
+ } else {
+ this.#panStrokes[4 + Math.floor((pan - 65) / 21)] = 1;
+ };
+ ctx.lineWidth = mprHeight;
+ for (let i = 0; i < 7; i ++) {
+ ctx.strokeStyle = inactivePixel;
+ if (this.#panStrokes[i]) {
+ ctx.strokeStyle = activePixel;
+ };
+ ctx.radial(582, 216, [
+ 7.068583470577034,
+ 6.283185307179586,
+ 5.497787143782138,
+ 4.71238898038469,
+ 3.9269908169872414,
+ 3.141592653589793,
+ 2.356194490192345
+ ][i], 8, 26)
+ };
+ };
+};
+
+export default MuDisplay;
diff --git a/src/disp/disp_n5.mjs b/src/disp/disp_n5.mjs
new file mode 100644
index 00000000..fe737d6c
--- /dev/null
+++ b/src/disp/disp_n5.mjs
@@ -0,0 +1,423 @@
+"use strict";
+
+import {OctaviaDevice} from "../state/index.mjs";
+import {RootDisplay, ccToPos} from "../basic/index.mjs";
+import {MxFont40, MxBmDef} from "../basic/mxReader.js";
+
+import {
+ bgGreen,
+ bgOrange,
+ bgWhite,
+ bgRed,
+ lcdCache
+} from "./colour.js";
+
+let Ns5rDisplay = class extends RootDisplay {
+ #omdb = new Uint8Array(5760); // Full display
+ #nmdb = new Uint8Array(5760); // Full display, but on commit
+ #dumpData;
+ #dumpExpire = 0;
+ #mode = "?";
+ #ch = 0;
+ #backlight;
+ #refreshed = true;
+ xgFont = new MxFont40("./data/bitmaps/xg/font.tsv");
+ trueFont = new MxFont40("./data/bitmaps/korg/font.tsv", "./data/bitmaps/xg/font.tsv");
+ element = new MxBmDef("./data/bitmaps/korg/element.tsv");
+ constructor() {
+ super(new OctaviaDevice(), 0.1, 0.9);
+ this.#backlight = bgWhite;
+ this.addEventListener("mode", (ev) => {
+ this.#backlight = {
+ "gs": bgOrange,
+ "mt32": bgOrange,
+ "xg": bgGreen,
+ "ns5r": bgGreen,
+ "x5d": bgGreen,
+ "ag10": bgRed,
+ "05rw": bgGreen,
+ "k11": bgGreen,
+ "gmlx": bgGreen,
+ "sg01": bgRed,
+ "s90es": bgGreen,
+ "motif": bgGreen
+ }[ev.data] || bgWhite;
+ this.#mode = ev.data;
+ this.#refreshed = true;
+ });
+ this.addEventListener("screen", (ev) => {
+ console.debug(ev);
+ if (ev.data.type == "ns5r") {
+ this.#dumpData = ev.data.data;
+ this.#dumpExpire = Date.now() + 1600;
+ };
+ });
+ };
+ setCh(ch) {
+ this.#ch = ch;
+ };
+ getCh() {
+ return this.#ch;
+ };
+ #renderParamBox(startX, value) {
+ // Draw the lever rest
+ for (let p = 0; p < 180; p ++) {
+ let pX = p % 12, pY = Math.floor(p / 12);
+ if (
+ (pY == 0 && pX < 11) ||
+ (pY == 14 && pX > 0) ||
+ (pY == 13)
+ ) {
+ this.#nmdb[pY * 144 + pX + startX] = 1;
+ } else if (pY > 0 && pY < 13) {
+ if (
+ pX == 0 || pX > 9 ||
+ (pX == 5 && pY > 1 && pY < 12)
+ ) {
+ this.#nmdb[pY * 144 + pX + startX] = 1;
+ };
+ };
+ };
+ let convertedValue = value >> 4;
+ // Draw the lever
+ for (let c = 0; c < 21; c ++) {
+ let pX = c % 7, pY = Math.floor(c / 7),
+ pcY = pY + (9 - convertedValue);
+ if (pY != 1 || pX == 0 || pX == 6) {
+ this.#nmdb[pcY * 144 + pX + startX + 2] = 1;
+ } else {
+ this.#nmdb[pcY * 144 + pX + startX + 2] = 0;
+ };
+ };
+ };
+ #renderLine(srcX, srcY, diffX, diffY) {
+ //console.debug(diffX, diffY);
+ srcX = (srcX < 0 ? Math.ceil : Math.floor)(srcX);
+ srcY = (srcY < 0 ? Math.ceil : Math.floor)(srcY);
+ diffX = Math.round(diffX);
+ diffY = Math.round(diffY);
+ if (Math.abs(diffX) < Math.abs(diffY)) {
+ let theta = diffX / diffY;
+ if (diffY < 0) {
+ for (let p = 0; p >= diffY; p --) {
+ this.#nmdb[Math.round(theta * p + srcX) + (srcY + p) * 144] = 1;
+ };
+ } else {
+ for (let p = 0; p <= diffY; p ++) {
+ this.#nmdb[Math.round(theta * p + srcX) + (srcY + p) * 144] = 1;
+ };
+ };
+ } else {
+ let theta = diffY / diffX;
+ if (diffX < 0) {
+ for (let p = 0; p >= diffX; p --) {
+ this.#nmdb[Math.round(theta * p + srcY) * 144 + srcX + p] = 1;
+ };
+ } else {
+ for (let p = 0; p <= diffX; p ++) {
+ this.#nmdb[Math.round(theta * p + srcY) * 144 + srcX + p] = 1;
+ };
+ };
+ };
+ };
+ #renderCompass(startX, startY, value) {
+ let radius = 7, circleStep = 40;
+ for (let c = 0; c < circleStep; c ++) {
+ let angle = Math.PI * c * 2 / circleStep;
+ let intX = radius * Math.sin(angle),
+ drawX = Math.sign(intX) * Math.round(Math.abs(intX));
+ let intY = radius * Math.cos(angle),
+ drawY = Math.sign(intY) * Math.round(Math.abs(intY));
+ this.#nmdb[(drawY + startY) * 144 + drawX + startX] = 1;
+ };
+ if (value < 128) {
+ let normAngle = Math.floor(value / 9.85) * 22.5;
+ //let normAngle = Math.floor(value * 2.126);
+ let lineStep = 5, angle = Math.PI * (315 - normAngle) / 180;
+ let deltaX = Math.sin(angle), deltaY = Math.cos(angle);
+ /* for (let c = 0; c <= lineStep; c ++) {
+ let drawX = Math.round(c * deltaX),
+ drawY = Math.round(c * deltaY);
+ this.#nmdb[(drawY + startY) * 144 + drawX + startX] = 1;
+ }; */
+ this.#renderLine(startX, startY, deltaX * lineStep, deltaY * lineStep);
+ } else {
+ this.#nmdb[(startY) * 144 + startX] = 1;
+ };
+ };
+ render(time, ctx, trueMode) {
+ let sum = super.render(time);
+ let upThis = this;
+ let timeNow = Date.now();
+ // Channel test
+ let alreadyMin = false;
+ let minCh = 0, maxCh = 0;
+ sum.chInUse.forEach(function (e, i) {
+ if (e) {
+ if (!alreadyMin) {
+ alreadyMin = true;
+ minCh = i;
+ };
+ maxCh = i;
+ };
+ });
+ let part = minCh >> 4;
+ minCh = part << 4;
+ maxCh = ((maxCh >> 4) << 4) + 15;
+ if (this.#ch > maxCh) {
+ this.#ch = minCh + this.#ch & 15;
+ };
+ if (this.#ch < minCh) {
+ this.#ch = maxCh - 15 + (this.#ch & 15);
+ };
+ let chOff = this.#ch * ccToPos.length;
+ if (timeNow < this.#dumpExpire) {
+ this.#dumpData?.forEach((e, i) => {
+ this.#nmdb[i] = e;
+ });
+ } else {
+ // Clear out the current working display buffer.
+ this.#nmdb.forEach((e, i, a) => {a[i] = 0});
+ // Screen buffer write begin.
+ // Determine the used font
+ let targetFont = trueMode ? this.trueFont : this.xgFont;
+ // Show current channel
+ targetFont.getStr(`${"ABCDEFGH"[this.#ch >> 4]}${((this.#ch & 15) + 1).toString().padStart(2, "0")}`).forEach((e0, i0) => {
+ let secX = i0 * 6 + 1;
+ e0.forEach((e1, i1) => {
+ let charX = i1 % 5,
+ charY = Math.floor(i1 / 5);
+ this.#nmdb[charY * 144 + secX + charX] = e1;
+ });
+ });
+ // Show current pitch shift
+ let cPit = this.device.getPitchShift(this.#ch);
+ targetFont.getStr(`${"+-"[+(cPit < 0)]}${Math.round(Math.abs(cPit)).toString().padStart(2, "0")}`).forEach((e0, i0) => {
+ let secX = i0 * 6 + 1;
+ e0.forEach((e1, i1) => {
+ let charX = i1 % 5,
+ charY = Math.floor(i1 / 5) + 8;
+ this.#nmdb[charY * 144 + secX + charX] = e1;
+ });
+ });
+ // Render bank background
+ let bankFetched = upThis.getChVoice(this.#ch), bankInfo = bankFetched.sect;
+ for (let bankSect = 0; bankSect < 225; bankSect ++) {
+ let pixX = bankSect % 25, pixY = Math.floor(bankSect / 25) + 15;
+ this.#nmdb[pixY * 144 + pixX] = 1;
+ };
+ targetFont.getStr(bankInfo).forEach((e0, i0) => {
+ let secX = i0 * 6 + 1;
+ e0.forEach((e1, i1) => {
+ let charX = i1 % 5,
+ charY = Math.floor(i1 / 5) + 16;
+ if (e1) {
+ this.#nmdb[charY * 144 + secX + charX] = 0;
+ };
+ });
+ });
+ // Render program info
+ let bankName = (bankFetched.name).slice(0, 10).padEnd(10, " ");
+ targetFont.getStr(`:${(sum.chProgr[this.#ch] + 1).toString().padStart(3, "0")}`).forEach((e0, i0) => {
+ let secX = i0 * 6 + 25;
+ e0.forEach((e1, i1) => {
+ let charX = i1 % 5,
+ charY = Math.floor(i1 / 5) + 16;
+ this.#nmdb[charY * 144 + secX + charX] = e1;
+ });
+ });
+ targetFont.getStr(bankName).forEach((e0, i0) => {
+ let secX = i0 * 6 + 53;
+ e0.forEach((e1, i1) => {
+ let charX = i1 % 5,
+ charY = Math.floor(i1 / 5) + 16;
+ this.#nmdb[charY * 144 + secX + charX] = e1;
+ });
+ })
+ // Render current channel
+ targetFont.getStr(`${this.#ch + 1}`.padStart(2, "0")).forEach((e0, i0) => {
+ let secX = i0 * 6;
+ e0.forEach((e1, i1) => {
+ let charX = i1 % 5,
+ charY = Math.floor(i1 / 5) + 32;
+ this.#nmdb[charY * 144 + secX + charX] = e1;
+ });
+ });
+ // Render channel strength
+ let showReduction = 22;
+ if (maxCh > 31) {
+ showReduction = 43;
+ };
+ sum.strength.forEach((e, i) => {
+ if (maxCh < 32 && i > 31) {
+ return;
+ };
+ for (let c = Math.floor(e / showReduction); c >= 0; c --) {
+ let pixX = (i % 32) * 4 + 12,
+ pixY = (i > 31 ? 32 : 39) - c;
+ if (trueMode) {
+ pixX ++;
+ };
+ this.#nmdb[pixY * 144 + pixX] = 1;
+ this.#nmdb[pixY * 144 + pixX + 1] = 1;
+ this.#nmdb[pixY * 144 + pixX + 2] = 1;
+ };
+ });
+ // Render effect types
+ let efxShow = this.device.aiEfxName.slice(0, 7 + +trueMode) || "Rev/Cho";
+ targetFont.getStr(trueMode ? `Fx A:001${efxShow}` : `FxA:001${efxShow}`).forEach((e0, i0) => {
+ let lineChars = trueMode ? 8 : 7;
+ let secX = (i0 % lineChars) * 6 + (trueMode ? 95 : 102),
+ secY = Math.floor(i0 / lineChars) * 8;
+ e0.forEach((e1, i1) => {
+ let charX = i1 % 5,
+ charY = Math.floor(i1 / 5) + secY;
+ this.#nmdb[charY * 144 + secX + charX] = e1;
+ });
+ });
+ // Render letter displays
+ if (timeNow < sum.letter.expire) {
+ let xShift = 19 + (+trueMode) * 3;
+ // White bounding box
+ for (let i = 0; i < 2000; i ++) {
+ let x = i % 100, y = Math.floor(i / 100);
+ // Top and bottom borders
+ if (
+ (y == 0 && x < 99) ||
+ (y == 18) ||
+ (y == 19 && x > 0)
+ ) {
+ this.#nmdb[y * 144 + x + xShift] = 1;
+ };
+ if (y > 0 && y < 18) {
+ this.#nmdb[y * 144 + x + xShift] = +(x < 1 || x > 97);
+ };
+ };
+ // Actual text
+ targetFont.getStr(sum.letter.text).forEach((e0, i0) => {
+ let secX = (i0 % 16) * 6 + xShift + 2,
+ secY = Math.floor(i0 / 16) * 8 + 2;
+ e0.forEach((e1, i1) => {
+ let charX = i1 % 5,
+ charY = Math.floor(i1 / 5) + secY;
+ this.#nmdb[charY * 144 + secX + charX] = e1;
+ });
+ });
+ } else {
+ // Render params only when it's not covered
+ let xShift = trueMode ? 2 : 0;
+ this.#renderParamBox(20 + xShift, sum.chContr[chOff + ccToPos[7]]);
+ this.#renderParamBox(33 + xShift, sum.chContr[chOff + ccToPos[11]]);
+ if (trueMode) {
+ if (sum.chContr[chOff + ccToPos[10]] < 128) {
+ this.element.getBm(`Pan_${Math.floor(sum.chContr[chOff + ccToPos[10]] / 9.85)}`)?.render((e, x, y) => {
+ this.#nmdb[y * 144 + x + 48] = e;
+ });
+ } else {
+ this.element.getBm("PanRndm")?.render((e, x, y) => {
+ this.#nmdb[y * 144 + x + 48] = e;
+ });
+ };
+ } else {
+ this.#renderCompass(53, 7, sum.chContr[chOff + ccToPos[10]]);
+ };
+ this.#renderParamBox(62 + 2 * (+trueMode) + xShift - (+trueMode), sum.chContr[chOff + ccToPos[91]]);
+ this.#renderParamBox(75 + 2 * (+trueMode) + xShift - (+trueMode), sum.chContr[chOff + ccToPos[93]]);
+ if (!trueMode) {
+ this.#renderParamBox(88, sum.chContr[chOff + ccToPos[74]]);
+ };
+ };
+ // Render bitmap displays
+ if (timeNow < sum.bitmap.expire) {
+ // White bounding box
+ for (let i = 0; i < 777; i ++) {
+ let x = i % 37, y = Math.floor(i / 37);
+ let realX = x + 77 + (+trueMode), realY = y + 19;
+ // Top and bottom borders
+ if (
+ (y == 0 && x < 36) ||
+ (y == 19) ||
+ (y == 20 && x > 0)
+ ) {
+ this.#nmdb[realY * 144 + realX] = 1;
+ };
+ if (y > 0 && y < 19) {
+ this.#nmdb[realY * 144 + realX] = +(x < 1 || x > 34);
+ };
+ };
+ // Actual bitmap
+ let colUnit = (sum.bitmap.bitmap.length == 512) ? 1 : 2;
+ for (let i = 0; i < 512; i += colUnit) {
+ let x = i & 31, y = i >> 5;
+ let realX = x + 79 + (+trueMode), realY = y + 21;
+ this.#nmdb[realY * 144 + realX] = sum.bitmap.bitmap[i / colUnit];
+ if (colUnit == 2) {
+ this.#nmdb[realY * 144 + realX + 1] = sum.bitmap.bitmap[i / colUnit];
+ };
+ };
+ };
+ };
+ // Screen buffer write finish.
+ // Determine if full render is required.
+ let drawPixMode = false;
+ if (this.#refreshed) {
+ // Full render required.
+ // Clear all pixels.
+ ctx.fillStyle = this.#backlight.replace("64", "");
+ ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+ ctx.textAlign = "center";
+ ctx.font = '11px "Arial Web"';
+ ctx.fillStyle = "#000e";
+ ctx.fillText("MIDI. CH", 58, 10);
+ ctx.fillText("VOL", 153.5, 10);
+ ctx.fillText("EXP", 231.5, 10);
+ ctx.fillText("PAN", 322.5, 10);
+ ctx.fillText("REV", 405, 10);
+ ctx.fillText("CHO", 484, 10);
+ ctx.fillText("BRT", 561.5, 10);
+ ctx.fillText("EFFECT TYPE", 738, 10);
+ ctx.fillText("PART", 34, 262);
+ let circle = 2 * Math.PI;
+ for (let c = 1; c < 33; c ++) {
+ if (c == 1 || c == 32 || c % 5 == 0) {
+ ctx.fillText(`${c}`, 24 * c + 58, 262);
+ } else {
+ ctx.beginPath();
+ ctx.ellipse(
+ 24 * c + 58,
+ 258,
+ 2, 2,
+ 0, 0, circle
+ );
+ ctx.fill();
+ };
+ };
+ drawPixMode = true;
+ this.#refreshed = false;
+ };
+ // Commit to display accordingly.
+ this.#nmdb.forEach((e, i) => {
+ let pixX = i % 144, pixY = Math.floor(i / 144);
+ let hasDifference = this.#omdb[i] != e;
+ if (!drawPixMode && hasDifference) {
+ ctx.fillStyle = this.#backlight.slice(0, 7);
+ ctx.fillRect(6 * pixX + 1, 12 + 6 * pixY, 6, 6);
+ };
+ if (drawPixMode || hasDifference) {
+ ctx.fillStyle = lcdCache.black[e + 3];
+ if (drawPixMode) {
+ ctx.fillStyle = ctx.fillStyle.slice(0, 7);
+ };
+ ctx.fillRect(6 * pixX + 1, 12 + 6 * pixY, 5.5, 5.5);
+ };
+ });
+ // Commit to old display buffer.
+ this.#nmdb.forEach((e, i) => {
+ if (this.#omdb[i] != e) {
+ this.#omdb[i] = e;
+ };
+ });
+ };
+};
+
+export default Ns5rDisplay;
diff --git a/src/disp/disp_psr.mjs b/src/disp/disp_psr.mjs
new file mode 100644
index 00000000..8a6729b8
--- /dev/null
+++ b/src/disp/disp_psr.mjs
@@ -0,0 +1,469 @@
+"use strict";
+
+import {OctaviaDevice} from "../state/index.mjs";
+import {RootDisplay, ccToPos} from "../basic/index.mjs";
+import {MxFont40, MxBm256} from "../basic/mxReader.js";
+
+import {
+ inactivePixel,
+ mediumPixel,
+ activePixel
+} from "./colour.js";
+
+let PsrDisplay = class extends RootDisplay {
+ // #okdb = new Uint8Array(61);
+ #nkdb = new Uint8Array(61);
+ // #osdb = new Uint8Array(22);
+ #nsdb = new Uint8Array(22);
+ #nadb = new Uint8Array(15);
+ #bmdb = new Uint8Array(256);
+ #bmst = 0;
+ #bmex = 0;
+ #ch = 0;
+ xgFont = new MxFont40("./data/bitmaps/xg/font.tsv");
+ trueFont = new MxFont40("./data/bitmaps/korg/font.tsv");
+ sysBm = new MxBm256("./data/bitmaps/xg/system.tsv");
+ voxBm = new MxBm256("./data/bitmaps/xg/voices.tsv");
+ aniBm = new MxBm256("./data/bitmaps/xg/animation.tsv");
+ clefs = new Path2D("M110 163.5c0 -3.9 3.2 -7.1 7.1 -7.1s7.1 3.2 7.1 7.1s-3.2 7.1 -7.1 7.1s-7.1 -3.2 -7.1 -7.1zM110 128.5c0 -3.9 3.2 -7.1 7.1 -7.1s7.1 3.2 7.1 7.1s-3.2 7.1 -7.1 7.1s-7.1 -3.2 -7.1 -7.1zM64.5 109.2c24.1 0 41 12.3 41 35.1c0 36.8 -36.8 58 -72.2 72.9c-0.4 0.4 -0.8 0.6 -1.3 0.6c-1 0 -1.8 -0.8 -1.8 -1.8c0 -0.4 0.1 -0.8 0.6 -1.3c28.3 -16.5 57.7 -37.1 57.7 -69c0 -16.8 -8.8 -32.9 -23.9 -32.9c-10.4 0 -18.1 7.6 -21.6 17.6c1.5 -0.7 3.1 -1.1 4.8 -1.1c7.7 0 14 6.3 14 14c0 8.1 -6.2 14.8 -14 14.8c-8.4 0 -15.7 -6.6 -15.7 -14.8c0 -18.6 14.3 -34.2 32.5 -34.2z M408.6 181.3c0.6 0 1.3 -0.1 1.8 -0.1c21.7 0 35.8 17.9 35.8 36.5c0 10.6 -4.6 21.6 -15 29.4c-3.1 2.4 -6.6 3.9 -10.2 5c0.4 4.9 0.7 9.8 0.7 14.7c0 2.7 -0.1 5.5 -0.3 8.1c-1 16.8 -12.6 31.9 -29.1 31.9c-15.1 0 -27.3 -12.3 -27.3 -27.6c0 -8.1 7.4 -14.4 15.7 -14.4c7.6 0 13.3 6.6 13.3 14.4c0 7.3 -6 13.3 -13.3 13.3 c-1.5 0 -2.9 -0.3 -4.3 -0.8c3.6 5.5 9.5 9.1 16.4 9.1c13.4 0 22 -12.9 22.8 -26.7c0.1 -2.5 0.3 -5.2 0.3 -7.7c0 -4.3 -0.1 -8.5 -0.6 -12.9c-4.1 0.7 -8.1 1.1 -12.5 1.1c-26.3 0 -46.6 -24.1 -46.6 -52.4c0 -24.8 18.3 -42.8 34.7 -61.7c-2.7 -8.7 -5.2 -17.5 -6.3 -26.6c-0.8 -7.3 -1 -14.6 -1 -21.8c0 -16.1 7.7 -31.4 20.9 -40.9c0.4 -0.3 1 -0.4 1.4 -0.4c0.6 0 1 0 1.4 0.4 c9.9 11.8 18.6 34.3 18.6 50.1c0 20 -12 35.7 -25.2 51c2.9 9.5 5.5 19.3 7.8 29zM420.5 246.4c9.5 -3.4 15.8 -13.3 15.8 -23c0 -12.6 -9.2 -25.1 -24.2 -26.6c3.4 16.2 6.4 32.3 8.4 49.6zM366.4 214.1c0 18.9 18.1 34.6 37 34.6c3.9 0 7.7 -0.3 11.5 -0.8c-2 -17.8 -5.2 -34.3 -8.8 -51c-11.1 1.1 -17.4 8.5 -17.4 16.7 c0 6.2 3.5 12.7 11.3 17.2c0.7 0.7 1 1.4 1 2.1c0 1.5 -1.4 3.1 -3.1 3.1c-0.4 0 -0.8 -0.1 -1.3 -0.3c-11.2 -6 -16.4 -16.1 -16.4 -25.9c0 -12.3 8.1 -24.4 22.4 -27.6c-2 -8.1 -4.1 -16.4 -6.4 -24.5c-15 16.9 -29.8 34 -29.8 56.4zM413.1 71.7c-13.9 6.7 -22.7 20.9 -22.7 36.3c0 10.4 2.5 18.6 5 27.2 c11.2 -13.6 20.4 -27.7 20.4 -45.4c0 -7.7 -0.6 -11.1 -2.8 -18.1z");
+ keyboard = new Path2D("M224 318 L380 318 L380 380 L224 380 Z M246 350 L246 380 M268 350 L268 380 M291 318 L291 380 M313 350 L313 380 M335 350 L335 380 M358 350 L358 380 M235 318 L235 350 L254 350 L254 318 M260 318 L260 350 L279 350 L279 318 M301 318 L301 350 L320 350 L320 318 M326 318 L326 350 L345 350 L345 318 M350 318 L350 350 L370 350 L370 318 M387 318 L543 318 L543 380 L387 380 Z M409 350 L409 380 M431 350 L431 380 M454 318 L454 380 M476 350 L476 380 M498 350 L498 380 M521 350 L521 380 M398 318 L398 350 L417 350 L417 318 M423 318 L423 350 L442 350 L442 318 M464 318 L464 350 L483 350 L483 318 M489 318 L489 350 L508 350 L508 318 M513 318 L513 350 L533 350 L533 318 M550 318 L706 318 L706 380 L550 380 Z M572 350 L572 380 M594 350 L594 380 M617 318 L617 380 M639 350 L639 380 M661 350 L661 380 M684 350 L684 380 M561 318 L561 350 L580 350 L580 318 M586 318 L586 350 L605 350 L605 318 M627 318 L627 350 L646 350 L646 318 M652 318 L652 350 L671 350 L671 318 M676 318 L676 350 L696 350 L696 318 M713 318 L869 318 L869 380 L713 380 Z M735 350 L735 380 M757 350 L757 380 M780 318 L780 380 M802 350 L802 380 M824 350 L824 380 M847 350 L847 380 M724 318 L724 350 L743 350 L743 318 M749 318 L749 350 L768 350 L768 318 M790 318 L790 350 L809 350 L809 318 M815 318 L815 350 L834 350 L834 318 M839 318 L839 350 L859 350 L859 318 M876 318 L1032 318 L1032 380 L876 380 Z M898 350 L898 380 M920 350 L920 380 M943 318 L943 380 M965 350 L965 380 M987 350 L987 380 M1010 350 L1010 380 M887 318 L887 350 L906 350 L906 318 M912 318 L912 350 L931 350 L931 318 M953 318 L953 350 L972 350 L972 318 M978 318 L978 350 L997 350 L997 318 M1002 318 L1002 350 L1022 350 L1022 318 M1032 318 L1055 318 L1055 380 L1032 380");
+ bracket = new Path2D("M83 23 L49 23 L49 86 L83 86 M264 23 L297 23 L297 86 L264 86");
+ staffLines = new Path2D("M30 110 L344 110 M356 110 L1074 110 M30 146 L344 146 M356 146 L1074 146 M30 182 L344 182 M356 182 L1074 182 M30 218 L344 218 M356 218 L1074 218 M30 254 L344 254 M356 254 L775 254 M894 254 L1074 254");
+ downbeatStar = new Path2D("m 160.263,824.43605 c 0.939,1.039 1.482,2.434 1.482,3.833 0,1.402 -0.543,2.796 -1.482,3.834 1.038,-0.944 2.43,-1.483 3.837,-1.483 1.398,0 2.791,0.539 3.828,1.483 -0.948,-1.038 -1.482,-2.432 -1.482,-3.834 0,-1.399 0.534,-2.794 1.482,-3.833 -1.037,0.945 -2.43,1.483 -3.828,1.483 -1.407,0 -2.799,-0.538 -3.837,-1.483");
+ downbeatHand = new Path2D("m 166.418,820.55105 c 0.13,0 0.253,-0.054 0.351,-0.143 0.089,-0.094 0.143,-0.223 0.143,-0.351 v -1.969 l 1.847,-6.897 c 0.706,-2.627 0.966,-5.371 0.78,-8.09 l -0.184,-2.644 1.188,-2.055 h -5.175 l -1.268,3.499 -1.278,-3.499 h -5.171 l 1.185,2.055 -0.185,2.644 c -0.185,2.719 0.076,5.463 0.782,8.09 l 1.847,6.897 v 1.969 c 0,0.128 0.054,0.257 0.145,0.351 0.089,0.089 0.218,0.143 0.348,0.143 h 0.214 c 0.423,0 0.841,-0.11 1.213,-0.321 0.364,-0.204 0.68,-0.509 0.9,-0.871 0.213,0.362 0.527,0.667 0.89,0.871 0.373,0.211 0.79,0.321 1.208,0.321 h 0.22 m -0.22,-1.304 c 0,0.111 -0.034,0.217 -0.095,0.303 -0.069,0.085 -0.164,0.147 -0.268,0.178 -0.103,0.024 -0.22,0.016 -0.317,-0.027 -0.315,-0.132 -0.588,-0.357 -0.78,-0.645 -0.185,-0.283 -0.289,-0.626 -0.289,-0.968 v -6.306 c 0.262,0.159 0.562,0.23 0.865,0.213 0.308,-0.023 0.595,-0.138 0.836,-0.329 0.233,-0.192 0.406,-0.454 0.488,-0.748 l 0.007,-0.017 c 0.379,-1.35 0.631,-2.734 0.747,-4.134 0.496,-0.497 0.797,-1.176 0.839,-1.876 0.046,-0.701 -0.172,-1.411 -0.591,-1.967 l -0.625,0.356 c 0.371,0.453 0.556,1.058 0.501,1.64 -0.054,0.584 -0.349,1.143 -0.801,1.517 -0.112,1.448 -0.365,2.889 -0.756,4.288 -0.055,0.178 -0.165,0.336 -0.323,0.436 -0.15,0.099 -0.343,0.145 -0.522,0.119 -0.184,-0.026 -0.356,-0.115 -0.472,-0.257 -0.124,-0.136 -0.193,-0.319 -0.193,-0.503 v -7.524 l 1.413,-3.887 h 3.453 l -0.687,1.18 0.199,2.865 c 0.186,2.636 -0.068,5.301 -0.756,7.853 l -1.873,6.989 z m -4.143,-1.251 -1.873,-6.989 c -0.681,-2.552 -0.94,-5.217 -0.755,-7.853 l 0.198,-2.865 -0.68,-1.18 h 3.446 l 1.412,3.887 v 7.524 c 0,0.184 -0.066,0.367 -0.185,0.503 -0.124,0.142 -0.295,0.231 -0.472,0.257 -0.185,0.026 -0.372,-0.02 -0.529,-0.119 -0.151,-0.1 -0.267,-0.258 -0.315,-0.436 -0.4,-1.399 -0.652,-2.84 -0.756,-4.288 -0.453,-0.374 -0.747,-0.933 -0.803,-1.517 -0.059,-0.582 0.125,-1.187 0.495,-1.64 l -0.618,-0.356 c -0.424,0.556 -0.637,1.266 -0.597,1.967 0.049,0.7 0.349,1.379 0.838,1.876 0.122,1.4 0.371,2.784 0.753,4.134 v 0.017 c 0.084,0.294 0.262,0.556 0.497,0.748 0.233,0.191 0.527,0.306 0.83,0.329 0.299,0.017 0.608,-0.054 0.862,-0.213 v 6.306 c 0,0.342 -0.095,0.685 -0.288,0.968 -0.184,0.288 -0.459,0.513 -0.774,0.645 -0.103,0.043 -0.212,0.051 -0.316,0.027 -0.104,-0.031 -0.199,-0.093 -0.268,-0.178 -0.069,-0.086 -0.102,-0.192 -0.102,-0.303 v -1.251");
+ upbeatHand = new Path2D("m 143.496,764.85205 -1.915,5.26 c -0.152,0.404 -0.158,0.856 -0.029,1.267 0.13,0.408 0.406,0.767 0.756,1.01 0.356,0.244 0.795,0.362 1.221,0.338 l -1.483,4.067 c -0.15,0.417 -0.136,0.885 0.035,1.291 0.163,0.409 0.494,0.744 0.893,0.926 0.403,0.186 0.87,0.209 1.288,0.075 -0.06,0.409 0.02,0.841 0.234,1.199 0.213,0.357 0.557,0.63 0.949,0.765 0.397,0.133 0.835,0.123 1.219,-0.032 0.384,-0.155 0.714,-0.445 0.913,-0.813 0.22,0.315 0.563,0.543 0.941,0.628 0.369,0.084 0.781,0.03 1.118,-0.151 0.336,-0.183 0.603,-0.496 0.733,-0.858 l 0.885,-2.412 c 0.222,0.306 0.565,0.529 0.94,0.611 0.371,0.083 0.776,0.029 1.112,-0.158 0.338,-0.186 0.596,-0.494 0.726,-0.851 l 2.074,-5.687 c 0.988,-2.715 0.803,-5.834 -0.493,-8.414 v -0.005 l -7.014,-2.549 c -1.152,0.262 -2.237,0.812 -3.128,1.595 -0.886,0.779 -1.577,1.784 -1.975,2.898 m 9.357,8.148 -0.665,-0.24 -2.484,6.824 c -0.076,0.217 -0.247,0.402 -0.453,0.497 -0.212,0.099 -0.459,0.11 -0.679,0.031 -0.218,-0.079 -0.406,-0.246 -0.501,-0.455 -0.096,-0.213 -0.109,-0.46 -0.026,-0.68 l 2.482,-6.823 -0.666,-0.241 -2.845,7.822 c -0.098,0.261 -0.303,0.48 -0.551,0.6 -0.253,0.118 -0.556,0.13 -0.815,0.036 -0.261,-0.097 -0.482,-0.3 -0.597,-0.55 -0.118,-0.253 -0.13,-0.551 -0.041,-0.813 l 2.846,-7.826 -0.666,-0.24 -2.483,6.823 c -0.095,0.262 -0.294,0.482 -0.548,0.602 -0.256,0.117 -0.549,0.129 -0.809,0.033 -0.262,-0.095 -0.488,-0.298 -0.606,-0.548 -0.115,-0.253 -0.13,-0.552 -0.035,-0.814 l 1.662,-4.569 c 0.398,-0.227 0.706,-0.597 0.865,-1.023 l 1.091,-3.001 c 0.83,-0.093 1.625,-0.392 2.304,-0.868 0.674,-0.477 1.236,-1.124 1.6,-1.866 l -0.672,-0.248 c -0.351,0.683 -0.893,1.269 -1.545,1.671 -0.658,0.404 -1.421,0.625 -2.196,0.631 l -1.25,3.438 c -0.108,0.306 -0.341,0.563 -0.635,0.7 -0.295,0.136 -0.647,0.151 -0.955,0.04 -0.303,-0.11 -0.557,-0.345 -0.693,-0.637 -0.137,-0.294 -0.158,-0.646 -0.049,-0.955 l 1.923,-5.259 c 0.35,-0.967 0.94,-1.847 1.702,-2.542 0.767,-0.687 1.7,-1.193 2.695,-1.452 l 6.539,2.38 c 1.103,2.359 1.236,5.158 0.343,7.605 l -2.073,5.685 c -0.076,0.22 -0.246,0.404 -0.459,0.499 -0.205,0.101 -0.453,0.109 -0.671,0.033 -0.22,-0.08 -0.406,-0.248 -0.503,-0.457 -0.094,-0.212 -0.109,-0.461 -0.026,-0.68 l 1.145,-3.163 M 184.684,764.85205 c -0.405,-1.114 -1.093,-2.119 -1.985,-2.898 -0.883,-0.783 -1.974,-1.333 -3.128,-1.595 l -7.004,2.549 v 0.005 c -1.303,2.58 -1.49,5.699 -0.501,8.414 l 2.072,5.687 c 0.13,0.357 0.397,0.665 0.732,0.851 0.332,0.187 0.736,0.241 1.113,0.158 0.37,-0.082 0.712,-0.305 0.94,-0.611 l 0.88,2.412 c 0.13,0.362 0.397,0.675 0.739,0.858 0.336,0.181 0.741,0.235 1.12,0.151 0.368,-0.085 0.712,-0.313 0.94,-0.628 0.19,0.368 0.52,0.658 0.905,0.813 0.383,0.155 0.83,0.165 1.219,0.032 0.393,-0.135 0.735,-0.408 0.955,-0.765 0.213,-0.358 0.296,-0.79 0.227,-1.199 0.418,0.134 0.891,0.111 1.289,-0.075 0.398,-0.182 0.729,-0.517 0.9,-0.926 0.173,-0.406 0.179,-0.874 0.028,-1.291 l -1.481,-4.067 c 0.429,0.024 0.862,-0.094 1.219,-0.338 0.358,-0.243 0.625,-0.602 0.755,-1.01 0.138,-0.411 0.123,-0.863 -0.02,-1.267 l -1.914,-5.26 m -8.213,11.311 c 0.074,0.219 0.068,0.468 -0.035,0.68 -0.095,0.209 -0.282,0.377 -0.501,0.457 -0.211,0.076 -0.467,0.068 -0.673,-0.033 -0.212,-0.095 -0.377,-0.279 -0.459,-0.499 l -2.071,-5.685 c -0.886,-2.447 -0.762,-5.246 0.342,-7.605 l 6.539,-2.38 c 1,0.259 1.935,0.765 2.695,1.452 0.762,0.695 1.352,1.575 1.71,2.542 l 1.914,5.259 c 0.109,0.309 0.094,0.661 -0.041,0.955 -0.138,0.292 -0.398,0.527 -0.7,0.637 -0.309,0.111 -0.66,0.096 -0.948,-0.04 -0.294,-0.137 -0.534,-0.394 -0.643,-0.7 l -1.248,-3.438 c -0.771,-0.006 -1.539,-0.227 -2.192,-0.631 -0.657,-0.402 -1.192,-0.988 -1.55,-1.671 l -0.671,0.248 c 0.371,0.742 0.926,1.389 1.605,1.866 0.68,0.476 1.476,0.775 2.298,0.868 l 1.092,3.001 c 0.159,0.426 0.467,0.796 0.865,1.023 l 1.66,4.569 c 0.096,0.262 0.081,0.561 -0.035,0.814 -0.118,0.25 -0.336,0.453 -0.596,0.548 -0.261,0.096 -0.563,0.084 -0.816,-0.033 -0.248,-0.12 -0.454,-0.34 -0.551,-0.602 l -2.482,-6.823 -0.666,0.24 2.845,7.826 c 0.099,0.262 0.084,0.56 -0.032,0.813 -0.124,0.25 -0.343,0.453 -0.604,0.55 -0.261,0.094 -0.556,0.082 -0.811,-0.036 -0.253,-0.12 -0.451,-0.339 -0.548,-0.6 l -2.847,-7.822 -0.666,0.241 2.484,6.823 c 0.076,0.22 0.069,0.467 -0.033,0.68 -0.097,0.209 -0.282,0.376 -0.494,0.455 -0.221,0.079 -0.467,0.068 -0.68,-0.031 -0.214,-0.095 -0.379,-0.28 -0.459,-0.497 l -2.485,-6.824 -0.665,0.24 1.153,3.163");
+ // noteHead = new Path2D("M220 138c56 0 109 -29 109 -91c0 -72 -56 -121 -103 -149c-36 -21 -76 -36 -117 -36c-56 0 -109 29 -109 91c0 72 56 121 103 149c36 21 76 36 117 36z");
+ noteHead = new Path2D("M19.8 -12.4c5 0 9.8 2.6 9.8 8.2c0 6.5 -5 10.9 -9.3 13.4c-3.2 1.9 -6.8 3.2 -10.5 3.2c-5 0 -9.8 -2.6 -9.8 -8.2c0 -6.5 5 -10.9 9.3 -13.4c3.2 -1.9 6.8 -3.2 10.5 -3.2 z");
+ sideIndicator1 = new Path2D("m 379.0355,823.51955 h -2.213 c -0.229,0 -0.436,-0.096 -0.587,-0.243 -0.162,-0.163 -0.243,-0.377 -0.243,-0.591 v -8.298 c 0,-0.229 0.092,-0.439 0.243,-0.586 0.162,-0.163 0.376,-0.244 0.587,-0.244 h 2.213 v -2.767 h -3.597 c -0.354,0 -0.708,0.136 -0.978,0.406 -0.251,0.251 -0.402,0.594 -0.402,0.977 v 12.726 c 0,0.356 0.133,0.709 0.402,0.98 0.251,0.251 0.598,0.406 0.978,0.406 h 3.597 v -2.766");
+ sideIndicator2 = new Path2D("m 379.0085,813.83755 h -2.21 c -0.144,0 -0.285,0.054 -0.391,0.159 -0.1,0.105 -0.163,0.242 -0.159,0.395 0,0 0,8.281 -0.004,8.281 0,0.142 0.055,0.284 0.163,0.39 0.103,0.103 0.239,0.162 0.391,0.162 h 2.21 v -9.387");
+ sharpSign = new Path2D("M216 -312c0 -10 -8 -19 -18 -19s-19 9 -19 19v145l-83 -31v-158c0 -10 -9 -19 -19 -19s-18 9 -18 19v145l-32 -12c-2 -1 -5 -1 -7 -1c-11 0 -20 9 -20 20v60c0 8 5 16 13 19l46 16v160l-32 -11c-2 -1 -5 -1 -7 -1c-11 0 -20 9 -20 20v60c0 8 5 15 13 18l46 17v158 c0 10 8 19 18 19s19 -9 19 -19v-145l83 31v158c0 10 9 19 19 19s18 -9 18 -19v-145l32 12c2 1 5 1 7 1c11 0 20 -9 20 -20v-60c0 -8 -5 -16 -13 -19l-46 -16v-160l32 11c2 1 5 1 7 1c11 0 20 -9 20 -20v-60c0 -8 -5 -15 -13 -18l-46 -17v-158zM96 65v-160l83 30v160z");
+ flatSign = new Path2D("M27 41l-1 -66v-11c0 -22 1 -44 4 -66c45 38 93 80 93 139c0 33 -14 67 -43 67c-31 0 -52 -30 -53 -63zM-15 -138l-12 595c8 5 18 8 27 8s19 -3 27 -8l-7 -345c25 21 58 34 91 34c52 0 89 -48 89 -102c0 -80 -86 -117 -147 -169c-15 -13 -24 -38 -45 -38 c-13 0 -23 11 -23 25z");
+ constructor() {
+ super(new OctaviaDevice());
+ let upThis = this;
+ this.addEventListener("mode", function (ev) {
+ (upThis.sysBm.getBm(`st_${({"gm":"gm1","g2":"gm2","?":"gm1","ns5r":"korg","ag10":"korg","x5d":"korg","05rw":"korg","krs":"korg","sg":"gm1","k11":"gm1"})[ev.data] || ev.data}`) || []).forEach(function (e, i) {
+ upThis.#bmdb[i] = e;
+ });
+ upThis.#bmst = 2;
+ upThis.#bmex = Date.now() + 1600;
+ });
+ this.addEventListener("channelactive", (ev) => {
+ this.#ch = ev.data;
+ });
+ };
+ setCh(ch) {
+ this.#ch = ch;
+ };
+ getCh() {
+ return this.#ch;
+ };
+ reset() {
+ super.reset();
+ if (this.demoInfo) {
+ delete this.demoInfo;
+ };
+ };
+ #render7seg(str, ctx, offsetX, offsetY, scaleX = 1, scaleY = 1, skew = -0.15) {
+ let path = [
+ new Path2D(),
+ new Path2D("M36 160 L48 148 L144 148 L156 160 L144 172 L48 172 Z"),
+ new Path2D("M32 156 L20 144 L20 48 L32 36 L44 48 L44 144 Z"),
+ new Path2D("M32 284 L20 272 L20 176 L32 164 L44 176 L44 272 Z"),
+ new Path2D("M156 288 L144 300 L48 300 L36 288 L48 276 L144 276 Z"),
+ new Path2D("M160 164 L172 176 L172 272 L160 284 L148 272 L148 176 Z"),
+ new Path2D("M160 36 L172 48 L172 144 L160 156 L148 144 L148 48 Z"),
+ new Path2D("M36 32 L48 20 L144 20 L156 32 L144 44 L48 44 Z")
+ ];
+ let sevenSegFont = {
+ 0: new Uint8Array([0, 0, 1, 1, 1, 1, 1, 1]),
+ 1: new Uint8Array([0, 0, 0, 0, 0, 1, 1, 0]),
+ 2: new Uint8Array([0, 1, 0, 1, 1, 0, 1, 1]),
+ 3: new Uint8Array([0, 1, 0, 0, 1, 1, 1, 1]),
+ 4: new Uint8Array([0, 1, 1, 0, 0, 1, 1, 0]),
+ 5: new Uint8Array([0, 1, 1, 0, 1, 1, 0, 1]),
+ 6: new Uint8Array([0, 1, 1, 1, 1, 1, 0, 1]),
+ 7: new Uint8Array([0, 0, 1, 0, 0, 1, 1, 1]),
+ 8: new Uint8Array([0, 1, 1, 1, 1, 1, 1, 1]),
+ 9: new Uint8Array([0, 1, 1, 0, 1, 1, 1, 1]),
+ " ": new Uint8Array(8),
+ A: new Uint8Array([0, 1, 1, 1, 0, 1, 1, 1]),
+ B: new Uint8Array([0, 1, 1, 1, 1, 1, 0, 0]),
+ C: new Uint8Array([0, 0, 1, 1, 1, 0, 0, 1]),
+ D: new Uint8Array([0, 1, 0, 1, 1, 1, 1, 0]),
+ "-": new Uint8Array([0, 1, 0, 0, 0, 0, 0, 0])
+ };
+ Array.from(str).forEach((e, i) => {
+ ctx.setTransform(scaleX, 0, skew * scaleY, scaleY, 190 * scaleX * i + offsetX, offsetY);
+ for (let i = 0; i < 8; i++) {
+ ctx.fillStyle = sevenSegFont[e][i] ? activePixel : inactivePixel;
+ ctx.fill(path[i]);
+ }
+ });
+ ctx.resetTransform();
+ };
+ #renderDotMatrix(str, ctx, trueMode = false, offsetX, offsetY, scaleX = 8, scaleY = 8, skew = -0.15) {
+ let upThis = this;
+ let timeNow = Date.now();
+ ctx.setTransform(1, 0, skew, 1, 0, 0);
+ // Determine the used font
+ let targetFont = trueMode ? upThis.trueFont : upThis.xgFont;
+ let rollX = 0;
+ if (str.length > 8) {
+ rollX = Math.floor(timeNow / 125) % (2 + str.length);
+ // rollX = 0;
+ str = `${str} ${str.slice(0, 8)}`
+ str = str.slice(rollX, rollX + 8);
+ };
+ str = str.padEnd(8, " ");
+ targetFont.getStr(str).forEach((e, i) => {
+ e.render((e, x, y) => {
+ ctx.fillStyle = e ? activePixel : inactivePixel;
+ ctx.fillRect(offsetX + (x + 6 * i) * scaleX, offsetY + y * scaleY, scaleX - 1, scaleY - 1);
+ });
+ });
+ ctx.resetTransform();
+ }
+ render(time, ctx, backlightColor = "#b7bfaf64", mixerView, tempoView, id = 0, trueMode = false) {
+ let sum = super.render(time);
+ let upThis = this;
+ let timeNow = Date.now();
+ // Channel test
+ let alreadyMin = false;
+ let minCh = 0, maxCh = 0;
+ sum.chInUse.forEach(function (e, i) {
+ if (e) {
+ if (!alreadyMin) {
+ alreadyMin = true;
+ minCh = i;
+ };
+ maxCh = i;
+ };
+ });
+ let part = minCh >> 4;
+ minCh = part << 4;
+ maxCh = ((maxCh >> 4) << 4) + 15;
+ if (this.#ch > maxCh) {
+ this.#ch = minCh + this.#ch & 15;
+ };
+ if (this.#ch < minCh) {
+ this.#ch = maxCh - 15 + (this.#ch & 15);
+ };
+ let chOff = this.#ch * ccToPos.length;
+ // Clear out the current working display buffer.
+ this.#nkdb.forEach((e, i, a) => {a[i] = 0});
+ this.#nsdb.forEach((e, i, a) => {a[i] = 0});
+ this.#nadb.forEach((e, i, a) => {a[i] = 0});
+ // Fill with white
+ ctx.fillStyle = backlightColor;
+ ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+ // Show text
+ ctx.fillStyle = "#000c";
+ ctx.textAlign = "left";
+ ctx.font = '22px "Arial Web"';
+ ctx.fillText("C4", 548, 399);
+ ctx.strokeStyle = "#000c";
+ ctx.stroke(upThis.bracket);
+ ctx.stroke(upThis.staffLines);
+ ctx.fill(upThis.clefs);
+ ctx.stroke(upThis.keyboard);
+ // Beat indicator
+ if (sum.noteBeat & 1) {
+ ctx.fillStyle = activePixel;
+ ctx.setTransform(3.2, 0, 0, -3.2, 455, 2733);
+ ctx.fill(upThis.upbeatHand);
+ ctx.fillStyle = inactivePixel;
+ ctx.setTransform(3.2, 0, 0, -3.2, 455, 2855);
+ ctx.fill(upThis.downbeatHand);
+ }
+ else {
+ ctx.fillStyle = inactivePixel;
+ ctx.setTransform(3.2, 0, 0, -3.2, 455, 2733);
+ ctx.fill(upThis.upbeatHand);
+ ctx.fillStyle = activePixel;
+ ctx.setTransform(3.2, 0, 0, -3.2, 455, 2855);
+ ctx.fill(upThis.downbeatHand);
+ }
+ ctx.fillStyle = (sum.noteBeat < 1) ? activePixel : inactivePixel;
+ ctx.setTransform(3.2, 0, 0, -3.2, 455, 2855);
+ ctx.fill(upThis.downbeatStar);
+ ctx.resetTransform();
+ // Keyboard display
+ // Reset the arrows
+ let arrowLeft = new Path2D("M199 349 L214 329 L214 369 Z"),
+ arrowRight = new Path2D("M1080 349 L1065 369 L1065 329 Z"),
+ arrowLeftFlag = false,
+ arrowRightFlag = false;
+ let note;
+ // Main range
+ for (let i = 36; i < 97; i++) {
+ let pixel = 0,
+ partInfo = sum.chKeyPr[this.#ch];
+ if (partInfo?.has(i)) {
+ pixel = partInfo.get(i).s < 4 ? 2 : 1;
+ };
+ this.#nkdb[i - 36] = pixel;
+ };
+ // Lower octaves
+ for (let i = 0; i < 36; i++) {
+ if (sum.chKeyPr[this.#ch]?.has(i)) {
+ arrowLeftFlag = true;
+ note = i % 12;
+ let pixel = sum.chKeyPr[this.#ch]?.get(i).s < 4 ? 2 : 1;
+ this.#nkdb[note] = Math.max(this.#nkdb[note], pixel);
+ };
+ };
+ // Higher octaves
+ for (let i = 97; i < 128; i++) {
+ if (sum.chKeyPr[this.#ch]?.has(i)) {
+ arrowRightFlag = true;
+ note = (i - 1) % 12 + 1;
+ let pixel = sum.chKeyPr[this.#ch]?.get(i).s < 4 ? 2 : 1;
+ this.#nkdb[note + 48] = Math.max(this.#nkdb[note], pixel);
+ };
+ };
+ // Render the arrows
+ ctx.fillStyle = arrowLeftFlag ? activePixel : inactivePixel;
+ ctx.fill(arrowLeft);
+ ctx.fillStyle = arrowRightFlag ? activePixel : inactivePixel;
+ ctx.fill(arrowRight);
+ // Staff display
+ let noteHeadPos = new Uint8Array([0, 0, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 7]);
+ let isBlackKey = new Uint8Array([0, 1, 0, 2, 0, 0, 1, 0, 2, 0, 2, 0]);
+ let nadbIndex = new Uint8Array([0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 2, 0]);
+ let bottomOctaveFlag1 = false,
+ bottomOctaveFlag2 = false,
+ topOctaveFlag1 = false,
+ topOctaveFlag2 = false;
+ // Main range
+ for (let i = 48; i < 85; i++) {
+ if (sum.chKeyPr[this.#ch]?.has(i)) {
+ let pixel = sum.chKeyPr[this.#ch]?.get(i).s < 4 ? 2 : 1;
+ this.#nsdb[(Math.floor(i / 12) - 4) * 7 + noteHeadPos[i % 12]] = pixel;
+ if (isBlackKey[i % 12]) {
+ if (isBlackKey[i % 12] == 1) {
+ this.#nadb[(Math.floor(i / 12) - 4) * 2 + nadbIndex[i % 12]] = 1;
+ }
+ else {
+ this.#nadb[(Math.floor(i / 12) - 4) * 3 + nadbIndex[i % 12] + 6] = 1;
+ }
+ }
+ }
+ }
+ // Lower octaves
+ for (let i = 0; i < 48; i++) {
+ if (sum.chKeyPr[this.#ch]?.has(i)) {
+ let pixel = sum.chKeyPr[this.#ch]?.get(i).s < 4 ? 2 : 1;
+ this.#nsdb[noteHeadPos[i % 12]] = Math.max(this.#nsdb[noteHeadPos[i % 12]], pixel);
+ if (Math.floor(i / 12) == 3) {
+ bottomOctaveFlag1 = true;
+ }
+ else {
+ bottomOctaveFlag2 = true;
+ }
+ if (isBlackKey[i % 12]) {
+ if (isBlackKey[i % 12] == 1) {
+ this.#nadb[nadbIndex[i % 12]] = 1;
+ }
+ else {
+ this.#nadb[nadbIndex[i % 12] + 6] = 1;
+ }
+ }
+ }
+ }
+ // Higher octaves
+ for (let i = 85; i < 128; i++) {
+ if (sum.chKeyPr[this.#ch]?.has(i)) {
+ let pixel = sum.chKeyPr[this.#ch]?.get(i).s < 4 ? 2 : 1;
+ this.#nsdb[14 + noteHeadPos[(i - 1) % 12 + 1]] = Math.max(this.#nsdb[14 + noteHeadPos[(i - 1) % 12 + 1]], pixel);
+ if (Math.floor((i - 1) / 12) == 7) {
+ topOctaveFlag1 = true;
+ }
+ else {
+ topOctaveFlag2 = true;
+ }
+ if (isBlackKey[i % 12]) {
+ if (isBlackKey[i % 12] == 1) {
+ this.#nadb[4 + nadbIndex[i % 12]] = 1;
+ }
+ else {
+ this.#nadb[12 + nadbIndex[i % 12]] = 1;
+ }
+ }
+ }
+ }
+ // Octave marks
+ ctx.font = '24px "Arial Web"';
+ ctx.fillStyle = bottomOctaveFlag1 ? activePixel : inactivePixel;
+ ctx.fillText("8va", 280, 208);
+ ctx.fillStyle = topOctaveFlag1 ? activePixel : inactivePixel;
+ ctx.fillText("8va", 876, 70);
+ ctx.fillStyle = bottomOctaveFlag2 ? activePixel : inactivePixel;
+ ctx.fillText("15va+", 253, 244);
+ ctx.fillStyle = topOctaveFlag2 ? activePixel : inactivePixel;
+ ctx.fillText("15va+", 874, 40);
+ // Temporary channel number display
+ this.#render7seg(`${"ABCDEFGH"[this.#ch >> 4]}${((this.#ch & 15) + 1).toString().padStart(2, "0")}`, ctx, 32, 315, 0.24, 0.24);
+ // Measure / tempo view
+ ctx.font = '23px "Arial Web"';
+ ctx.fillStyle = tempoView ? inactivePixel : activePixel;
+ ctx.fillText("MEASURE", 664, 296);
+ ctx.fillStyle = tempoView ? activePixel : inactivePixel;
+ ctx.fillText("TEMPO", 795, 242);
+ if (tempoView) {
+ this.#render7seg(Math.round(sum.tempo).toString().padStart(3, "0"), ctx, 791, 245, 0.17, 0.17);
+ }
+ else {
+ this.#render7seg((sum.noteBar + 1).toString().padStart(3, "0"), ctx, 791, 245, 0.17, 0.17);
+ }
+ if (timeNow <= sum.letter.expire) {
+ let letterDisp = sum.letter.text.trim();
+ this.#renderDotMatrix(letterDisp, ctx, trueMode, 454, 32);
+ if (mixerView) {
+ this.#render7seg(`${sum.chProgr[this.#ch] + 1}`.padStart(3, "0"), ctx, 112, 15, 0.24, 0.24);
+ }
+ else {
+ this.#render7seg(`${id + 1}`.padStart(3, "0"), ctx, 112, 15, 0.24, 0.24);
+ }
+ }
+ else {
+ if (mixerView) {
+ this.#render7seg(`${sum.chProgr[this.#ch] + 1}`.padStart(3, "0"), ctx, 112, 15, 0.24, 0.24);
+ this.#renderDotMatrix(upThis.getChVoice(this.#ch).name, ctx, trueMode, 454, 32);
+ }
+ else {
+ this.#render7seg(`${id + 1}`.padStart(3, "0"), ctx, 112, 15, 0.24, 0.24);
+ let sngTtl = upThis.songTitle;
+ while (sngTtl.indexOf(" ") > -1) {
+ sngTtl = sngTtl.replaceAll(" ", " ");
+ };
+ this.#renderDotMatrix(sngTtl || "Unknown", ctx, trueMode, 454, 32);
+ }
+ }
+ // Side indicator
+ ctx.fillStyle = activePixel;
+ ctx.setTransform(4.5, 0, 0, 4.5, -605, -3642);
+ ctx.fill(upThis.sideIndicator1);
+ ctx.fillStyle = mixerView ? inactivePixel : activePixel;
+ ctx.fill(upThis.sideIndicator2);
+ ctx.setTransform(4.5, 0, 0, 4.5, -605, -3484);
+ ctx.fillStyle = mixerView ? activePixel : inactivePixel;
+ ctx.fill(upThis.sideIndicator2);
+ ctx.resetTransform();
+ // Fetch voice bitmap
+ // Commit to bitmap screen
+ let useBm;
+ if (timeNow <= sum.bitmap.expire) {
+ // Use provided bitmap
+ useBm = sum.bitmap.bitmap;
+ } else if (this.demoInfo && time > 0) {
+ let sequence = this.demoInfo.class || "boot";
+ let stepTime = this.demoInfo.fps || 2;
+ let stepSize = this.demoInfo.size || 4;
+ let stepId = `${sequence}_${Math.floor(time * stepTime % stepSize)}`;
+ useBm = this.aniBm?.getBm(stepId) || this.sysBm?.getBm(stepId) || this.sysBm?.getBm("no_abm");
+ if (!useBm) {
+ useBm = this.#bmdb.slice();
+ };
+ } else {
+ // Use stored pic
+ useBm = this.#bmdb.slice();
+ if (timeNow >= this.#bmex) {
+ this.#bmst = 0;
+ let standard = upThis.getChVoice(this.#ch).standard.toLowerCase();
+ useBm = this.voxBm.getBm(upThis.getChVoice(this.#ch).name) || this.voxBm.getBm(upThis.getVoice(sum.chContr[chOff] + ccToPos[0], sum.chProgr[this.#ch], 0, sum.mode).name);
+ if (["an", "ap", "dr", "dx", "pc", "pf", "sg", "vl"].indexOf(standard) > -1) {
+ useBm = this.sysBm.getBm(`ext_${standard}`);
+ };
+ if (!useBm && (sum.chContr[chOff + ccToPos[0]] < 48 || sum.chContr[chOff + ccToPos[0]] == 56)) {
+ useBm = this.voxBm.getBm(upThis.getVoice(0, sum.chProgr[this.#ch], 0, sum.mode).name)
+ };
+ if (!useBm && (sum.chContr[chOff] + ccToPos[0]) == 126) {
+ useBm = this.sysBm.getBm("cat_smpl");
+ };
+ if (!useBm && (sum.chContr[chOff] + ccToPos[0]) == 64) {
+ useBm = this.sysBm.getBm("cat_sfx");
+ };
+ if (!useBm) {
+ useBm = this.sysBm.getBm("no_abm");
+ };
+ } else {
+ if (this.#bmst == 2) {
+ useBm.forEach((e, i, a) => {
+ let crit = Math.floor((this.#bmex - timeNow) / 400);
+ a[i] = crit % 2 == e;
+ });
+ };
+ };
+ }
+ if (useBm) {
+ useBm.width = useBm.length / 16;
+ };
+ useBm?.render((e, x, y) => {
+ ctx.fillStyle = e ? activePixel : inactivePixel;
+ ctx.fillRect(224 + x * 6, 261 + y * 3, 5, 2);
+ });
+ ctx.fillStyle = inactivePixel;
+ ctx.font = '18px "Arial Web"';
+ ctx.fillText("ACMP", 430, 275);
+ ctx.fillText("ON", 430, 295);
+ ctx.fill(new Path2D("M482 296 L482 312 L462 304 Z"));
+ // Commit to display accordingly.
+ let keyboardData = new Uint16Array([228, 238.5, 250.3, 263.5, 272.6, 295, 304.5, 317.3, 330, 339.5, 354, 361.8]);
+ this.#nkdb.forEach((e, i) => {
+ ctx.fillStyle = [inactivePixel, mediumPixel, activePixel][e];
+ let octave = Math.floor(i / 12), note = i % 12;
+ if (i != 60) {
+ isBlackKey[note] ? ctx.fillRect(keyboardData[note] + 163 * octave, 321, 12, 26) : ctx.fillRect(keyboardData[note] + 163 * octave, 355, 14, 21);
+ }
+ else {
+ ctx.fillRect(1036, 355, 14, 21);
+ }
+ });
+ this.#nsdb.forEach((e, i) => {
+ if (i < 7) {
+ ctx.setTransform(1, 0, 0, 1, 100 + 36 * i, 200 - 18 * i);
+ }
+ else {
+ ctx.setTransform(1, 0, 0, 1, 538 + 36 * (i - 7), 290 - 18 * (i - 7));
+ }
+ ctx.fillStyle = [inactivePixel, mediumPixel, activePixel][e];
+ ctx.fill(upThis.noteHead);
+ ctx.resetTransform();
+ });
+ // Accidentals
+ let sharpPosX = new Uint16Array([82, 158, 488, 596, 740, 848]);
+ let sharpPosY = new Uint16Array([200, 146, 290, 236, 164, 110]);
+ let flatPosX = new Uint16Array([130, 230, 306, 560, 668, 704, 812, 920, 956]);
+ let flatPosY = new Uint16Array([164, 110, 92, 254, 200, 182, 128, 74, 56]);
+ this.#nadb.forEach((e, i) => {
+ if (i < 6) {
+ ctx.setTransform(0.03, 0, 0, -0.03, sharpPosX[i], sharpPosY[i]);
+ ctx.fillStyle = [inactivePixel, activePixel][e];
+ ctx.fill(upThis.sharpSign);
+ ctx.resetTransform();
+ }
+ else {
+ ctx.setTransform(0.03, 0, 0, -0.03, flatPosX[i - 6], flatPosY[i - 6]);
+ ctx.fillStyle = [inactivePixel, activePixel][e];
+ ctx.fill(upThis.flatSign);
+ ctx.resetTransform();
+ }
+ });
+ // Commit to old display buffer.
+ /*
+ this.#nkdb.forEach((e, i) => {
+ if (this.#okdb[i] != e) {
+ this.#okdb[i] = e;
+ };
+ });
+ this.#nsdb.forEach((e, i) => {
+ if (this.#osdb[i] != e) {
+ this.#osdb[i] = e;
+ };
+ });
+ */
+ }
+};
+
+export default PsrDisplay;
diff --git a/src/disp/disp_qy.mjs b/src/disp/disp_qy.mjs
new file mode 100644
index 00000000..8c26e8c7
--- /dev/null
+++ b/src/disp/disp_qy.mjs
@@ -0,0 +1,517 @@
+"use strict";
+
+import {OctaviaDevice} from "../state/index.mjs";
+import {RootDisplay, ccToPos} from "../basic/index.mjs";
+import {MxFont40, MxBm256, MxBmDef} from "../basic/mxReader.js";
+
+import {
+ bgWhite,
+ lcdCache
+} from "./colour.js";
+
+let QyDisplay = class extends RootDisplay {
+ #omdb = new Uint8Array(8192); // Full display
+ #nmdb = new Uint8Array(8192); // Full display, but on commit
+ #mode = "?";
+ #ch = 0;
+ #refreshed = true;
+ #backlight = bgWhite;
+ #bmst = 0;
+ #bmex = 0;
+ #bmdb = new Uint8Array(256);
+ songTitle = "";
+ xgFont = new MxFont40("./data/bitmaps/xg/font.tsv");
+ sqrFont = new MxFont40("./data/bitmaps/xg/qySqr.tsv");
+ qy35Font = new MxFont40("./data/bitmaps/xg/qyCh35.tsv");
+ qy55Font = new MxFont40("./data/bitmaps/xg/qyCh55.tsv");
+ qyRsrc = new MxBmDef("./data/bitmaps/xg/qyRsrc.tsv");
+ sysBm = new MxBm256("./data/bitmaps/xg/system.tsv");
+ voxBm = new MxBm256("./data/bitmaps/xg/voices.tsv");
+ constructor() {
+ super(new OctaviaDevice(), 0, 0.95);
+ let upThis = this;
+ this.addEventListener("mode", function (ev) {
+ (upThis.sysBm.getBm(`st_${({"gm":"gm1","g2":"gm2","?":"gm1","ns5r":"korg","ag10":"korg","x5d":"korg","05rw":"korg","krs":"korg","sg":"gm1","k11":"gm1"})[ev.data] || ev.data}`) || []).forEach(function (e, i) {
+ upThis.#bmdb[i] = e;
+ });
+ upThis.#bmst = 2;
+ upThis.#bmex = Date.now() + 1600;
+ });
+ };
+ setCh(ch) {
+ this.#ch = ch;
+ };
+ getCh() {
+ return this.#ch;
+ };
+ #renderBox(sx, sy, width, height) {
+ let length = width * height;
+ let offset = sx + sy * 128;
+ for (let i = 0; i < length; i ++) {
+ let x = i % width, y = Math.floor(i / width);
+ if (
+ x == 0 && y < height - 1 ||
+ y == 0 && x < width - 1 ||
+ x == width - 1 && y > 0 ||
+ y == height - 1 && x > 0 ||
+ x == width - 2
+ ) {
+ this.#nmdb[offset + x + y * 128] = 1;
+ };
+ };
+ };
+ #renderFill(sx, sy, width, height, target = 1) {
+ let length = width * height;
+ let offset = sx + sy * 128;
+ for (let i = 0; i < length; i ++) {
+ let x = i % width, y = Math.floor(i / width);
+ this.#nmdb[offset + x + y * 128] = target;
+ };
+ };
+ #renderMosaic(sx, sy, width, height, start = 1) {
+ let curBit = !start;
+ let offset = sx + sy * 128,
+ length = width * height;
+ for (let i = 0; i < length; i ++) {
+ let x = i % width, y = Math.floor(i / width);
+ if (x == 0 && y > 0 && width % 2 == 0) {} else {
+ curBit = !curBit;
+ };
+ this.#nmdb[offset + x + y * 128] = +curBit;
+ };
+ };
+ #getCat(channel, msb, prg) {
+ let voiceInfo = this.getChVoice(channel);
+ let category;
+ if (["GM", "AG", "XG", "GS", "G2"].indexOf(voiceInfo.standard) > -1) {
+ switch(msb) {
+ case 64: {
+ category = "sfx";
+ break;
+ };
+ case 120:
+ case 122:
+ case 126:
+ case 127: {
+ category = "dr";
+ break;
+ };
+ default: {
+ category = (prg >> 3).toString(16);
+ };
+ };
+ } else {
+ category = voiceInfo.standard;
+ category = `${category[0]}${category[1].toLowerCase()}`;
+ };
+ return category;
+ };
+ render(time, ctx, mixerView, id = 0) {
+ let sum = super.render(time);
+ let upThis = this;
+ let timeNow = Date.now();
+ // Channel test
+ let alreadyMin = false;
+ let minCh = 0, maxCh = 0;
+ sum.chInUse.forEach(function (e, i) {
+ if (e) {
+ if (!alreadyMin) {
+ alreadyMin = true;
+ minCh = i;
+ };
+ maxCh = i;
+ };
+ });
+ let part = minCh >> 4;
+ minCh = part << 4;
+ maxCh = ((maxCh >> 4) << 4) + 15;
+ if (this.#ch > maxCh) {
+ this.#ch = minCh + this.#ch & 15;
+ };
+ if (this.#ch < minCh) {
+ this.#ch = maxCh - 15 + (this.#ch & 15);
+ };
+ let chOff = this.#ch * ccToPos.length;
+ // Clear out the current working display buffer.
+ this.#nmdb.forEach((e, i, a) => {a[i] = 0});
+ // Start rendering
+ if (mixerView) {
+ // Mixer view
+ // Render the upperleft
+ upThis.qyRsrc.getBm("MixPill")?.render((e, x, y) => {
+ if (e) {
+ upThis.#nmdb[x + y * 128] = 1;
+ };
+ });
+ upThis.qyRsrc.getBm("MixIcon")?.render((e, x, y) => {
+ if (e) {
+ upThis.#nmdb[10 + x + y * 128] = 1;
+ };
+ });
+ // Info labels
+ upThis.qyRsrc.getBm("MsVoice")?.render((e, x, y) => {
+ upThis.#nmdb[2176 + x + y * 128] = e;
+ });
+ upThis.qyRsrc.getBm("ElPan")?.render((e, x, y) => {
+ upThis.#nmdb[4096 + x + y * 128] = e;
+ });
+ upThis.qyRsrc.getBm("ElVol")?.render((e, x, y) => {
+ upThis.#nmdb[4864 + x + y * 128] = e;
+ });
+ upThis.qyRsrc.getBm("ElMsPa")?.render((e, x, y) => {
+ upThis.#nmdb[5634 + x + y * 128] = e;
+ });
+ // Global mosaic
+ upThis.#renderMosaic(0, 50, 5, 14, 1);
+ upThis.#renderFill(5, 50, 1, 14);
+ upThis.#renderMosaic(7, 50, 10, 14, 0);
+ upThis.#renderFill(10, 52, 1, 10);
+ upThis.#renderFill(11, 52, 1, 10, 0);
+ upThis.#renderFill(17, 50, 1, 14);
+ upThis.#renderMosaic(19, 50, 10, 14, 0);
+ upThis.#renderFill(22, 52, 1, 10);
+ upThis.#renderFill(23, 52, 1, 10, 0);
+ let masterVol = 9 - Math.floor(sum.master.volume / 10.1);
+ upThis.qyRsrc.getBm("VolSlid")?.render((e, x, y) => {
+ upThis.#nmdb[7 + x + (50 + masterVol + y) * 128] = e;
+ });
+ upThis.#renderFill(8, 53 + masterVol, 8, 1);
+ upThis.qyRsrc.getBm("VolSlid")?.render((e, x, y) => {
+ upThis.#nmdb[6419 + x + y * 128] = e;
+ });
+ upThis.#renderFill(20, 53, 8, 1);
+ upThis.#renderFill(29, 24, 1, 40);
+ // Bank info
+ let voiceInfo = upThis.getChVoice(this.#ch);
+ upThis.xgFont.getStr(`${(sum.chProgr[this.#ch] + 1).toString().padStart(3, "0")}${"+ "[+((["GM", "MT", "AG"].indexOf(voiceInfo.standard) > -1) || sum.chContr[chOff] >= 120)]}${voiceInfo.name.slice(0, 8)}`).forEach((e, i) => {
+ e.render((e, x, y) => {
+ upThis.#nmdb[55 + x + i * 6 + y * 128] = e;
+ });
+ });
+ let curCat = upThis.#getCat(this.#ch, sum.chContr[this.#ch * ccToPos.length], sum.chProgr[this.#ch]),
+ curCatBm = upThis.qyRsrc.getBm(`Vox_${curCat}`);
+ if (curCatBm) {
+ curCatBm.render((e, x, y) => {
+ upThis.#nmdb[37 + x + y * 128] = e;
+ });
+ } else {
+ upThis.xgFont.getStr(curCat).forEach((e, i) => {
+ e.render((e, x, y) => {
+ upThis.#nmdb[37 + x + i * 6 + y * 128] = e;
+ });
+ });
+ };
+ } else {
+ // Normal view
+ // Render the pill
+ upThis.qyRsrc.getBm("NorPill")?.render((e, x, y) => {
+ if (e) {
+ upThis.#nmdb[x + y * 128] = 1;
+ };
+ });
+ // Carve out the text on that pill
+ upThis.xgFont.getStr("SONG").forEach((e, i) => {
+ e.render((e, x, y) => {
+ if (e) {
+ upThis.#nmdb[5 + x + i * 6 + y * 128] = 0;
+ };
+ });
+ });
+ // Prepare info boxes
+ // Song info box
+ upThis.#renderBox(34, 6, 65, 11);
+ upThis.#renderFill(35, 7, 13, 9);
+ upThis.#renderBox(100, 6, 28, 11); // Bar box
+ if (sum.letter.expire < timeNow) {
+ upThis.xgFont.getStr(`${id + 1}`.padStart(2, "0")).forEach((e, i) => {
+ e.render((e, x, y) => {
+ if (e) {
+ upThis.#nmdb[1060 + x + i * 6 + y * 128] = 0;
+ };
+ });
+ });
+ if (upThis.songTitle.length < 9) {
+ upThis.xgFont.getStr(upThis.songTitle || "Unknown").forEach((e, i) => {
+ e.render((e, x, y) => {
+ upThis.#nmdb[1073 + x + i * 6 + y * 128] = e;
+ });
+ });
+ } else {
+ let sngTtl = upThis.songTitle;
+ while (sngTtl.indexOf(" ") > -1) {
+ sngTtl = sngTtl.replaceAll(" ", " ");
+ };
+ let rollX = Math.floor(time * 25) % (6 * (10 + sngTtl.length)) - 47;
+ upThis.xgFont.getStr(`${sngTtl} ${sngTtl.slice(0, 8)}`).forEach((e, i) => {
+ e.render((e, x, y) => {
+ let area = x + i * 6;
+ let tX = rollX;
+ if (rollX < 0) {
+ tX = rollX >= -48 ? 0 : rollX + 48;
+ };
+ if (area >= tX && area < tX + 47) {
+ upThis.#nmdb[1073 - tX + area + y * 128] = e;
+ };
+ });
+ });
+ };
+ // Bar info box
+ {
+ let blinker = sum.noteBeat % 1;
+ upThis.sqrFont.getStr(`${"$%"[+(blinker > 0 && blinker <= 0.25)]}${(sum.noteBar + 1).toString().padStart(3, "0")}`).forEach((e, i) => {
+ e.render((e, x, y) => {
+ upThis.#nmdb[1126 + x + i * 6 + y * 128] = e;
+ });
+ });
+ };
+ };
+ // Tempo render
+ upThis.sqrFont.getStr(`&=${Math.round(sum.tempo).toString().padStart(3, "0")}`).forEach((e, i) => {
+ e.render((e, x, y) => {
+ upThis.#nmdb[2048 + x + i * 6 + y * 128] = e;
+ });
+ });
+ // tSig render
+ upThis.xgFont.getStr(`${sum.tSig[0].toString().padStart(2, " ")}/${sum.tSig[1].toString().padEnd(2, " ")}`).forEach((e, i) => {
+ e.render((e, x, y) => {
+ upThis.#nmdb[3072 + x + i * 6 + y * 128] = e;
+ });
+ });
+ // Placeholder
+ upThis.qyRsrc.getBm("Vtfj")?.render((e, x, y) => {
+ upThis.#nmdb[2338 + x + y * 128] = e;
+ });
+ // Transpose render
+ {
+ let tPit = upThis.device.getPitchShift(upThis.#ch);
+ let tStr = tPit < 0 ? "-" : "+";
+ tStr += `${Math.round(Math.abs(tPit))}`.padStart(2, "0");
+ upThis.xgFont.getStr(tStr).forEach((e, i) => {
+ e.render((e, x, y) => {
+ upThis.#nmdb[3127 + x + i * 6 + y * 128] = e;
+ });
+ });
+ };
+ // Jump render
+ upThis.xgFont.getStr("001").forEach((e, i) => {
+ e.render((e, x, y) => {
+ upThis.#nmdb[3181 + x + i * 6 + y * 128] = e;
+ });
+ });
+ // Split line
+ upThis.#renderFill(71, 48, 1, 16);
+ upThis.qyRsrc.getBm("Mod_Usr")?.render((e, x, y) => {
+ upThis.#nmdb[6253 + x + y * 128] = e;
+ });
+ // Bank info
+ {
+ let voiceName = upThis.getChVoice(this.#ch);
+ upThis.xgFont.getStr(`${sum.chContr[chOff + ccToPos[0]].toString().padStart(3, "0")} ${sum.chProgr[this.#ch].toString().padStart(3, "0")} ${sum.chContr[chOff + ccToPos[32]].toString().padStart(3, "0")}`).forEach((e, i) => {
+ e.render((e, x, y) => {
+ upThis.#nmdb[6145 + 6 * i + x + y * 128] = e;
+ });
+ });;
+ upThis.xgFont.getStr(`${voiceName.standard}:${voiceName.name.slice(0, 8)}`).forEach((e, i) => {
+ e.render((e, x, y) => {
+ upThis.#nmdb[7169 + 6 * i + x + y * 128] = e;
+ });
+ });
+ };
+ // Fetch voice bitmap
+ // Commit to bitmap screen
+ let useBm;
+ if (timeNow <= sum.bitmap.expire) {
+ // Use provided bitmap
+ useBm = sum.bitmap.bitmap;
+ } else {
+ // Use stored pic
+ useBm = this.#bmdb.slice();
+ if (timeNow >= this.#bmex) {
+ this.#bmst = 0;
+ let standard = upThis.getChVoice(this.#ch).standard.toLowerCase();
+ useBm = this.voxBm.getBm(upThis.getChVoice(this.#ch).name) || this.voxBm.getBm(upThis.getVoice(sum.chContr[chOff] + ccToPos[0], sum.chProgr[this.#ch], 0, sum.mode).name);
+ if (["an", "ap", "dr", "dx", "pc", "pf", "sg", "vl"].indexOf(standard) > -1) {
+ useBm = this.sysBm.getBm(`ext_${standard}`);
+ };
+ if (!useBm && (sum.chContr[chOff + ccToPos[0]] < 48 || sum.chContr[chOff + ccToPos[0]] == 56)) {
+ useBm = this.voxBm.getBm(upThis.getVoice(0, sum.chProgr[this.#ch], 0, sum.mode).name)
+ };
+ if (!useBm && (sum.chContr[chOff] + ccToPos[0]) == 126) {
+ useBm = this.sysBm.getBm("cat_smpl");
+ };
+ if (!useBm && (sum.chContr[chOff] + ccToPos[0]) == 64) {
+ useBm = this.sysBm.getBm("cat_sfx");
+ };
+ if (!useBm) {
+ useBm = this.sysBm.getBm("no_abm");
+ };
+ } else {
+ if (this.#bmst == 2) {
+ useBm.forEach((e, i, a) => {
+ let crit = Math.floor((this.#bmex - timeNow) / 400);
+ a[i] = crit % 2 == e;
+ });
+ };
+ };
+ };
+ if (useBm) {
+ useBm.width = useBm.length / 16;
+ };
+ useBm?.render((e, x, y) => {
+ if (useBm.width < 32) {
+ upThis.#nmdb[6217 + 2 * x + y * 128] = e;
+ upThis.#nmdb[6218 + 2 * x + y * 128] = e;
+ } else {
+ upThis.#nmdb[6217 + x + y * 128] = e;
+ };
+ });
+ };
+ {
+ // Channel tabs
+ let curSeg = this.#ch >> 3;
+ let preCal = mixerView ? 1310 : 4254,
+ preCalY = mixerView ? 10 : 33;
+ // Channel info box
+ if (mixerView) {
+ upThis.#renderFill(28, preCalY - 1, 99, 15);
+ upThis.#renderFill(29, preCalY, 97, 13, 0);
+ } else {
+ upThis.#renderBox(0, preCalY - 1, 128, 15);
+ };
+ // Arrows
+ if (curSeg < (maxCh >> 3)) {
+ upThis.qyRsrc.getBm(`ArrowR${+mixerView + 1}`)?.render((e, x, y) => {
+ upThis.#nmdb[preCal + 735 + x + y * 128] = e;
+ });
+ };
+ if (curSeg > (minCh >> 3)) {
+ upThis.qyRsrc.getBm(`ArrowL${+mixerView + 1}`)?.render((e, x, y) => {
+ upThis.#nmdb[preCal + 610 + (+mixerView * 27) + x + y * 128] = e;
+ });
+ };
+ if (!mixerView) {
+ // PtCdTm
+ upThis.qyRsrc.getBm("PtCdTm")?.render((e, x, y) => {
+ upThis.#nmdb[4227 + x + y * 128] = e;
+ });
+ // The tempo pill
+ if (sum.tempo != 120) {
+ upThis.qyRsrc.getBm("ActPill")?.render((e, x, y) => {
+ upThis.#nmdb[5141 + x + y * 128] = e;
+ });
+ };
+ };
+ for (let tch = 0; tch < 8; tch ++) { // target channel
+ let rch = curSeg * 8 + tch,
+ textTarget = 1;
+ upThis.qyRsrc.getBm("CTabOff")?.render((e, x, y) => {
+ upThis.#nmdb[preCal + 12 * tch + x + y * 128] = e;
+ });
+ let cVelo = Math.floor(sum.strength[rch] / 51);
+ upThis.#renderFill(31 + 12 * tch, preCalY + 11 - cVelo, 9, cVelo + 1);
+ if (this.#ch == rch) {
+ textTarget = 0;
+ upThis.#renderFill(31 + 12 * tch, preCalY, 9, 5);
+ if (mixerView) {
+ upThis.#renderFill(30 + 12 * tch, preCalY + 14, 13, 8);
+ };
+ };
+ if (rch < 19) {
+ upThis.qy55Font.getStr(String.fromCharCode(48 + rch))[0].render((e, x, y) => {
+ if (e) {
+ upThis.#nmdb[preCal + 3 + 12 * tch + x + y * 128] = textTarget;
+ };
+ });
+ } else {
+ upThis.qy35Font.getStr((rch + 1).toString()).forEach((e, i) => {
+ e.render((e, x, y) => {
+ if (e) {
+ upThis.#nmdb[preCal + 2 + 4 * i + 12 * tch + x + y * 128] = textTarget;
+ };
+ });
+ });
+ };
+ if (mixerView) {
+ upThis.#renderMosaic(31 + tch * 12, 32, 10, 32, 0);
+ upThis.#renderFill(41 + tch * 12, 32, 1, 32);
+ upThis.#renderFill(34 + tch * 12, 43, 1, 18);
+ upThis.#renderFill(35 + tch * 12, 45, 1, 16, 0);
+ upThis.#renderFill(31 + tch * 12, 63, 10, 1);
+ upThis.qyRsrc.getBm("PanIcon")?.render((e, x, y) => {
+ upThis.#nmdb[4255 + tch * 12 + x + y * 128] = e;
+ });
+ let volSlid = 15 - (sum.chContr[rch * ccToPos.length + ccToPos[7]] >> 3);
+ upThis.qyRsrc.getBm("VolSlid")?.render((e, x, y) => {
+ upThis.#nmdb[5535 + tch * 12 + x + (volSlid + y) * 128] = e;
+ });
+ upThis.#renderFill(32 + tch * 12, 46 + volSlid, 8, 1);
+ // Category render
+ let curCat = upThis.#getCat(rch, sum.chContr[rch * ccToPos.length], sum.chProgr[rch]),
+ curCatBm = upThis.qyRsrc.getBm(`Vox_${curCat}`);
+ if (curCatBm) {
+ curCatBm.render((e, x, y) => {
+ if (e) {
+ upThis.#nmdb[3103 + tch * 12 + x + y * 128] = textTarget;
+ };
+ });
+ } else {
+ upThis.xgFont.getStr(curCat).forEach((e, i) => {
+ e.render((e, x, y) => {
+ if (e) {
+ upThis.#nmdb[3103 + tch * 12 + x + i * 6 + y * 128] = textTarget;
+ };
+ });
+ });
+ };
+ };
+ };
+ };
+ if (timeNow <= sum.letter.expire) {
+ //upThis.#renderFill(12, 9, 109, 31);
+ upThis.qyRsrc.getBm("TxtDisp")?.render((e, x, y) => {
+ upThis.#nmdb[(mixerView ? 655 : 1036) + x + y * 128] = e;
+ });
+ upThis.xgFont.getStr(sum.letter.text).forEach((e, i) => {
+ let ri = (i % 16) * 6, ry = i >> 4;
+ e.render((e, x, y) => {
+ upThis.#nmdb[(mixerView ? 1686 : 2067) + ri + x + (y + ry * 8) * 128] = e;
+ });
+ });
+ };
+ // Screen buffer write finish.
+ // Determine if full render is required.
+ let drawPixMode = false;
+ if (this.#refreshed) {
+ // Full render required.
+ // Clear all pixels.
+ ctx.fillStyle = this.#backlight.replace("64", "");
+ ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+ drawPixMode = true;
+ this.#refreshed = false;
+ };
+ // Commit to display accordingly.
+ this.#nmdb.forEach((e, i) => {
+ let pixX = i % 128, pixY = Math.floor(i / 128);
+ let hasDifference = this.#omdb[i] != e;
+ if (!drawPixMode && hasDifference) {
+ ctx.fillStyle = this.#backlight.slice(0, 7);
+ ctx.fillRect(6 * pixX + 7, 7 + 8 * pixY, 6, 8);
+ };
+ if (drawPixMode || hasDifference) {
+ ctx.fillStyle = lcdCache.black[e + 3];
+ if (drawPixMode) {
+ ctx.fillStyle = ctx.fillStyle.slice(0, 7);
+ };
+ ctx.fillRect(6 * pixX + 7, 7 + 8 * pixY, 5.5, 7.5);
+ };
+ });
+ // Commit to old display buffer.
+ this.#nmdb.forEach((e, i) => {
+ if (this.#omdb[i] != e) {
+ this.#omdb[i] = e;
+ };
+ });
+ };
+};
+
+export default QyDisplay;
diff --git a/src/disp/disp_sc.mjs b/src/disp/disp_sc.mjs
new file mode 100644
index 00000000..ee80cc9e
--- /dev/null
+++ b/src/disp/disp_sc.mjs
@@ -0,0 +1,327 @@
+"use strict";
+
+import {OctaviaDevice} from "../state/index.mjs";
+import {RootDisplay, ccToPos} from "../basic/index.mjs";
+import {MxFont40} from "../basic/mxReader.js";
+
+import {
+ bgOrange,
+ inactivePixel,
+ activePixel
+} from "./colour.js";
+
+let cmpWidth = 7,
+mspWidth = 6,
+cmpHeightX = 31,
+cmpHeightY = 12,
+mspHeightX = 29,
+mspHeightY = 10,
+pdsX = cmpWidth * (17 + 2),
+pdsY = cmpWidth * (7 + 3) + 1;
+let ScDisplay = class extends RootDisplay {
+ #tmdb = new Uint8Array(665); // Text display
+ #pmdb = new Uint8Array(735); // Param display
+ #bmdb = new Uint8Array(256); // Bitmap display
+ #linger = new Uint8Array(64);
+ #ch = 0;
+ xgFont = new MxFont40("./data/bitmaps/korg/font.tsv", "./data/bitmaps/xg/font.tsv");
+ constructor() {
+ super(new OctaviaDevice(), 0, 0.875);
+ };
+ setCh(ch) {
+ this.#ch = ch;
+ };
+ getCh() {
+ return this.#ch;
+ };
+ render(time, ctx) {
+ let sum = super.render(time);
+ let upThis = this;
+ let timeNow = Date.now();
+ // Fill with orange
+ //ctx.fillStyle = "#af2";
+ ctx.fillStyle = bgOrange;
+ ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+ // Universal offset
+ let pdaX = 22,
+ pdaY = 24;
+ // Channel test
+ let alreadyMin = false;
+ let minCh = 0, maxCh = 0;
+ sum.chInUse.forEach(function (e, i) {
+ if (e) {
+ if (!alreadyMin) {
+ alreadyMin = true;
+ minCh = i;
+ };
+ maxCh = i;
+ };
+ });
+ let part = minCh >> 4;
+ minCh = part << 4;
+ maxCh = ((maxCh >> 4) << 4) + 15;
+ if (this.#ch > maxCh) {
+ this.#ch = minCh + this.#ch & 15;
+ };
+ if (this.#ch < minCh) {
+ this.#ch = maxCh - 15 + (this.#ch & 15);
+ };
+ let chOff = this.#ch * ccToPos.length;
+ // Text matrix display
+ this.#tmdb.forEach((e, i, a) => {a[i] = 0});
+ let infoTxt, isTextNull = sum.letter.text.trim();
+ while (isTextNull.indexOf(" ") > -1) {
+ isTextNull = isTextNull.replaceAll(" ", " ");
+ };
+ if (timeNow <= sum.letter.expire) {
+ infoTxt = isTextNull;
+ let original = sum.letter.text,
+ leftTrim = original.length - original.trimLeft().length,
+ rightTrim = original.length - original.trimRight().length;
+ if (original.length > infoTxt.length && infoTxt.length < 16) {
+ if (leftTrim > 0) {
+ while(infoTxt.length < 15) {
+ infoTxt = ` ${infoTxt} `;
+ };
+ if (infoTxt.length < 16) {
+ if (leftTrim < rightTrim) {
+ infoTxt = ` ${infoTxt}`;
+ } else {
+ infoTxt = `${infoTxt} `;
+ };
+ };
+ };
+ };
+ let xShift = 0;
+ if (infoTxt.length > 16) {
+ xShift = Math.floor((sum.letter.expire - timeNow) / 33) - 96;
+ let maxShift = (infoTxt.length - 16) * -6;
+ if (xShift < maxShift) {
+ xShift = maxShift;
+ } else if (xShift > 0) {
+ xShift = 0;
+ };
+ };
+ this.xgFont.getStr(infoTxt).forEach(function (e0, i0) {
+ e0.forEach(function (e1, i1) {
+ let pX = i0 * 6 + i1 % 5 + xShift,
+ pY = Math.floor(i1 / 5);
+ if (pX >= 0 && pX < 95) {
+ upThis.#tmdb[pY * 95 + pX] = e1;
+ };
+ });
+ });
+ } else {
+ infoTxt = `${sum.chProgr[this.#ch] + 1}`.padStart(3, "0");
+ infoTxt += " ";
+ infoTxt += (upThis.getChVoice(this.#ch).name).slice(0, 12).padEnd(12, " ");
+ this.xgFont.getStr(infoTxt).forEach(function (e0, i0) {
+ e0.forEach(function (e1, i1) {
+ let pX = i0 * 6 + i1 % 5,
+ pY = Math.floor(i1 / 5);
+ upThis.#tmdb[pY * 95 + pX] = e1;
+ });
+ });
+ };
+ // Commit to text matrix display
+ this.#tmdb.forEach(function (e, i) {
+ ctx.fillStyle = inactivePixel;
+ if (e) {
+ ctx.fillStyle = activePixel;
+ };
+ let pixelX = i % 95,
+ pixelY = Math.floor(i / 95);
+ ctx.fillRect(
+ pdaX + 133 + pixelX * cmpWidth,
+ pdaY + pixelY * cmpWidth,
+ mspWidth,
+ mspWidth
+ );
+ });
+ // Param display
+ this.#pmdb.forEach((e, i, a) => {a[i] = 0});
+ // Assemble text
+ let paramText = "";
+ paramText += `${"ABCDEFGH"[this.#ch >> 4]}${(this.#ch % 16 + 1).toString().padStart(2, "0")}`;
+ paramText += sum.chContr[chOff + ccToPos[7]].toString().padStart(3, " ");
+ paramText += sum.chContr[chOff + ccToPos[91]].toString().padStart(3, " ");
+ let cPit = this.device.getPitchShift(this.#ch);
+ if (cPit < 0) {
+ paramText += "-";
+ } else {
+ paramText += "+";
+ };
+ paramText += Math.round(cPit < 0 ? Math.abs(cPit) : cPit).toString().padStart(2, "0");
+ let cPan = sum.chContr[chOff + ccToPos[10]];
+ if (cPan == 64) {
+ paramText += "C ";
+ } else if (cPan == 128) {
+ paramText += "RND";
+ } else {
+ if (cPan > 64) {
+ paramText += "R";
+ } else {
+ paramText += "L";
+ };
+ paramText += Math.abs(cPan - 64).toString().padStart(2, " ");
+ };
+ paramText += sum.chContr[chOff + ccToPos[93]].toString().padStart(3, " ");
+ paramText += (sum.chContr[chOff + ccToPos[0]] || sum.chContr[chOff + ccToPos[32]]).toString().padStart(3, "0");
+ // Render fonts
+ this.xgFont.getStr(paramText).forEach(function (e0, i0) {
+ e0.forEach(function (e1, i1) {
+ let pX = Math.floor(i0 / 3) * 90 + i0 * 5 + i1 % 5,
+ pY = Math.floor(i1 / 5);
+ if (pY < 7) {
+ upThis.#pmdb[pY * 15 + pX] = e1;
+ };
+ });
+ });
+ // Commit to param display
+ this.#pmdb.forEach(function (e, i) {
+ ctx.fillStyle = inactivePixel;
+ if (e) {
+ ctx.fillStyle = activePixel;
+ };
+ let regionX = i > 419 ? 1 : 0,
+ regionY = 0,
+ pixelX = i % 15 + Math.floor(i % 15 / 5),
+ pixelY = Math.floor((i % 105) / 15);
+ if (!regionX) {
+ regionY = Math.floor(i / 105);
+ } else {
+ regionY = Math.floor((i - 315) / 105);
+ };
+ ctx.fillRect(
+ pdaX + pdsX * regionX + pixelX * cmpWidth,
+ pdaY + pdsY * regionY + pixelY * cmpWidth,
+ mspWidth,
+ mspWidth
+ );
+ });
+ // Bitmap display
+ this.#bmdb.forEach((e, i, a) => {a[i] = 0});
+ let rendMode = Math.ceil(Math.log2(maxCh - minCh + 1) - 4),
+ rendPos = 0;
+ // Strength calculation
+ sum.velo.forEach(function (e, i) {
+ if (e >= upThis.#linger[i]) {
+ upThis.#linger[i] = ((e >> 4) << 4) + 15;
+ } else {
+ let val = upThis.#linger[i] - 2;
+ if (val < 0) {
+ val = 0;
+ };
+ upThis.#linger[i] = val;
+ };
+ });
+ let useBm = this.#bmdb;
+ if (timeNow <= sum.bitmap.expire) {
+ useBm = sum.bitmap.bitmap;
+ } else {
+ let rendPos = 0;
+ for (let c = minCh; c <= maxCh; c ++) {
+ let rendPart = rendPos >> 4;
+ let strSmooth = sum.strength[c] >> (4 + rendMode),
+ lingered = this.#linger[c] >> (4 + rendMode);
+ if (rendMode == 2) {
+ let offY = 4 * (3 - rendPart);
+ for (let d = 3 - strSmooth; d < 4; d ++) {
+ this.#bmdb[rendPos % 16 + (d + offY) * 16] = 1;
+ };
+ } else if (rendMode == 1) {
+ let offY = 8 * (1 - rendPart);
+ for (let d = 7 - strSmooth; d < 8; d ++) {
+ this.#bmdb[rendPos % 16 + (d + offY) * 16] = 1;
+ };
+ this.#bmdb[rendPos % 16 + (7 - lingered + offY) * 16] = 1;
+ } else {
+ for (let d = 15 - strSmooth; d < 16; d ++) {
+ this.#bmdb[rendPos % 16 + d * 16] = 1;
+ };
+ this.#bmdb[rendPos + (15 - lingered) * 16] = 1;
+ };
+ rendPos ++;
+ };
+ };
+ // Commit to bitmap display
+ useBm.forEach(function (e, i) {
+ ctx.fillStyle = inactivePixel;
+ if (e) {
+ ctx.fillStyle = activePixel;
+ };
+ let pixelX = i % 16,
+ pixelY = Math.floor(i / 16);
+ ctx.fillRect(
+ pdaX + 302 + pixelX * cmpHeightX,
+ pdaY + 71 + pixelY * cmpHeightY,
+ mspHeightX,
+ mspHeightY
+ );
+ });
+ // Show text
+ ctx.fillStyle = "#000c";
+ ctx.textAlign = "left";
+ ctx.font = '16px "Arial Web"';
+ ctx.fillText("PART", 21, 20);
+ ctx.fillText("INSTRUMENT", 154, 20);
+ ctx.fillText("LEVEL", 21, 91);
+ ctx.fillText("PAN", 154, 91);
+ ctx.fillText("REVERB", 21, 162);
+ ctx.fillText("CHORUS", 154, 162);
+ ctx.fillText("KEY SHIFT", 21, 233);
+ ctx.fillText("BANK", 154, 233);
+ ctx.textAlign = "right";
+ ctx.fillText("SB", 274, 233);
+ ctx.textAlign = "center";
+ for (let c = 1; c <= 16; c ++) {
+ ctx.fillText(`${c}`.padStart(2, "0"), 308 + cmpHeightX * c, 300);
+ };
+ ctx.lineWidth = 1;
+ ctx.strokeStyle = "#000c";
+ let circle = 2 * Math.PI;
+ for (let c = 0; c < 16; c ++) {
+ let d = c % 8;
+ ctx.beginPath();
+ if (!d) {
+ ctx.ellipse(
+ 316,
+ (15 - c) * 12 + 100,
+ 4, 4,
+ 0, 0, circle
+ );
+ ctx.fill();
+ } else if (d == 4) {
+ ctx.ellipse(
+ 316,
+ (15 - c) * 12 + 100,
+ 3, 3,
+ 0, 0, circle
+ );
+ ctx.fill();
+ } else {
+ ctx.ellipse(
+ 316,
+ (15 - c) * 12 + 100,
+ 2, 2,
+ 0, 0, circle
+ );
+ ctx.stroke();
+ };
+ };
+ if (sum.chContr[chOff + ccToPos[0]]) {
+ ctx.fillStyle = activePixel;
+ } else {
+ ctx.fillStyle = inactivePixel;
+ };
+ ctx.fillText("M", 236, 233);
+ if (sum.chContr[chOff + ccToPos[0]]) {
+ ctx.fillStyle = inactivePixel;
+ } else {
+ ctx.fillStyle = activePixel;
+ };
+ ctx.fillText("L", 248, 233);
+ };
+};
+
+export default ScDisplay;
diff --git a/src/disp/disp_tui.mjs b/src/disp/disp_tui.mjs
new file mode 100644
index 00000000..7459e62a
--- /dev/null
+++ b/src/disp/disp_tui.mjs
@@ -0,0 +1,138 @@
+"use strict";
+
+import {OctaviaDevice} from "../state/index.mjs";
+import {textedPanning, textedPitchBend} from "./texted.js";
+import {RootDisplay, ccToPos} from "../basic/index.mjs";
+
+import {
+ noteNames,
+ noteRegion,
+ map,
+ waveMap
+} from "./common.js";
+
+const modeNames = {
+ "?": "UnkwnStd",
+ "gm": "GnrlMIDI",
+ "g2": "GrlMIDI2",
+ "xg": "YamahaXG",
+ "gs": "RolandGS",
+ "mt32": "RlndMT32",
+ "ag10": "KorgAG10",
+ "x5d": "Korg X5D",
+ "05rw": "Korg05RW",
+ "ns5r": "KorgNS5R",
+ "k11": "KawaiK11",
+ "sg": "AkaiPrSG",
+ "krs": "KorgKros",
+ "s90es": "YmhS90ES",
+ "motif": "YmhMotif"
+};
+
+// Velocity to brightness
+let velToLuma = function (velo) {
+ let newVel = velo * 2 + 1;
+ return `${hexMap[newVel >> 4]}${hexMap[newVel & 15]}`;
+};
+
+let TuiDisplay = class extends RootDisplay {
+ #maxPoly = 0;
+ constructor() {
+ super(new OctaviaDevice);
+ this.addEventListener("reset", () => {
+ this.#maxPoly = 0;
+ });
+ };
+ render(time, ctx) {
+ let fields = new Array(24);
+ let sum = super.render(time);
+ let upThis = this;
+ let timeNow = Date.now();
+ let cramTempo = Math.round(sum.tempo * 100) / 100;
+ let curPoly = sum.curPoly + sum.extraPoly;
+ if (this.#maxPoly < curPoly) {
+ this.#maxPoly = curPoly;
+ };
+ fields[0] = `${sum.eventCount.toString().padStart(3, "0")} ${curPoly.toString().padStart(3, "0")}:${this.#maxPoly.toString().padStart(3, "0")}/512 TSig:${sum.tSig[0]}/${sum.tSig[1]} Bar:${(sum.noteBar + 1).toString().padStart(3, "0")}/${Math.floor(sum.noteBeat) + 1} Tempo:${Math.floor(cramTempo)}.${Math.floor(cramTempo % 1 * 100).toString().padStart(2, "0")} Vol:${Math.floor(sum.master.volume)}.${Math.round(sum.master.volume % 1 * 100).toString().padStart(2, "0")}%`;
+ fields[1] = `Mode:${modeNames[sum.mode]} Title:${sum.title || "N/A"}`;
+ fields[2] = "Ch:VoiceNme#St T VEM RCDBRP12 PiBd Pan : Note";
+ let line = 3, maxCh = 0;
+ sum.chInUse.forEach(function (e, i) {
+ if (e) {
+ maxCh = i;
+ let chOffset = i * ccToPos.length;
+ if (line < fields.length - 5 && i >= (self.minCh || 0)) {
+ let voiceName = upThis.getChVoice(i);
+ fields[line] = `${(i + 1).toString().padStart(2, "0")}:${voiceName.name.slice(0, 8).padEnd(8, " ")}${voiceName.ending}${voiceName.standard} ${sum.chType[i]} ${map[sum.chContr[chOffset + ccToPos[7]] >> 1]}${map[sum.chContr[chOffset + ccToPos[11]] >> 1]}${waveMap[sum.chContr[chOffset + ccToPos[1]] >> 5]} ${map[sum.chContr[chOffset + ccToPos[91]] >> 1]}${map[sum.chContr[chOffset + ccToPos[93]] >> 1]}${map[sum.chContr[chOffset + ccToPos[94]] >> 1]}${map[sum.chContr[chOffset + ccToPos[74]] >> 1]}${map[sum.chContr[chOffset + ccToPos[71]] >> 1]}${(sum.chContr[chOffset + ccToPos[65]] >> 6) ? map[sum.chContr[chOffset + ccToPos[5]] >> 1] : " "}${sum.ace[0] ? map[upThis.device.getChAce(i, 0) >> 1] : " "}${sum.ace[1] ? map[upThis.device.getChAce(i, 1) >> 1] : " "} ${textedPitchBend(sum.chPitch[i])} ${textedPanning(sum.chContr[chOffset + ccToPos[10]])}:`;
+ sum.chKeyPr[i].forEach(function (e1, i1) {
+ if (e1.v > 0) {
+ fields[line] += ` ${noteNames[i1 % 12]}${noteRegion[Math.floor(i1 / 12)]} `;
+ };
+ });
+ line ++;
+ };
+ };
+ });
+ if (sum.texts.length > 0) {
+ let metaLine = 0,
+ st = fields.length - 1;
+ while (st >= line) {
+ if (sum.texts[metaLine]?.length) {
+ fields[st] = (sum.texts[metaLine] || "").padEnd(100, " ");
+ };
+ if (sum.texts[metaLine]?.length > 0 || sum.texts[metaLine]?.length == undefined) {
+ st --;
+ };
+ metaLine ++;
+ };
+ };
+ if (timeNow <= sum.letter.expire) {
+ let letterDisp = sum.letter.text.padEnd(32, " ");
+ let startLn = fields.length - 2;
+ for (let st = 0; st < 2; st ++) {
+ fields[st + startLn] = `${(fields[st + startLn] || "").slice(0, 82).padEnd(81, " ")} ${letterDisp.slice(st * 16, st * 16 + 16).padEnd(" ", 16)} `;
+ };
+ };
+ if (ctx) {
+ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+ ctx.fillStyle = "#202020";
+ let renderer;
+ if (timeNow <= sum.bitmap.expire) {
+ renderer = sum.bitmap.bitmap;
+ } else {
+ renderer = new Array(256);
+ if (maxCh < 16) {
+ sum.strength.forEach(function (e, i) {
+ if (i < 16) {
+ let strength = e >> 4;
+ for (let dot = 0; dot <= strength; dot ++) {
+ renderer[i + (15 - dot) * 16] = 1;
+ };
+ };
+ });
+ } else {
+ sum.strength.forEach(function (e, i) {
+ if (i < 32) {
+ let strength = e >> 5;
+ for (let dot = 0; dot <= strength; dot ++) {
+ renderer[i + ((i > 15 ? 6 : 15) - dot) * 16] = 1;
+ };
+ };
+ });
+ };
+ };
+ renderer.forEach(function (e, i) {
+ if (e) {
+ ctx.fillRect((i & 15) * 12, (i >> 4) * 6, 11, 5);
+ };
+ });
+ // Create a dividing line
+ /* for (let c = 0; c < 15; c ++) {
+ ctx.clearRect(c * 12 + 5, 0, 1, ctx.canvas.height);
+ }; */
+ };
+ return fields.join(" ");
+ };
+};
+
+export default TuiDisplay;
diff --git a/src/disp/texted.js b/src/disp/texted.js
new file mode 100644
index 00000000..4cabc4b3
--- /dev/null
+++ b/src/disp/texted.js
@@ -0,0 +1,36 @@
+"use strict";
+
+let arrowGen = function (charArr, value, border, unit) {
+ let boundLow = border - (unit >> 1), boundHi = border + (unit >> 1);
+ if (value > border) {
+ for (let c = 0; value > border; c ++) {
+ charArr[c] = (value < boundHi) ? "=" : ">";
+ value -= unit;
+ };
+ } else if (value < border) {
+ for (let c = charArr.length - 1; value < border; c --) {
+ charArr[c] = (value >= boundLow) ? "=" : "<";
+ value += unit;
+ };
+ };
+};
+
+let textedPitchBend = function (number) {
+ let result = Array.from("----");
+ arrowGen(result, number, 0, 2048);
+ return result.join("");
+};
+
+let textedPanning = function (number) {
+ if (number == 128) {
+ return "<<>>";
+ };
+ let result = Array.from("----");
+ arrowGen(result, number, 64, 16);
+ return result.join("");
+};
+
+export {
+ textedPanning,
+ textedPitchBend
+};
diff --git a/src/fakeMu/index.js b/src/fakeMu/index.js
new file mode 100644
index 00000000..a78b417a
--- /dev/null
+++ b/src/fakeMu/index.js
@@ -0,0 +1,571 @@
+"use strict";
+
+import {} from "../../libs/lightfelt@ltgcgo/main/cssClass.js";
+import {$e, $a} from "../../libs/lightfelt@ltgcgo/main/quickPath.js";
+import MuDisplay from "../disp/disp_mu.mjs";
+import {fileOpen} from "../../libs/browser-fs-access@GoogleChromeLabs/browser_fs_access.min.js";
+import {
+ getBridge
+} from "../bridge/index.mjs";
+import {SheetData} from "../basic/sheetLoad.js";
+
+import {
+ PointEvent,
+ RangeEvent,
+ TimedEvents
+} from "../../libs/lightfelt@ltgcgo/ext/timedEvents.js";
+
+let demoBlobs = {};
+let demoPerfs = {};
+let demoInfo = {};
+let demoModes = [];
+demoModes[9] = "gm";
+let currentPerformance;
+let currentAnimation;
+let useMidiBus = false;
+
+// Generate Octavia channel switch SysEx
+self.generateSwitch = function (ch = 0, min, max) {
+ let data = [67, 16, 73, 0, 0, 10, ch];
+ if (min?.constructor == Number) {
+ data.push(min);
+ if (max.constructor == Number) {
+ data.push(max);
+ };
+ };
+ return {
+ type: 15,
+ track: 0,
+ data
+ };
+};
+self.generateString = function (text) {
+ let data = [67, 16, 76, 6, 0, 0];
+ for (let c = 0; c < text.length; c ++) {
+ data.push(text.charCodeAt(c));
+ };
+ return {
+ type: 15,
+ track: 0,
+ data
+ };
+};
+
+// Standard switching
+let stSwitch = $a("b.mode");
+let stSwitchMode = [];
+stSwitch.to = function (i) {
+ stSwitch.forEach(function (e) {
+ e.classList.off("active");
+ });
+ if (i > -1) {
+ stSwitch[i].classList.on("active");
+ };
+};
+stSwitch.forEach(function (e, i, a) {
+ stSwitchMode[i] = e.title;
+ e.addEventListener("click", function () {
+ visualizer.switchMode(e.title, true);
+ stSwitch.to(i);
+ });
+});
+
+// Standard demo switching
+let demoPool = new SheetData();
+let stList = $e("span#demo-list"), stDemo = [];
+const srcPaths = ['../../midi-demo-data/collection/octavia/', './demo/'];
+let getBlobFrom = async function (filename) {
+ let i = 0;
+ while (i < srcPaths.length) {
+ let e = srcPaths[i];
+ let response = await fetch(`${e}${filename}`);
+ if (response.status < 400) {
+ return response;
+ };
+ i ++;
+ };
+ console.error(`Loading of data ${filename} failed.`);
+};
+getBlobFrom(`list.tsv`).then(async (response) => {
+ await demoPool.load(await response.text());
+ //console.info(demoPool.data);
+ demoPool.data.forEach((e, i) => {
+ if (i) {
+ let space = document.createElement("span");
+ space.innerHTML = " ";
+ stList.appendChild(space);
+ } else {
+ stList.innerText = "";
+ };
+ let demoChoice = document.createElement("b");
+ demoChoice.innerText = e.text;
+ demoChoice.title = e.file;
+ demoChoice.classList.on("demo");
+ stDemo.push(demoChoice);
+ stList.appendChild(demoChoice);
+ });
+ stDemo.to = function (i) {
+ stDemo.forEach(function (e) {
+ e.classList.off("active");
+ });
+ if (i > -1) {
+ stDemo[i].classList.on("active");
+ };
+ };
+ stDemo.forEach(function (e, i, a) {
+ e.addEventListener("click", async function () {
+ audioPlayer.pause();
+ if (!demoBlobs[e.title]?.midi) {
+ demoBlobs[e.title] = {};
+ audioPlayer.src = "about:blank";
+ demoBlobs[e.title].midi = await (await getBlobFrom(`${e.title}.mid`)).blob();
+ demoBlobs[e.title].wave = await (await getBlobFrom(`${e.title}.opus`)).blob();
+ };
+ currentPerformance = demoPerfs[e.title];
+ currentPerformance?.resetIndex();
+ currentAnimation = demoInfo[e.title];
+ audioPlayer.currentTime = 0;
+ visualizer.reset();
+ visualizer.loadFile(demoBlobs[e.title].midi);
+ if (audioBlob) {
+ URL.revokeObjectURL(audioBlob);
+ };
+ audioBlob = demoBlobs[e.title].wave;
+ audioPlayer.src = URL.createObjectURL(audioBlob);
+ if (demoModes[i]?.length > 0) {
+ visualizer.switchMode(demoModes[i]);
+ };
+ stDemo.to(i);
+ });
+ });
+});
+
+// Start the visualizers
+self.visualizer = new MuDisplay();
+visualizer.addEventListener("reset", function (e) {
+ console.info("Processor reset.");
+});
+
+// Listen to mode switches
+visualizer.addEventListener("mode", function (ev) {
+ stSwitch.to(stSwitchMode.indexOf(ev.data));
+});
+
+// Open the files
+let midwIndicator = $e("#openMidw");
+let audioBlob;
+const propsMid = JSON.parse('{"extensions":[".mid",".MID",".kar",".KAR",".syx",".SYX",".s7e",".S7E"],"startIn":"music","id":"midiOpener","description":"Open a MIDI file"}'),
+propsAud = JSON.parse('{"mimeTypes":["audio/*"],"startIn":"music","id":"audioOpener","description":"Open an audio file"}');
+$e("#openMidi").addEventListener("click", async function () {
+ useMidiBus = false;
+ midwIndicator.classList.off("active");
+ let file = await fileOpen(propsMid);
+ let fileSplit = file.name.lastIndexOf("."), ext = "";
+ if (fileSplit > -1) {
+ ext = file.name.slice(fileSplit + 1).toLowerCase();
+ };
+ switch (ext) {
+ case "syx": {
+ // Load SysEx blobs
+ visualizer.sendCmd({type: 15, track: 0, data: new Uint8Array(await file.arrayBuffer())});
+ break;
+ };
+ case "s7e": {
+ // Load sound banks
+ visualizer.device.loadBank(ext, file);
+ break;
+ };
+ default: {
+ // Load MIDI files
+ stDemo.to(-1);
+ visualizer.reset();
+ visualizer.loadFile(file);
+ visualizer.device.initOnReset = false;
+ };
+ };
+});
+$e("#openAudio").addEventListener("click", async function () {
+ useMidiBus = false;
+ midwIndicator.classList.off("active");
+ if (audioBlob) {
+ URL.revokeObjectURL(audioBlob);
+ };
+ audioBlob = await fileOpen(propsAud);
+ audioPlayer.src = URL.createObjectURL(audioBlob);
+});
+midwIndicator.addEventListener("click", function () {
+ stDemo.to(-1);
+ if (audioBlob) {
+ URL.revokeObjectURL(audioBlob);
+ };
+ audioBlob = null;
+ audioPlayer.src = "";
+ visualizer.reset();
+ useMidiBus = true;
+ midwIndicator.classList.on("active");
+});
+
+// Get canvas
+let dispCanv = $e("#ymhMu");
+let dispCtx = dispCanv.getContext("2d");
+dispCanv.addEventListener("wheel", function (ev) {
+ ev.preventDefault();
+ let ch = visualizer.getCh();
+ if (ev.deltaY > 0) {
+ visualizer.setCh(ch + 1);
+ } else {
+ visualizer.setCh(ch - 1);
+ };
+});
+dispCanv.addEventListener("mousedown", function (ev) {
+ let ch = visualizer.getCh();
+ if (ev.offsetX < 64) {
+ visualizer.setCh(ch - 1);
+ } else if (ev.offsetX >= 776) {
+ visualizer.setCh(ch + 1);
+ };
+});
+
+// Render frames
+let audioPlayer = $e("#audioPlayer");
+audioPlayer.onended = function () {
+ visualizer.reset();
+ currentPerformance?.resetIndex();
+ audioPlayer.currentTime = 0;
+};
+(async function () {
+ visualizer.reset();
+ let midiBlob = await (await fetch("./demo/KANDI8.mid")).blob();
+ demoBlobs.KANDI8 = {};
+ demoBlobs.KANDI8.midi = midiBlob;
+ visualizer.loadFile(midiBlob);
+ if (audioBlob) {
+ URL.revokeObjectURL(audioBlob);
+ };
+ audioBlob = await (await fetch("./demo/KANDI8.opus")).blob();
+ demoBlobs.KANDI8.wave = audioBlob;
+ audioPlayer.src = URL.createObjectURL(audioBlob);
+})();
+let lastTime = 0;
+let renderThread = setInterval(function () {
+ if (/*!audioPlayer.paused*/true) {
+ let curTime = audioPlayer.currentTime - (self.audioDelay || 0);
+ if (curTime < lastTime) {
+ };
+ if (currentPerformance) {
+ currentPerformance.step(curTime)?.forEach((e) => {
+ visualizer.sendCmd(e.data);
+ });
+ };
+ if (currentAnimation && !visualizer.demoInfo) {
+ visualizer.demoInfo = currentAnimation;
+ };
+ visualizer.render(curTime, dispCtx);
+ lastTime = curTime;
+ };
+}, 20);
+
+getBridge().addEventListener("message", function (ev) {
+ if (useMidiBus) {
+ visualizer.sendCmd(ev.data);
+ };
+});
+
+self.visualizer = visualizer;
+self.performance = currentPerformance;
+
+// Hardcoded animation reference
+{
+ let mu80Ani = {class: "mubasic", fps: 10, size: 16};
+ let mu1kAni = {class: "munativ", fps: 8, size: 32};
+ demoInfo["ninety_hipty"] = mu80Ani;
+ demoInfo["OutOfTheMuse"] = mu80Ani;
+ demoInfo["MU100DEMO"] = mu80Ani;
+ demoInfo["TheMusithm"] = mu80Ani;
+ demoInfo["MU128DEMO"] = mu80Ani;
+ demoInfo["PhoenixA"] = mu1kAni;
+ demoInfo["PhoenixB"] = mu1kAni;
+ demoInfo["R-love"] = mu1kAni;
+};
+
+// Hardcoded performance
+{
+ // PhoenixA
+ let perf = new TimedEvents();
+ perf.push(new PointEvent(0, generateString(` YAMAHA TONE GENERATOR `)));
+ perf.push(new PointEvent(0, generateSwitch(0, 0, 0)));
+ perf.push(new PointEvent(2.52, generateString(` YAMAHA TONE GENERATOR `)));
+ perf.push(new PointEvent(5.04, generateString(` YAMAHA TONE GENERATOR`)));
+ perf.push(new PointEvent(5.21, generateString(` YAMAHA TONE GENERATO`)));
+ perf.push(new PointEvent(5.37, generateString(` YAMAHA TONE GENERAT`)));
+ perf.push(new PointEvent(5.54, generateString(` YAMAHA TONE GENERA`)));
+ perf.push(new PointEvent(5.71, generateString(` YAMAHA TONE GENER`)));
+ perf.push(new PointEvent(5.87, generateString(` YAMAH TONE GENE`)));
+ perf.push(new PointEvent(6.04, generateString(` YAMA TONE GEN`)));
+ perf.push(new PointEvent(6.21, generateString(` YAM TONE GE`)));
+ perf.push(new PointEvent(6.38, generateString(` YA TONE G`)));
+ perf.push(new PointEvent(6.54, generateString(` Y TONE `)));
+ perf.push(new PointEvent(6.71, generateString(` TONE`)));
+ perf.push(new PointEvent(6.88, generateString(` TON`)));
+ perf.push(new PointEvent(7.04, generateString(` TO`)));
+ perf.push(new PointEvent(7.21, generateString(` T`)));
+ perf.push(new PointEvent(7.38, generateString(` `)));
+ perf.push(new PointEvent(7.52, generateString(` MU1000 `)));
+ perf.push(new PointEvent(8.14, generateString(` `)));
+ perf.push(new PointEvent(8.76, generateString(` MU1000 `)));
+ perf.push(new PointEvent(9.38, generateString(` `)));
+ perf.push(new PointEvent(10.08, generateString(` MU1000 `)));
+ perf.push(new PointEvent(10.49, generateString(` DU1000 `)));
+ perf.push(new PointEvent(10.92, generateString(` Db1000 0 `)));
+ perf.push(new PointEvent(11.33, generateString(` Dbl000 06 `)));
+ perf.push(new PointEvent(11.75, generateString(` DblC00 066 `)));
+ perf.push(new PointEvent(12.17, generateString(` DblCo0 066 `)));
+ perf.push(new PointEvent(12.59, generateString(` DblCon 066 0 `)));
+ perf.push(new PointEvent(13.01, generateString(` DblConG 066 00 `)));
+ perf.push(new PointEvent(13.42, generateString(` DblConGr 066 001`)));
+ perf.push(new PointEvent(27.98, generateSwitch(4)));
+ perf.push(new PointEvent(43.85, generateSwitch(10)));
+ perf.push(new PointEvent(63.33, generateSwitch(19, 1, 1)));
+ perf.push(new PointEvent(103.31, generateSwitch(34, 2, 2)));
+ perf.push(new PointEvent(109.52, generateSwitch(35)));
+ perf.push(new PointEvent(114.32, generateSwitch(32)));
+ perf.push(new PointEvent(119.36, generateSwitch(33)));
+ perf.push(new PointEvent(123.68, generateSwitch(36)));
+ perf.push(new PointEvent(128.91, generateSwitch(41)));
+ perf.push(new PointEvent(140.83, generateSwitch(45)));
+ perf.push(new PointEvent(153.29, generateSwitch(42)));
+ perf.push(new PointEvent(176.74, generateSwitch(2, 0, 0)));
+ perf.push(new PointEvent(178.27, generateString(` WindChim. SFX 070`)));
+ perf.push(new PointEvent(178.92, generateString(` WindChim . SFX 070`)));
+ perf.push(new PointEvent(179.56, generateString(` WindChim . SFX 070`)));
+ perf.push(new PointEvent(180.21, generateString(` WindChim . SFX 070`)));
+ perf.push(new PointEvent(180.85, generateString(` WindChim . SFX 070`)));
+ perf.push(new PointEvent(181.5, generateString(` WindChim . SFX 070`)));
+ perf.push(new PointEvent(182.14, generateString(` WindChim . SFX 070`)));
+ perf.push(new PointEvent(182.79, generateString(` WindChim . SFX 070`)));
+ perf.push(new PointEvent(183.43, generateString(` WindChim .SFX 070`)));
+ perf.push(new PointEvent(184.08, generateString(` BindChim .FX 070`)));
+ perf.push(new PointEvent(184.72, generateString(` BrndChim 0.X 070`)));
+ perf.push(new PointEvent(185.36, generateString(` BrtdChim 06. 070`)));
+ perf.push(new PointEvent(186.01, generateString(` BrtFChim 066.070`)));
+ perf.push(new PointEvent(186.66, generateString(` BrtFrhim 066 .70`)));
+ perf.push(new PointEvent(187.3, generateString(` BrtFrHim 066 0.0`)));
+ perf.push(new PointEvent(187.89, generateString(` BrtFrHrm 066 06.`)));
+ perf.push(new PointEvent(187.95, generateString(` BrtFrHrn 066 061`)));
+ perf.fresh();
+ demoPerfs["PhoenixA"] = perf;
+};
+{
+ // PhoenixB
+ let perf = new TimedEvents();
+ perf.push(new PointEvent(0, generateString(` BrtFrHrn 066 061`)));
+ perf.push(new PointEvent(0, generateSwitch(11, 0, 0)));
+ perf.push(new PointEvent(2.02, {type: 15, track: 0, data: [67, 16, 76, 6, 0, 64]}));
+ perf.push(new PointEvent(38.19, generateSwitch(9)));
+ perf.push(new PointEvent(40.05, generateSwitch(16, 0, 1)));
+ perf.push(new PointEvent(40.67, generateSwitch(34, 0, 3)));
+ perf.push(new PointEvent(44.61, generateSwitch(17, 0, 1)));
+ perf.push(new PointEvent(47.59, generateSwitch(32, 0, 3)));
+ perf.push(new PointEvent(53.64, generateSwitch(18)));
+ perf.push(new PointEvent(54.89, generateSwitch(32)));
+ perf.push(new PointEvent(56.01, generateSwitch(49)));
+ perf.push(new PointEvent(58.47, generateSwitch(9, 0, 0)));
+ perf.push(new PointEvent(61.79, generateSwitch(0)));
+ perf.push(new PointEvent(71.54, generateSwitch(1)));
+ perf.push(new PointEvent(78.46, generateSwitch(16, 0, 3)));
+ perf.push(new PointEvent(80.33, generateSwitch(0, 0, 0)));
+ perf.push(new PointEvent(83.43, generateSwitch(0, 0, 3)));
+ perf.push(new PointEvent(84.86, generateSwitch(0, 0, 0)));
+ perf.push(new PointEvent(87.83, generateSwitch(0, 0, 1)));
+ perf.push(new PointEvent(89.29, generateSwitch(1, 0, 3)));
+ perf.push(new PointEvent(93.61, generateSwitch(1, 0, 0)));
+ perf.push(new PointEvent(98.21, generateSwitch(16, 0, 3)));
+ perf.push(new PointEvent(102.93, generateSwitch(17, 0, 1)));
+ perf.push(new PointEvent(107.45, generateSwitch(16, 0, 3)));
+ perf.push(new PointEvent(107.78, generateSwitch(17, 0, 1)));
+ perf.push(new PointEvent(110.97, generateSwitch(32, 0, 3)));
+ perf.push(new PointEvent(111.98, generateSwitch(16, 0, 1)));
+ perf.push(new PointEvent(113.27, generateSwitch(34, 0, 3)));
+ perf.push(new PointEvent(114.18, generateSwitch(16, 0, 1)));
+ perf.push(new PointEvent(115.75, generateSwitch(17, 0, 3)));
+ perf.push(new PointEvent(123.01, generateSwitch(5, 0, 0)));
+ perf.push(new PointEvent(124.53, generateSwitch(7, 0, 0)));
+ perf.push(new PointEvent(126.06, generateSwitch(20, 1, 1)));
+ perf.push(new PointEvent(126.78, generateSwitch(32, 0, 3)));
+ perf.fresh();
+ demoPerfs["PhoenixB"] = perf;
+};
+{
+ // Ninety Hipty
+ let perf = new TimedEvents();
+ perf.push(new PointEvent(0.5, generateSwitch(1, 0, 0)));
+ perf.push(new PointEvent(19.7, generateSwitch(11)));
+ perf.push(new PointEvent(28.5, generateSwitch(12)));
+ perf.push(new PointEvent(37.4, generateSwitch(4, 0, 1)));
+ perf.push(new PointEvent(45.8, generateSwitch(2)));
+ perf.push(new PointEvent(50.6, generateSwitch(3)));
+ perf.push(new PointEvent(54.9, generateSwitch(4)));
+ perf.push(new PointEvent(74.4, generateSwitch(0)));
+ perf.push(new PointEvent(76.85, generateSwitch(9)));
+ perf.push(new PointEvent(81.75, generateSwitch(10)));
+ perf.push(new PointEvent(86.6, generateSwitch(25)));
+ perf.push(new PointEvent(96.7, generateSwitch(13)));
+ perf.push(new PointEvent(106.2, generateSwitch(22)));
+ perf.push(new PointEvent(111.25, generateSwitch(23)));
+ perf.push(new PointEvent(116.1, generateSwitch(17)));
+ perf.push(new PointEvent(121, generateSwitch(13)));
+ perf.push(new PointEvent(127.9, generateSwitch(8)));
+ perf.push(new PointEvent(138, generateSwitch(0)));
+ perf.fresh();
+ demoPerfs["ninety_hipty"] = perf;
+};
+{
+ // Is it realy love?
+ let perf = new TimedEvents();
+ perf.push(new PointEvent(1.8, generateSwitch(24, 1, 2)));
+ perf.push(new PointEvent(7.6, generateSwitch(29)));
+ perf.push(new PointEvent(10.53, generateSwitch(0, 0, 1)));
+ perf.push(new PointEvent(20.9, generateSwitch(22)));
+ perf.push(new PointEvent(28.47, generateSwitch(23)));
+ perf.push(new PointEvent(31.1, generateSwitch(3, 0, 0)));
+ perf.push(new PointEvent(38.88, generateSwitch(17, 1, 1)));
+ perf.push(new PointEvent(41.02, generateSwitch(5, 0, 1)));
+ perf.push(new PointEvent(48.59, generateSwitch(17)));
+ perf.push(new PointEvent(50.9, generateSwitch(0, 0, 0)));
+ perf.push(new PointEvent(70.7, generateSwitch(1, 0, 1)));
+ perf.push(new PointEvent(78.2, generateSwitch(17)));
+ perf.push(new PointEvent(80.79, generateSwitch(2)));
+ perf.push(new PointEvent(88.65, generateSwitch(1)));
+ perf.push(new PointEvent(90.02, generateSwitch(2)));
+ perf.push(new PointEvent(91.11, generateSwitch(1)));
+ perf.push(new PointEvent(92.43, generateSwitch(2)));
+ perf.push(new PointEvent(93.18, generateSwitch(0, 0, 0)));
+ perf.push(new PointEvent(112.9, generateSwitch(1, 0, 1)));
+ perf.push(new PointEvent(119, generateSwitch(17)));
+ perf.push(new PointEvent(122.64, generateSwitch(2)));
+ perf.push(new PointEvent(130.12, generateSwitch(15)));
+ perf.push(new PointEvent(132.73, generateSwitch(0, 0, 0)));
+ perf.push(new PointEvent(152.54, generateSwitch(1, 0, 1)));
+ perf.push(new PointEvent(158.66, generateSwitch(17)));
+ perf.push(new PointEvent(162.39, generateSwitch(2)));
+ perf.push(new PointEvent(166.24, generateSwitch(14)));
+ perf.push(new PointEvent(172.26, generateSwitch(8, 0, 0)));
+ perf.push(new PointEvent(182.23, generateSwitch(8, 0, 1)));
+ perf.push(new PointEvent(191.81, generateSwitch(23, 1, 1)));
+ perf.push(new PointEvent(193, generateSwitch(0, 0, 0)));
+ perf.fresh();
+ demoPerfs["R-love"] = perf;
+};
+{
+ // MU80 demo, Out of the Muse
+ let perf = new TimedEvents();
+ perf.push(new PointEvent(1.6, generateSwitch(19, 0, 1)));
+ perf.push(new PointEvent(18.92, generateSwitch(3, 0, 0)));
+ perf.push(new PointEvent(27.29, generateSwitch(2)));
+ perf.push(new PointEvent(31.47, generateSwitch(9)));
+ perf.push(new PointEvent(33.49, generateSwitch(10)));
+ perf.push(new PointEvent(35.52, generateSwitch(19, 0, 1)));
+ perf.push(new PointEvent(37.62, generateSwitch(1)));
+ perf.push(new PointEvent(39.73, generateSwitch(3)));
+ perf.push(new PointEvent(41.83, generateSwitch(6)));
+ perf.push(new PointEvent(43.93, generateSwitch(18)));
+ perf.push(new PointEvent(46.03, generateSwitch(19)));
+ perf.push(new PointEvent(48.13, generateSwitch(21)));
+ perf.push(new PointEvent(50.23, generateSwitch(24)));
+ perf.push(new PointEvent(52.34, generateSwitch(3, 0, 0)));
+ perf.push(new PointEvent(57.76, generateSwitch(4)));
+ perf.push(new PointEvent(61.12, generateSwitch(3)));
+ perf.push(new PointEvent(64.11, generateSwitch(4)));
+ perf.push(new PointEvent(69.84, generateSwitch(6)));
+ perf.push(new PointEvent(87.48, generateSwitch(4, 0, 1)));
+ perf.push(new PointEvent(117.12, generateSwitch(23)));
+ perf.push(new PointEvent(125, generateSwitch(0)));
+ perf.fresh();
+ demoPerfs["OutOfTheMuse"] = perf;
+};
+{
+ // MU100 demo, It's an AmaZing MU World!!
+ let perf = new TimedEvents();
+ perf.push(new PointEvent(3.28, generateSwitch(1)));
+ perf.push(new PointEvent(6.22, generateSwitch(5)));
+ perf.push(new PointEvent(7.93, generateSwitch(6)));
+ perf.push(new PointEvent(10.92, generateSwitch(5)));
+ perf.push(new PointEvent(13.98, generateSwitch(6)));
+ perf.push(new PointEvent(17.31, generateSwitch(5)));
+ perf.push(new PointEvent(18.64, generateSwitch(6)));
+ perf.push(new PointEvent(23.93, generateSwitch(11)));
+ perf.push(new PointEvent(24.41, generateSwitch(2)));
+ perf.push(new PointEvent(24.89, generateSwitch(9)));
+ perf.push(new PointEvent(25.37, generateSwitch(10)));
+ perf.push(new PointEvent(25.89, generateSwitch(3)));
+ perf.push(new PointEvent(41.84, generateSwitch(15)));
+ perf.push(new PointEvent(43.93, generateSwitch(14)));
+ perf.push(new PointEvent(46.02, generateSwitch(15)));
+ perf.push(new PointEvent(50.25, generateSwitch(16)));
+ perf.push(new PointEvent(54.46, generateSwitch(15)));
+ perf.push(new PointEvent(58.37, generateSwitch(16)));
+ perf.push(new PointEvent(62.34, generateSwitch(15)));
+ perf.push(new PointEvent(66.58, generateSwitch(16)));
+ perf.push(new PointEvent(70.41, generateSwitch(15)));
+ perf.fresh();
+ demoPerfs["MU100DEMO"] = perf;
+};
+{
+ // MU128 demo
+ let perf = new TimedEvents();
+ // Disable native RS
+ perf.push(new PointEvent(0, {type: 15, track: 0, data: [67, 16, 73, 0, 0, 14, 0]}));
+ perf.push(new PointEvent(0, generateSwitch(0, 0, 0)));
+ perf.push(new PointEvent(1.6, generateSwitch(0, 0, 3)));
+ perf.push(new PointEvent(40.02, generateSwitch(48, 3, 3)));
+ perf.push(new PointEvent(41.68, generateSwitch(49)));
+ perf.push(new PointEvent(43.07, generateSwitch(50)));
+ perf.push(new PointEvent(44.65, generateSwitch(51)));
+ perf.push(new PointEvent(46.2, generateSwitch(52)));
+ perf.push(new PointEvent(47.74, generateSwitch(53)));
+ perf.push(new PointEvent(49.29, generateSwitch(54)));
+ perf.push(new PointEvent(50.83, generateSwitch(55)));
+ perf.push(new PointEvent(52.38, generateSwitch(56)));
+ perf.push(new PointEvent(53.92, generateSwitch(58)));
+ perf.push(new PointEvent(55.47, generateSwitch(59)));
+ perf.push(new PointEvent(57.02, generateSwitch(48)));
+ perf.push(new PointEvent(69.56, generateSwitch(8, 0, 0)));
+ perf.push(new PointEvent(70.54, generateSwitch(9)));
+ perf.push(new PointEvent(71.52, generateSwitch(10)));
+ perf.push(new PointEvent(72.5, generateSwitch(11)));
+ perf.push(new PointEvent(73.48, generateSwitch(12)));
+ perf.push(new PointEvent(74.46, generateSwitch(13)));
+ perf.push(new PointEvent(75.44, generateSwitch(14)));
+ perf.push(new PointEvent(76.42, generateSwitch(15)));
+ perf.push(new PointEvent(77.4, generateSwitch(8)));
+ perf.push(new PointEvent(81.18, generateSwitch(0)));
+ perf.push(new PointEvent(82.15, generateSwitch(1)));
+ perf.push(new PointEvent(83.12, generateSwitch(2)));
+ perf.push(new PointEvent(84.09, generateSwitch(3)));
+ perf.push(new PointEvent(85.06, generateSwitch(4)));
+ perf.push(new PointEvent(86.03, generateSwitch(5)));
+ perf.push(new PointEvent(87.0, generateSwitch(6)));
+ perf.push(new PointEvent(87.97, generateSwitch(7)));
+ perf.push(new PointEvent(88.94, generateSwitch(0)));
+ perf.push(new PointEvent(96.66, generateSwitch(16, 1, 1)));
+ perf.push(new PointEvent(98.15, generateSwitch(17)));
+ perf.push(new PointEvent(99.63, generateSwitch(18)));
+ perf.push(new PointEvent(101.12, generateSwitch(19)));
+ perf.push(new PointEvent(102.6, generateSwitch(20)));
+ perf.push(new PointEvent(104.09, generateSwitch(21)));
+ perf.push(new PointEvent(105.57, generateSwitch(22)));
+ perf.push(new PointEvent(107.06, generateSwitch(23)));
+ perf.push(new PointEvent(108.54, generateSwitch(24)));
+ perf.push(new PointEvent(110.03, generateSwitch(25)));
+ perf.push(new PointEvent(111.51, generateSwitch(26)));
+ perf.push(new PointEvent(112.99, generateSwitch(27)));
+ perf.push(new PointEvent(114.48, generateSwitch(28)));
+ perf.push(new PointEvent(115.97, generateSwitch(29)));
+ perf.push(new PointEvent(117.45, generateSwitch(30)));
+ perf.push(new PointEvent(118.94, generateSwitch(31)));
+ perf.push(new PointEvent(120.42, generateSwitch(16)));
+ perf.push(new PointEvent(122.34, generateSwitch(5, 0, 1)));
+ perf.push(new PointEvent(158.26, generateSwitch(0)));
+ perf.fresh();
+ demoPerfs["MU128DEMO"] = perf;
+};
diff --git a/src/fakeNs5r/index.js b/src/fakeNs5r/index.js
new file mode 100644
index 00000000..abbfe0da
--- /dev/null
+++ b/src/fakeNs5r/index.js
@@ -0,0 +1,238 @@
+"use strict";
+
+import {} from "../../libs/lightfelt@ltgcgo/main/cssClass.js";
+import {$e, $a} from "../../libs/lightfelt@ltgcgo/main/quickPath.js";
+import Ns5rDisplay from "../disp/disp_n5.mjs";
+import {fileOpen} from "../../libs/browser-fs-access@GoogleChromeLabs/browser_fs_access.min.js";
+import {
+ getBridge
+} from "../bridge/index.mjs";
+import {sysexBitmap} from "../state/emitGlobal.js";
+import {SheetData} from "../basic/sheetLoad.js";
+
+let demoBlobs = {};
+let demoModes = [];
+demoModes[9] = "gm";
+let useMidiBus = false;
+
+// Standard switching
+let stSwitch = $a("b.mode");
+let stSwitchMode = [];
+stSwitch.to = function (i) {
+ stSwitch.forEach(function (e) {
+ e.classList.off("active");
+ });
+ if (i > -1) {
+ stSwitch[i].classList.on("active");
+ };
+};
+stSwitch.forEach(function (e, i, a) {
+ stSwitchMode[i] = e.title;
+ e.addEventListener("click", function () {
+ visualizer.switchMode(e.title, true);
+ stSwitch.to(i);
+ });
+});
+
+// Standard demo switching
+let demoPool = new SheetData();
+let stList = $e("span#demo-list"), stDemo = [];
+const srcPaths = ['../../midi-demo-data/collection/octavia/', './demo/'];
+let getBlobFrom = async function (filename) {
+ let i = 0;
+ while (i < srcPaths.length) {
+ let e = srcPaths[i];
+ let response = await fetch(`${e}${filename}`);
+ if (response.status < 400) {
+ return response;
+ };
+ i ++;
+ };
+ console.error(`Loading of data ${filename} failed.`);
+};
+let codepointArray = function (string) {
+ let arr = new Uint16Array(string.length);
+ arr.forEach((e, i, a) => {
+ a[i] = string.charCodeAt(i);
+ });
+ return arr;
+};
+getBlobFrom(`list.tsv`).then(async (response) => {
+ await demoPool.load(await response.text());
+ //console.info(demoPool.data);
+ demoPool.data.forEach((e, i) => {
+ if (i) {
+ let space = document.createElement("span");
+ space.innerHTML = " ";
+ stList.appendChild(space);
+ } else {
+ stList.innerText = "";
+ };
+ let demoChoice = document.createElement("b");
+ demoChoice.innerText = e.text;
+ demoChoice.title = e.file;
+ demoChoice.classList.on("demo");
+ stDemo.push(demoChoice);
+ stList.appendChild(demoChoice);
+ });
+ stDemo.to = function (i) {
+ stDemo.forEach(function (e) {
+ e.classList.off("active");
+ });
+ if (i > -1) {
+ stDemo[i].classList.on("active");
+ };
+ };
+ stDemo.forEach(function (e, i, a) {
+ e.addEventListener("click", async function () {
+ audioPlayer.pause();
+ if (!demoBlobs[e.title]?.midi) {
+ demoBlobs[e.title] = {};
+ audioPlayer.src = "about:blank";
+ demoBlobs[e.title].midi = await (await getBlobFrom(`${e.title}.mid`)).blob();
+ demoBlobs[e.title].wave = await (await getBlobFrom(`${e.title}.opus`)).blob();
+ };
+ audioPlayer.currentTime = 0;
+ visualizer.reset();
+ visualizer.loadFile(demoBlobs[e.title].midi);
+ if (audioBlob) {
+ URL.revokeObjectURL(audioBlob);
+ };
+ audioBlob = demoBlobs[e.title].wave;
+ audioPlayer.src = URL.createObjectURL(audioBlob);
+ if (demoModes[i]?.length > 0) {
+ visualizer.switchMode(demoModes[i]);
+ };
+ stDemo.to(i);
+ visualizer.device.setLetterDisplay(codepointArray(`\x8a${demoPool.data[i].artist.slice(0, 15).padEnd(15, " ")}\x8b${demoPool.data[i].title.slice(0, 15)}`));
+ });
+ });
+});
+
+// Start the visualizers
+self.sysexBitmap = sysexBitmap;
+self.visualizer = new Ns5rDisplay();
+visualizer.addEventListener("reset", function (e) {
+ console.info("Processor reset.");
+});
+
+// Listen to mode switches
+visualizer.addEventListener("mode", function (ev) {
+ stSwitch.to(stSwitchMode.indexOf(ev.data));
+});
+
+// Open the files
+let midwIndicator = $e("#openMidw");
+let audioBlob;
+const propsMid = JSON.parse('{"extensions":[".mid",".MID",".kar",".KAR",".syx",".SYX",".s7e",".S7E"],"startIn":"music","id":"midiOpener","description":"Open a MIDI file"}'),
+propsAud = JSON.parse('{"mimeTypes":["audio/*"],"startIn":"music","id":"audioOpener","description":"Open an audio file"}');
+$e("#openMidi").addEventListener("click", async function () {
+ useMidiBus = false;
+ midwIndicator.classList.off("active");
+ let file = await fileOpen(propsMid);
+ let fileSplit = file.name.lastIndexOf("."), ext = "";
+ if (fileSplit > -1) {
+ ext = file.name.slice(fileSplit + 1).toLowerCase();
+ };
+ switch (ext) {
+ case "syx": {
+ // Load SysEx blobs
+ visualizer.sendCmd({type: 15, track: 0, data: new Uint8Array(await file.arrayBuffer())});
+ break;
+ };
+ case "s7e": {
+ // Load sound banks
+ visualizer.device.loadBank(ext, file);
+ break;
+ };
+ default: {
+ // Load MIDI files
+ stDemo.to(-1);
+ visualizer.reset();
+ visualizer.loadFile(file);
+ visualizer.device.initOnReset = false;
+ };
+ };
+});
+$e("#openAudio").addEventListener("click", async function () {
+ useMidiBus = false;
+ midwIndicator.classList.off("active");
+ if (audioBlob) {
+ URL.revokeObjectURL(audioBlob);
+ };
+ audioBlob = await fileOpen(propsAud);
+ audioPlayer.src = URL.createObjectURL(audioBlob);
+});
+midwIndicator.addEventListener("click", function () {
+ stDemo.to(-1);
+ if (audioBlob) {
+ URL.revokeObjectURL(audioBlob);
+ };
+ audioBlob = null;
+ audioPlayer.src = "";
+ visualizer.reset();
+ useMidiBus = true;
+ midwIndicator.classList.on("active");
+});
+
+// Get canvas
+let dispCanv = $e("#ns5rSc");
+let dispCtx = dispCanv.getContext("2d");
+dispCanv.addEventListener("wheel", function (ev) {
+ ev.preventDefault();
+ let ch = visualizer.getCh();
+ if (ev.deltaY > 0) {
+ visualizer.setCh(ch + 1);
+ } else {
+ visualizer.setCh(ch - 1);
+ };
+});
+dispCanv.addEventListener("mousedown", function (ev) {
+ let ch = visualizer.getCh();
+ if (ev.offsetX < 64) {
+ visualizer.setCh(ch - 1);
+ } else if (ev.offsetX >= 801) {
+ visualizer.setCh(ch + 1);
+ };
+});
+
+// Allow channel switching in browser console
+self.toCh = function (ch) {
+ visualizer.setCh(ch);
+};
+
+// Render frames
+let audioPlayer = $e("#audioPlayer");
+audioPlayer.onended = function () {
+ visualizer.reset();
+ audioPlayer.currentTime = 0;
+};
+(async function () {
+ visualizer.reset();
+ let midiBlob = await (await fetch("./demo/KANDI8.mid")).blob();
+ demoBlobs.KANDI8 = {};
+ demoBlobs.KANDI8.midi = midiBlob;
+ visualizer.loadFile(midiBlob);
+ if (audioBlob) {
+ URL.revokeObjectURL(audioBlob);
+ };
+ audioBlob = await (await fetch("./demo/KANDI8.opus")).blob();
+ demoBlobs.KANDI8.wave = audioBlob;
+ audioPlayer.src = URL.createObjectURL(audioBlob);
+})();
+let lastTime = 0;
+let renderThread = setInterval(function () {
+ if (/*!audioPlayer.paused*/true) {
+ let curTime = audioPlayer.currentTime - (self.audioDelay || 0);
+ if (curTime < lastTime) {
+ };
+ visualizer.render(curTime, dispCtx, location.hash?.length > 1);
+ lastTime = curTime;
+ };
+}, 20);
+
+getBridge().addEventListener("message", function (ev) {
+ if (useMidiBus) {
+ visualizer.sendCmd(ev.data);
+ };
+});
diff --git a/src/fakePsr/index.js b/src/fakePsr/index.js
new file mode 100644
index 00000000..3278c703
--- /dev/null
+++ b/src/fakePsr/index.js
@@ -0,0 +1,754 @@
+"use strict";
+
+import {} from "../../libs/lightfelt@ltgcgo/main/cssClass.js";
+import {$e, $a} from "../../libs/lightfelt@ltgcgo/main/quickPath.js";
+import PsrDisplay from "../disp/disp_psr.mjs";
+import {fileOpen} from "../../libs/browser-fs-access@GoogleChromeLabs/browser_fs_access.min.js";
+import {
+ getBridge
+} from "../bridge/index.mjs";
+import {SheetData} from "../basic/sheetLoad.js";
+
+import {
+ PointEvent,
+ RangeEvent,
+ TimedEvents
+} from "../../libs/lightfelt@ltgcgo/ext/timedEvents.js";
+
+let demoBlobs = {};
+let demoPerfs = {};
+let demoInfo = {};
+let demoModes = [];
+demoModes[9] = "gm";
+let currentPerformance;
+let currentAnimation;
+let useMidiBus = false;
+let demoId = 0;
+
+// Generate Octavia channel switch SysEx
+let generateSwitch = function (ch = 0, min, max) {
+ let data = [67, 16, 73, 0, 0, 10, ch];
+ if (min?.constructor == Number) {
+ data.push(min);
+ if (max.constructor == Number) {
+ data.push(max);
+ };
+ };
+ return {
+ type: 15,
+ track: 0,
+ data
+ };
+};
+let generateString = function (text) {
+ let data = [67, 16, 76, 6, 0, 0];
+ for (let c = 0; c < text.length; c ++) {
+ data.push(text.charCodeAt(c));
+ };
+ return {
+ type: 15,
+ track: 0,
+ data
+ };
+};
+
+// Standard switching
+let stSwitch = $a("b.mode");
+let stSwitchMode = [];
+stSwitch.to = function (i) {
+ stSwitch.forEach(function (e) {
+ e.classList.off("active");
+ });
+ if (i > -1) {
+ stSwitch[i].classList.on("active");
+ };
+};
+stSwitch.forEach(function (e, i, a) {
+ stSwitchMode[i] = e.title;
+ e.addEventListener("click", function () {
+ visualizer.switchMode(e.title, true);
+ stSwitch.to(i);
+ });
+});
+
+// Standard demo switching
+let demoPool = new SheetData();
+let stList = $e("span#demo-list"), stDemo = [];
+const srcPaths = ['../../midi-demo-data/collection/octavia/', './demo/'];
+let getBlobFrom = async function (filename) {
+ let i = 0;
+ while (i < srcPaths.length) {
+ let e = srcPaths[i];
+ let response = await fetch(`${e}${filename}`);
+ if (response.status < 400) {
+ return response;
+ };
+ i ++;
+ };
+ console.error(`Loading of data ${filename} failed.`);
+};
+getBlobFrom(`list.tsv`).then(async (response) => {
+ await demoPool.load(await response.text());
+ //console.info(demoPool.data);
+ demoPool.data.forEach((e, i) => {
+ if (i) {
+ let space = document.createElement("span");
+ space.innerHTML = " ";
+ stList.appendChild(space);
+ } else {
+ stList.innerText = "";
+ };
+ let demoChoice = document.createElement("b");
+ demoChoice.innerText = e.text;
+ demoChoice.title = e.file;
+ demoChoice.classList.on("demo");
+ stDemo.push(demoChoice);
+ stList.appendChild(demoChoice);
+ });
+ stDemo.to = function (i) {
+ stDemo.forEach(function (e) {
+ e.classList.off("active");
+ });
+ if (i > -1) {
+ stDemo[i].classList.on("active");
+ };
+ };
+ stDemo.forEach(function (e, i, a) {
+ e.addEventListener("click", async function () {
+ audioPlayer.pause();
+ if (!demoBlobs[e.title]?.midi) {
+ demoBlobs[e.title] = {};
+ audioPlayer.src = "about:blank";
+ demoBlobs[e.title].midi = await (await getBlobFrom(`${e.title}.mid`)).blob();
+ demoBlobs[e.title].wave = await (await getBlobFrom(`${e.title}.opus`)).blob();
+ };
+ currentPerformance = demoPerfs[e.title];
+ currentPerformance?.resetIndex();
+ currentAnimation = demoInfo[e.title];
+ audioPlayer.currentTime = 0;
+ visualizer.reset();
+ visualizer.loadFile(demoBlobs[e.title].midi);
+ if (audioBlob) {
+ URL.revokeObjectURL(audioBlob);
+ };
+ audioBlob = demoBlobs[e.title].wave;
+ audioPlayer.src = URL.createObjectURL(audioBlob);
+ if (demoModes[i]?.length > 0) {
+ visualizer.switchMode(demoModes[i]);
+ };
+ stDemo.to(i);
+ demoId = i;
+ });
+ });
+});
+
+// Backlight color switching
+let backlightColor = "#b7bfaf64";
+let blSwitch = $a("b.backlight");
+blSwitch.to = function (i) {
+ blSwitch.forEach(function (e) {
+ e.classList.off("active");
+ });
+ if (i > -1) {
+ blSwitch[i].classList.on("active");
+ };
+};
+blSwitch.forEach(function (e, i) {
+ e.addEventListener("click", function () {
+ backlightColor = e.title;
+ blSwitch.to(i);
+ });
+});
+
+// Automatic channel switching
+let enableChannelSwitch = true;
+let csSwitch = $a("b.channelSwitching");
+csSwitch.to = function (i) {
+ csSwitch.forEach(function (e) {
+ e.classList.off("active");
+ });
+ if (enableChannelSwitch) {
+ csSwitch[i].classList.on("active");
+ };
+};
+csSwitch.forEach(function (e, i) {
+ e.addEventListener("click", function () {
+ enableChannelSwitch = !enableChannelSwitch;
+ this.innerText = enableChannelSwitch ? "ON" : "OFF";
+ csSwitch.to(i);
+ });
+});
+
+// Start the visualizers
+self.visualizer = new PsrDisplay();
+visualizer.addEventListener("reset", function (e) {
+ visualizer.songTitle = "";
+ console.info("Processor reset.");
+});
+
+// Listen to mode switches
+visualizer.addEventListener("mode", function (ev) {
+ stSwitch.to(stSwitchMode.indexOf(ev.data));
+ let textCmd = [67, 16, 76, 6, 0, 0, 77, 79, 68, 69, 58, 32];
+ let modeText = {
+ gm: [71, 77],
+ gs: [71, 83],
+ xg: [88, 71],
+ g2: [71, 77, 50],
+ mt32: [77, 84, 45, 51, 50],
+ ns5r: [78, 83, 53, 82],
+ ag10: [65, 71, 45, 49, 48],
+ "05rw": [48, 53, 82, 47, 87],
+ x5d: [88, 53, 68],
+ k11: [71, 77, 101, 103, 97],
+ sg: [83, 71],
+ krs: [75, 82, 79, 83, 83],
+ s90es: [83, 57, 48, 32, 69, 83],
+ motif: [77, 111, 116, 105, 102, 32, 69, 83]
+ };
+ visualizer.sendCmd({type: 15, track: 0, data: textCmd.concat(modeText[visualizer.getMode()])});
+});
+
+// Open the files
+let midwIndicator = $e("#openMidw");
+let audioBlob;
+const propsMid = JSON.parse('{"extensions":[".mid",".MID",".kar",".KAR",".syx",".SYX",".s7e",".S7E"],"startIn":"music","id":"midiOpener","description":"Open a MIDI file"}'),
+propsAud = JSON.parse('{"mimeTypes":["audio/*"],"startIn":"music","id":"audioOpener","description":"Open an audio file"}');
+$e("#openMidi").addEventListener("click", async function () {
+ useMidiBus = false;
+ midwIndicator.classList.off("active");
+ let file = await fileOpen(propsMid);
+ let fileSplit = file.name.lastIndexOf("."), ext = "";
+ if (fileSplit > -1) {
+ ext = file.name.slice(fileSplit + 1).toLowerCase();
+ };
+ switch (ext) {
+ case "syx": {
+ // Load SysEx blobs
+ visualizer.sendCmd({type: 15, track: 0, data: new Uint8Array(await file.arrayBuffer())});
+ break;
+ };
+ case "s7e": {
+ // Load sound banks
+ visualizer.device.loadBank(ext, file);
+ break;
+ };
+ default: {
+ // Load MIDI files
+ stDemo.to(-1);
+ visualizer.reset();
+ visualizer.loadFile(file);
+ visualizer.device.initOnReset = false;
+ };
+ };
+});
+$e("#openAudio").addEventListener("click", async function () {
+ useMidiBus = false;
+ midwIndicator.classList.off("active");
+ if (audioBlob) {
+ URL.revokeObjectURL(audioBlob);
+ };
+ audioBlob = await fileOpen(propsAud);
+ audioPlayer.src = URL.createObjectURL(audioBlob);
+});
+midwIndicator.addEventListener("click", function () {
+ stDemo.to(-1);
+ if (audioBlob) {
+ URL.revokeObjectURL(audioBlob);
+ };
+ audioBlob = null;
+ audioPlayer.src = "";
+ visualizer.reset();
+ useMidiBus = true;
+ midwIndicator.classList.on("active");
+});
+
+visualizer.addEventListener("meta", function (ev) {
+ if (!visualizer.songTitle) {
+ ev.data.forEach(function (e) {
+ if (!visualizer.songTitle && e.meta == 3) {
+ visualizer.songTitle = e.data;
+ };
+ });
+ };
+});
+
+// Get canvas
+let dispCanv = $e("#ymhPsr");
+let dispCtx = dispCanv.getContext("2d");
+let mixerView = false;
+let tempoView = false;
+dispCanv.addEventListener("wheel", function (ev) {
+ ev.preventDefault();
+ let ch = visualizer.getCh();
+ if (ev.deltaY > 0) {
+ visualizer.setCh(ch + 1);
+ } else {
+ visualizer.setCh(ch - 1);
+ };
+ ev.preventDefault();
+ ev.stopImmediatePropagation();
+});
+dispCanv.addEventListener("mousedown", function (ev) {
+ let ch = visualizer.getCh();
+ if (ev.button == 0) {
+ if (ev.offsetX < 64) {
+ visualizer.setCh(ch - 1);
+ } else if (ev.offsetX >= 1046) {
+ visualizer.setCh(ch + 1);
+ } else if (ev.offsetY < 110) {
+ mixerView = !mixerView;
+ } else if (ev.offsetY > 218) {
+ tempoView = !tempoView;
+ };
+ };
+});
+
+// Allow channel switching in browser console
+self.toCh = function (ch) {
+ visualizer.setCh(ch);
+};
+
+// Render frames
+let audioPlayer = $e("#audioPlayer");
+audioPlayer.onended = function () {
+ visualizer.reset();
+ currentPerformance?.resetIndex();
+ audioPlayer.currentTime = 0;
+};
+(async function () {
+ visualizer.reset();
+ let midiBlob = await (await fetch("./demo/KANDI8.mid")).blob();
+ demoBlobs.KANDI8 = {};
+ demoBlobs.KANDI8.midi = midiBlob;
+ visualizer.loadFile(midiBlob);
+ if (audioBlob) {
+ URL.revokeObjectURL(audioBlob);
+ };
+ audioBlob = await (await fetch("./demo/KANDI8.opus")).blob();
+ demoBlobs.KANDI8.wave = audioBlob;
+ audioPlayer.src = URL.createObjectURL(audioBlob);
+ currentPerformance = demoPerfs["KANDI8"];
+})();
+let lastTime = 0;
+let renderThread = setInterval(function () {
+ if (/*!audioPlayer.paused*/true) {
+ let curTime = audioPlayer.currentTime - (self.audioDelay || 0);
+ if (curTime < lastTime) {
+ };
+ if (enableChannelSwitch && currentPerformance) {
+ currentPerformance.step(curTime)?.forEach((e) => {
+ visualizer.sendCmd(e.data);
+ });
+ };
+ if (currentAnimation && !visualizer.demoInfo) {
+ visualizer.demoInfo = currentAnimation;
+ };
+ visualizer.render(curTime, dispCtx, backlightColor, mixerView, tempoView, useMidiBus ? 0 : demoId, location.hash?.length > 1);
+ lastTime = curTime;
+ };
+}, 20);
+
+getBridge().addEventListener("message", function (ev) {
+ if (useMidiBus) {
+ visualizer.sendCmd(ev.data);
+ };
+});
+
+self.visualizer = visualizer;
+self.performance = currentPerformance;
+
+// Hardcoded animation reference
+{
+ let mu80Ani = {class: "mubasic", fps: 10, size: 16};
+ let mu1kAni = {class: "munativ", fps: 8, size: 32};
+ demoInfo["ninety_hipty"] = mu80Ani;
+ demoInfo["OutOfTheMuse"] = mu80Ani;
+ demoInfo["MU100DEMO"] = mu80Ani;
+ demoInfo["TheMusithm"] = mu80Ani;
+ demoInfo["MU128DEMO"] = mu80Ani;
+ demoInfo["PhoenixA"] = mu1kAni;
+ demoInfo["PhoenixB"] = mu1kAni;
+ demoInfo["R-love"] = mu1kAni;
+};
+
+// Hardcoded channel switching
+{
+ // KANDI8
+ let perf = new TimedEvents();
+ perf.push(new PointEvent(4, generateSwitch(15)));
+ perf.push(new PointEvent(5.7, generateSwitch(12)));
+ perf.push(new PointEvent(20, generateSwitch(1)));
+ perf.push(new PointEvent(89, generateSwitch(0)));
+ perf.push(new PointEvent(117, generateSwitch(12)));
+ perf.fresh();
+ demoPerfs["KANDI8"] = perf;
+};
+{
+ // Straight to the Horizon
+ let perf = new TimedEvents();
+ perf.push(new PointEvent(3.5, generateSwitch(13)));
+ perf.push(new PointEvent(7.5, generateSwitch(6)));
+ perf.push(new PointEvent(22, generateSwitch(5)));
+ perf.push(new PointEvent(80, generateSwitch(1)));
+ perf.push(new PointEvent(106, generateSwitch(0)));
+ perf.push(new PointEvent(148.5, generateSwitch(1)));
+ perf.push(new PointEvent(177, generateSwitch(5)));
+ perf.fresh();
+ demoPerfs["HORIZON"] = perf;
+};
+{
+ // Low Down
+ let perf = new TimedEvents();
+ perf.push(new PointEvent(3, generateSwitch(2)));
+ perf.push(new PointEvent(6, generateSwitch(5)));
+ perf.push(new PointEvent(28, generateSwitch(1)));
+ perf.push(new PointEvent(51, generateSwitch(6)));
+ perf.push(new PointEvent(73.5, generateSwitch(5)));
+ perf.push(new PointEvent(96, generateSwitch(4)));
+ perf.push(new PointEvent(118, generateSwitch(6)));
+ perf.push(new PointEvent(141, generateSwitch(5)));
+ perf.push(new PointEvent(163, generateSwitch(5)));
+ perf.push(new PointEvent(186, generateSwitch(5)));
+ perf.fresh();
+ demoPerfs["Sam Sketty - Low Down"] = perf;
+};
+{
+ // StarGame
+ let perf = new TimedEvents();
+ perf.push(new PointEvent(0, generateSwitch(3)));
+ perf.push(new PointEvent(8.6, generateSwitch(2)));
+ perf.fresh();
+ demoPerfs["StarGame"] = perf;
+};
+{
+ // Japanese
+ let perf = new TimedEvents();
+ perf.push(new PointEvent(2, generateSwitch(8)));
+ perf.push(new PointEvent(7.5, generateSwitch(9)));
+ perf.fresh();
+ demoPerfs["25Japan"] = perf;
+};
+{
+ // Clasitario
+ let perf = new TimedEvents();
+ perf.push(new PointEvent(7.5, generateSwitch(2)));
+ perf.push(new PointEvent(21.5, generateSwitch(0)));
+ perf.push(new PointEvent(28.5, generateSwitch(2)));
+ perf.push(new PointEvent(53.5, generateSwitch(0)));
+ perf.push(new PointEvent(57.5, generateSwitch(2)));
+ perf.push(new PointEvent(93, generateSwitch(5)));
+ perf.push(new PointEvent(132, generateSwitch(2)));
+ perf.push(new PointEvent(160, generateSwitch(0)));
+ perf.push(new PointEvent(182.5, generateSwitch(2)));
+ perf.fresh();
+ demoPerfs["AGDEMO3"] = perf;
+};
+{
+ // Kimi ga Iru dake de
+ let perf = new TimedEvents();
+ perf.push(new PointEvent(12, generateSwitch(3)));
+ perf.fresh();
+ demoPerfs["01KIMIGA"] = perf;
+};
+{
+ // Do-Re-Mi
+ let perf = new TimedEvents();
+ perf.push(new PointEvent(15, generateSwitch(0)));
+ perf.push(new PointEvent(22, generateSwitch(1)));
+ perf.push(new PointEvent(30.5, generateSwitch(3)));
+ perf.push(new PointEvent(32.5, generateSwitch(2)));
+ perf.push(new PointEvent(38, generateSwitch(1)));
+ perf.push(new PointEvent(40, generateSwitch(3)));
+ perf.push(new PointEvent(42, generateSwitch(0)));
+ perf.push(new PointEvent(46, generateSwitch(7)));
+ perf.push(new PointEvent(47.8, generateSwitch(4)));
+ perf.push(new PointEvent(62.5, generateSwitch(11)));
+ perf.push(new PointEvent(77.5, generateSwitch(2)));
+ perf.push(new PointEvent(90, generateSwitch(11)));
+ perf.push(new PointEvent(104, generateSwitch(0)));
+ perf.push(new PointEvent(107.5, generateSwitch(1)));
+ perf.push(new PointEvent(121, generateSwitch(6)));
+ perf.push(new PointEvent(128, generateSwitch(1)));
+ perf.push(new PointEvent(141, generateSwitch(5)));
+ perf.push(new PointEvent(154.5, generateSwitch(12)));
+ perf.push(new PointEvent(168, generateSwitch(11)));
+ perf.push(new PointEvent(188, generateSwitch(3)));
+ perf.push(new PointEvent(210.5, generateSwitch(12)));
+ perf.push(new PointEvent(224, generateSwitch(11)));
+ perf.push(new PointEvent(237, generateSwitch(1)));
+ perf.push(new PointEvent(244, generateSwitch(5)));
+ perf.push(new PointEvent(253.5, generateSwitch(12)));
+ perf.fresh();
+ demoPerfs["10DOREMI"] = perf;
+};
+{
+ // Haru yo Koi
+ let perf = new TimedEvents();
+ perf.push(new PointEvent(5, generateSwitch(3)));
+ perf.push(new PointEvent(27.5, generateSwitch(0)));
+ perf.fresh();
+ demoPerfs["haruyoko"] = perf;
+};
+{
+ // PhoenixA
+ let perf = new TimedEvents();
+ perf.push(new PointEvent(0, generateString(` YAMAHA TONE GENERATOR `)));
+ perf.push(new PointEvent(0, generateSwitch(0)));
+ perf.push(new PointEvent(2.52, generateString(` YAMAHA TONE GENERATOR `)));
+ perf.push(new PointEvent(5.04, generateString(` YAMAHA TONE GENERATOR`)));
+ perf.push(new PointEvent(5.21, generateString(` YAMAHA TONE GENERATO`)));
+ perf.push(new PointEvent(5.37, generateString(` YAMAHA TONE GENERAT`)));
+ perf.push(new PointEvent(5.54, generateString(` YAMAHA TONE GENERA`)));
+ perf.push(new PointEvent(5.71, generateString(` YAMAHA TONE GENER`)));
+ perf.push(new PointEvent(5.87, generateString(` YAMAH TONE GENE`)));
+ perf.push(new PointEvent(6.04, generateString(` YAMA TONE GEN`)));
+ perf.push(new PointEvent(6.21, generateString(` YAM TONE GE`)));
+ perf.push(new PointEvent(6.38, generateString(` YA TONE G`)));
+ perf.push(new PointEvent(6.54, generateString(` Y TONE `)));
+ perf.push(new PointEvent(6.71, generateString(` TONE`)));
+ perf.push(new PointEvent(6.88, generateString(` TON`)));
+ perf.push(new PointEvent(7.04, generateString(` TO`)));
+ perf.push(new PointEvent(7.21, generateString(` T`)));
+ perf.push(new PointEvent(7.38, generateString(` `)));
+ perf.push(new PointEvent(7.52, generateString(` MU1000 `)));
+ perf.push(new PointEvent(8.14, generateString(` `)));
+ perf.push(new PointEvent(8.76, generateString(` MU1000 `)));
+ perf.push(new PointEvent(9.38, generateString(` `)));
+ perf.push(new PointEvent(10.08, generateString(` MU1000 `)));
+ perf.push(new PointEvent(10.49, generateString(` DU1000 `)));
+ perf.push(new PointEvent(10.92, generateString(` Db1000 0 `)));
+ perf.push(new PointEvent(11.33, generateString(` Dbl000 06 `)));
+ perf.push(new PointEvent(11.75, generateString(` DblC00 066 `)));
+ perf.push(new PointEvent(12.17, generateString(` DblCo0 066 `)));
+ perf.push(new PointEvent(12.59, generateString(` DblCon 066 0 `)));
+ perf.push(new PointEvent(13.01, generateString(` DblConG 066 00 `)));
+ perf.push(new PointEvent(13.42, generateString(` DblConGr 066 001`)));
+ perf.push(new PointEvent(27.98, generateSwitch(4)));
+ perf.push(new PointEvent(43.85, generateSwitch(10)));
+ perf.push(new PointEvent(63.33, generateSwitch(19)));
+ perf.push(new PointEvent(103.31, generateSwitch(34)));
+ perf.push(new PointEvent(109.52, generateSwitch(35)));
+ perf.push(new PointEvent(114.32, generateSwitch(32)));
+ perf.push(new PointEvent(119.36, generateSwitch(33)));
+ perf.push(new PointEvent(123.68, generateSwitch(36)));
+ perf.push(new PointEvent(128.91, generateSwitch(41)));
+ perf.push(new PointEvent(140.83, generateSwitch(45)));
+ perf.push(new PointEvent(153.29, generateSwitch(42)));
+ perf.push(new PointEvent(176.74, generateSwitch(2)));
+ perf.push(new PointEvent(178.27, generateString(` WindChim. SFX 070`)));
+ perf.push(new PointEvent(178.92, generateString(` WindChim . SFX 070`)));
+ perf.push(new PointEvent(179.56, generateString(` WindChim . SFX 070`)));
+ perf.push(new PointEvent(180.21, generateString(` WindChim . SFX 070`)));
+ perf.push(new PointEvent(180.85, generateString(` WindChim . SFX 070`)));
+ perf.push(new PointEvent(181.5, generateString(` WindChim . SFX 070`)));
+ perf.push(new PointEvent(182.14, generateString(` WindChim . SFX 070`)));
+ perf.push(new PointEvent(182.79, generateString(` WindChim . SFX 070`)));
+ perf.push(new PointEvent(183.43, generateString(` WindChim .SFX 070`)));
+ perf.push(new PointEvent(184.08, generateString(` BindChim .FX 070`)));
+ perf.push(new PointEvent(184.72, generateString(` BrndChim 0.X 070`)));
+ perf.push(new PointEvent(185.36, generateString(` BrtdChim 06. 070`)));
+ perf.push(new PointEvent(186.01, generateString(` BrtFChim 066.070`)));
+ perf.push(new PointEvent(186.66, generateString(` BrtFrhim 066 .70`)));
+ perf.push(new PointEvent(187.3, generateString(` BrtFrHim 066 0.0`)));
+ perf.push(new PointEvent(187.89, generateString(` BrtFrHrm 066 06.`)));
+ perf.push(new PointEvent(187.95, generateString(` BrtFrHrn 066 061`)));
+ perf.fresh();
+ demoPerfs["PhoenixA"] = perf;
+};
+{
+ // PhoenixB
+ let perf = new TimedEvents();
+ perf.push(new PointEvent(0, generateString(` BrtFrHrn 066 061`)));
+ perf.push(new PointEvent(0, generateSwitch(11)));
+ perf.push(new PointEvent(2.02, {type: 15, track: 0, data: [67, 16, 76, 6, 0, 64]}));
+ perf.push(new PointEvent(38.19, generateSwitch(9)));
+ perf.push(new PointEvent(40.05, generateSwitch(16)));
+ perf.push(new PointEvent(40.67, generateSwitch(34)));
+ perf.push(new PointEvent(44.61, generateSwitch(17)));
+ perf.push(new PointEvent(47.59, generateSwitch(32)));
+ perf.push(new PointEvent(53.64, generateSwitch(18)));
+ perf.push(new PointEvent(54.89, generateSwitch(32)));
+ perf.push(new PointEvent(56.01, generateSwitch(49)));
+ perf.push(new PointEvent(58.47, generateSwitch(9)));
+ perf.push(new PointEvent(61.79, generateSwitch(0)));
+ perf.push(new PointEvent(71.54, generateSwitch(1)));
+ perf.push(new PointEvent(78.46, generateSwitch(16)));
+ perf.push(new PointEvent(80.33, generateSwitch(0)));
+ perf.push(new PointEvent(83.43, generateSwitch(0)));
+ perf.push(new PointEvent(84.86, generateSwitch(0)));
+ perf.push(new PointEvent(87.83, generateSwitch(0)));
+ perf.push(new PointEvent(89.29, generateSwitch(1)));
+ perf.push(new PointEvent(93.61, generateSwitch(1)));
+ perf.push(new PointEvent(98.21, generateSwitch(16)));
+ perf.push(new PointEvent(102.93, generateSwitch(17)));
+ perf.push(new PointEvent(107.45, generateSwitch(16)));
+ perf.push(new PointEvent(107.78, generateSwitch(17)));
+ perf.push(new PointEvent(110.97, generateSwitch(32)));
+ perf.push(new PointEvent(111.98, generateSwitch(16)));
+ perf.push(new PointEvent(113.27, generateSwitch(34)));
+ perf.push(new PointEvent(114.18, generateSwitch(16)));
+ perf.push(new PointEvent(115.75, generateSwitch(17)));
+ perf.push(new PointEvent(123.01, generateSwitch(5)));
+ perf.push(new PointEvent(124.53, generateSwitch(7)));
+ perf.push(new PointEvent(126.06, generateSwitch(20)));
+ perf.push(new PointEvent(126.78, generateSwitch(32)));
+ perf.fresh();
+ demoPerfs["PhoenixB"] = perf;
+};
+{
+ // Ninety Hipty
+ let perf = new TimedEvents();
+ perf.push(new PointEvent(0.5, generateSwitch(1)));
+ perf.push(new PointEvent(19.7, generateSwitch(11)));
+ perf.push(new PointEvent(28.5, generateSwitch(12)));
+ perf.push(new PointEvent(37.4, generateSwitch(4)));
+ perf.push(new PointEvent(45.8, generateSwitch(2)));
+ perf.push(new PointEvent(50.6, generateSwitch(3)));
+ perf.push(new PointEvent(54.9, generateSwitch(4)));
+ perf.push(new PointEvent(74.4, generateSwitch(0)));
+ perf.push(new PointEvent(76.85, generateSwitch(9)));
+ perf.push(new PointEvent(81.75, generateSwitch(10)));
+ perf.push(new PointEvent(86.6, generateSwitch(25)));
+ perf.push(new PointEvent(96.7, generateSwitch(13)));
+ perf.push(new PointEvent(106.2, generateSwitch(22)));
+ perf.push(new PointEvent(111.25, generateSwitch(23)));
+ perf.push(new PointEvent(116.1, generateSwitch(17)));
+ perf.push(new PointEvent(121, generateSwitch(13)));
+ perf.push(new PointEvent(127.9, generateSwitch(8)));
+ perf.push(new PointEvent(138, generateSwitch(0)));
+ perf.fresh();
+ demoPerfs["ninety_hipty"] = perf;
+};
+{
+ // The PF Theatre
+ let perf = new TimedEvents();
+ perf.push(new PointEvent(0, generateSwitch(0)));
+ perf.fresh();
+ demoPerfs["02THEATR"] = perf;
+};
+{
+ // Is it realy love?
+ let perf = new TimedEvents();
+ perf.push(new PointEvent(1.8, generateSwitch(24)));
+ perf.push(new PointEvent(7.6, generateSwitch(29)));
+ perf.push(new PointEvent(10.53, generateSwitch(0)));
+ perf.push(new PointEvent(20.9, generateSwitch(22)));
+ perf.push(new PointEvent(28.47, generateSwitch(23)));
+ perf.push(new PointEvent(31.1, generateSwitch(3)));
+ perf.push(new PointEvent(38.88, generateSwitch(17)));
+ perf.push(new PointEvent(41.02, generateSwitch(5)));
+ perf.push(new PointEvent(48.59, generateSwitch(17)));
+ perf.push(new PointEvent(50.9, generateSwitch(0)));
+ perf.push(new PointEvent(70.7, generateSwitch(1)));
+ perf.push(new PointEvent(78.2, generateSwitch(17)));
+ perf.push(new PointEvent(80.79, generateSwitch(2)));
+ perf.push(new PointEvent(88.65, generateSwitch(1)));
+ perf.push(new PointEvent(90.02, generateSwitch(2)));
+ perf.push(new PointEvent(91.11, generateSwitch(1)));
+ perf.push(new PointEvent(92.43, generateSwitch(2)));
+ perf.push(new PointEvent(93.18, generateSwitch(0)));
+ perf.push(new PointEvent(112.9, generateSwitch(1)));
+ perf.push(new PointEvent(119, generateSwitch(17)));
+ perf.push(new PointEvent(122.64, generateSwitch(2)));
+ perf.push(new PointEvent(130.12, generateSwitch(15)));
+ perf.push(new PointEvent(132.73, generateSwitch(0)));
+ perf.push(new PointEvent(152.54, generateSwitch(1)));
+ perf.push(new PointEvent(158.66, generateSwitch(17)));
+ perf.push(new PointEvent(162.39, generateSwitch(2)));
+ perf.push(new PointEvent(166.24, generateSwitch(14)));
+ perf.push(new PointEvent(172.26, generateSwitch(8)));
+ perf.push(new PointEvent(182.23, generateSwitch(8)));
+ perf.push(new PointEvent(191.81, generateSwitch(23)));
+ perf.push(new PointEvent(193, generateSwitch(0)));
+ perf.fresh();
+ demoPerfs["R-love"] = perf;
+};
+{
+ // The Musithm
+ let perf = new TimedEvents();
+ perf.push(new PointEvent(2.5, generateSwitch(14)));
+ perf.push(new PointEvent(3.5, generateSwitch(3)));
+ perf.push(new PointEvent(30.5, generateSwitch(4)));
+ perf.push(new PointEvent(37.5, generateSwitch(3)));
+ perf.push(new PointEvent(78, generateSwitch(15)));
+ perf.fresh();
+ demoPerfs["TheMusithm"] = perf;
+};
+{
+ // EP Ballade
+ let perf = new TimedEvents();
+ perf.push(new PointEvent(0, generateSwitch(1)));
+ perf.push(new PointEvent(5, generateSwitch(0)));
+ perf.fresh();
+ demoPerfs["12EP"] = perf;
+};
+{
+ // The Soul of DX
+ let perf = new TimedEvents();
+ perf.push(new PointEvent(0, generateSwitch(0)));
+ perf.push(new PointEvent(34, generateSwitch(13)));
+ perf.push(new PointEvent(62.5, generateSwitch(0)));
+ perf.push(new PointEvent(164, generateSwitch(13)));
+ perf.fresh();
+ demoPerfs["12SOULDX"] = perf;
+};
+{
+ // MU128 demo
+ let perf = new TimedEvents();
+ // Disable native RS
+ perf.push(new PointEvent(0, {type: 15, track: 0, data: [67, 16, 73, 0, 0, 14, 0]}));
+ perf.push(new PointEvent(0, generateSwitch(0)));
+ perf.push(new PointEvent(1.6, generateSwitch(0)));
+ perf.push(new PointEvent(40.02, generateSwitch(48)));
+ perf.push(new PointEvent(41.68, generateSwitch(49)));
+ perf.push(new PointEvent(43.07, generateSwitch(50)));
+ perf.push(new PointEvent(44.65, generateSwitch(51)));
+ perf.push(new PointEvent(46.2, generateSwitch(52)));
+ perf.push(new PointEvent(47.74, generateSwitch(53)));
+ perf.push(new PointEvent(49.29, generateSwitch(54)));
+ perf.push(new PointEvent(50.83, generateSwitch(55)));
+ perf.push(new PointEvent(52.38, generateSwitch(56)));
+ perf.push(new PointEvent(53.92, generateSwitch(58)));
+ perf.push(new PointEvent(55.47, generateSwitch(59)));
+ perf.push(new PointEvent(57.02, generateSwitch(48)));
+ perf.push(new PointEvent(69.56, generateSwitch(8)));
+ perf.push(new PointEvent(70.54, generateSwitch(9)));
+ perf.push(new PointEvent(71.52, generateSwitch(10)));
+ perf.push(new PointEvent(72.5, generateSwitch(11)));
+ perf.push(new PointEvent(73.48, generateSwitch(12)));
+ perf.push(new PointEvent(74.46, generateSwitch(13)));
+ perf.push(new PointEvent(75.44, generateSwitch(14)));
+ perf.push(new PointEvent(76.42, generateSwitch(15)));
+ perf.push(new PointEvent(77.4, generateSwitch(8)));
+ perf.push(new PointEvent(81.18, generateSwitch(0)));
+ perf.push(new PointEvent(82.15, generateSwitch(1)));
+ perf.push(new PointEvent(83.12, generateSwitch(2)));
+ perf.push(new PointEvent(84.09, generateSwitch(3)));
+ perf.push(new PointEvent(85.06, generateSwitch(4)));
+ perf.push(new PointEvent(86.03, generateSwitch(5)));
+ perf.push(new PointEvent(87.0, generateSwitch(6)));
+ perf.push(new PointEvent(87.97, generateSwitch(7)));
+ perf.push(new PointEvent(88.94, generateSwitch(0)));
+ perf.push(new PointEvent(96.66, generateSwitch(16)));
+ perf.push(new PointEvent(98.15, generateSwitch(17)));
+ perf.push(new PointEvent(99.63, generateSwitch(18)));
+ perf.push(new PointEvent(101.12, generateSwitch(19)));
+ perf.push(new PointEvent(102.6, generateSwitch(20)));
+ perf.push(new PointEvent(104.09, generateSwitch(21)));
+ perf.push(new PointEvent(105.57, generateSwitch(22)));
+ perf.push(new PointEvent(107.06, generateSwitch(23)));
+ perf.push(new PointEvent(108.54, generateSwitch(24)));
+ perf.push(new PointEvent(110.03, generateSwitch(25)));
+ perf.push(new PointEvent(111.51, generateSwitch(26)));
+ perf.push(new PointEvent(112.99, generateSwitch(27)));
+ perf.push(new PointEvent(114.48, generateSwitch(28)));
+ perf.push(new PointEvent(115.97, generateSwitch(29)));
+ perf.push(new PointEvent(117.45, generateSwitch(30)));
+ perf.push(new PointEvent(118.94, generateSwitch(31)));
+ perf.push(new PointEvent(120.42, generateSwitch(16)));
+ perf.push(new PointEvent(122.34, generateSwitch(5)));
+ perf.push(new PointEvent(158.26, generateSwitch(0)));
+ perf.fresh();
+ demoPerfs["MU128DEMO"] = perf;
+};
diff --git a/src/fakeQy/index.js b/src/fakeQy/index.js
new file mode 100644
index 00000000..53602dd0
--- /dev/null
+++ b/src/fakeQy/index.js
@@ -0,0 +1,260 @@
+"use strict";
+
+import {} from "../../libs/lightfelt@ltgcgo/main/cssClass.js";
+import {$e, $a} from "../../libs/lightfelt@ltgcgo/main/quickPath.js";
+import QyDisplay from "../disp/disp_qy.mjs";
+import {fileOpen} from "../../libs/browser-fs-access@GoogleChromeLabs/browser_fs_access.min.js";
+import {
+ getBridge
+} from "../bridge/index.mjs";
+import {SheetData} from "../basic/sheetLoad.js";
+
+let demoBlobs = {};
+let demoModes = [];
+demoModes[9] = "gm";
+let useMidiBus = false;
+let demoId = 0;
+
+// Standard switching
+let stSwitch = $a("b.mode");
+let stSwitchMode = [];
+stSwitch.to = function (i) {
+ stSwitch.forEach(function (e) {
+ e.classList.off("active");
+ });
+ if (i > -1) {
+ stSwitch[i].classList.on("active");
+ };
+};
+stSwitch.forEach(function (e, i, a) {
+ stSwitchMode[i] = e.title;
+ e.addEventListener("click", function () {
+ visualizer.switchMode(e.title, true);
+ stSwitch.to(i);
+ });
+});
+
+// Standard demo switching
+let demoPool = new SheetData();
+let stList = $e("span#demo-list"), stDemo = [];
+const srcPaths = ['../../midi-demo-data/collection/octavia/', './demo/'];
+let getBlobFrom = async function (filename) {
+ let i = 0;
+ while (i < srcPaths.length) {
+ let e = srcPaths[i];
+ let response = await fetch(`${e}${filename}`);
+ if (response.status < 400) {
+ return response;
+ };
+ i ++;
+ };
+ console.error(`Loading of data ${filename} failed.`);
+};
+let codepointArray = function (string) {
+ let arr = new Uint16Array(string.length);
+ arr.forEach((e, i, a) => {
+ a[i] = string.charCodeAt(i);
+ });
+ return arr;
+};
+getBlobFrom(`list.tsv`).then(async (response) => {
+ await demoPool.load(await response.text());
+ //console.info(demoPool.data);
+ demoPool.data.forEach((e, i) => {
+ if (i) {
+ let space = document.createElement("span");
+ space.innerHTML = " ";
+ stList.appendChild(space);
+ } else {
+ stList.innerText = "";
+ };
+ let demoChoice = document.createElement("b");
+ demoChoice.innerText = e.text;
+ demoChoice.title = e.file;
+ demoChoice.classList.on("demo");
+ stDemo.push(demoChoice);
+ stList.appendChild(demoChoice);
+ });
+ stDemo.to = function (i) {
+ stDemo.forEach(function (e) {
+ e.classList.off("active");
+ });
+ if (i > -1) {
+ stDemo[i].classList.on("active");
+ };
+ };
+ stDemo.forEach(function (e, i, a) {
+ e.addEventListener("click", async function () {
+ audioPlayer.pause();
+ if (!demoBlobs[e.title]?.midi) {
+ demoBlobs[e.title] = {};
+ audioPlayer.src = "about:blank";
+ demoBlobs[e.title].midi = await (await getBlobFrom(`${e.title}.mid`)).blob();
+ demoBlobs[e.title].wave = await (await getBlobFrom(`${e.title}.opus`)).blob();
+ };
+ audioPlayer.currentTime = 0;
+ visualizer.reset();
+ visualizer.loadFile(demoBlobs[e.title].midi);
+ if (audioBlob) {
+ URL.revokeObjectURL(audioBlob);
+ };
+ audioBlob = demoBlobs[e.title].wave;
+ audioPlayer.src = URL.createObjectURL(audioBlob);
+ if (demoModes[i]?.length > 0) {
+ visualizer.switchMode(demoModes[i]);
+ };
+ stDemo.to(i);
+ demoId = i;
+ visualizer.device.setLetterDisplay(codepointArray(`\x8a${demoPool.data[i].artist.slice(0, 15).padEnd(15, " ")}\x8b${demoPool.data[i].title.slice(0, 15)}`));
+ });
+ });
+});
+
+// Start the visualizers
+self.visualizer = new QyDisplay();
+visualizer.addEventListener("reset", function (e) {
+ visualizer.songTitle = "";
+ console.info("Processor reset.");
+});
+
+// Listen to mode switches
+visualizer.addEventListener("mode", function (ev) {
+ stSwitch.to(stSwitchMode.indexOf(ev.data));
+});
+
+// Open the files
+let midwIndicator = $e("#openMidw");
+let audioBlob;
+const propsMid = JSON.parse('{"extensions":[".mid",".MID",".kar",".KAR",".syx",".SYX",".s7e",".S7E"],"startIn":"music","id":"midiOpener","description":"Open a MIDI file"}'),
+propsAud = JSON.parse('{"mimeTypes":["audio/*"],"startIn":"music","id":"audioOpener","description":"Open an audio file"}');
+$e("#openMidi").addEventListener("click", async function () {
+ useMidiBus = false;
+ midwIndicator.classList.off("active");
+ let file = await fileOpen(propsMid);
+ let fileSplit = file.name.lastIndexOf("."), ext = "";
+ if (fileSplit > -1) {
+ ext = file.name.slice(fileSplit + 1).toLowerCase();
+ };
+ switch (ext) {
+ case "syx": {
+ // Load SysEx blobs
+ visualizer.sendCmd({type: 15, track: 0, data: new Uint8Array(await file.arrayBuffer())});
+ break;
+ };
+ case "s7e": {
+ // Load sound banks
+ visualizer.device.loadBank(ext, file);
+ break;
+ };
+ default: {
+ // Load MIDI files
+ stDemo.to(-1);
+ visualizer.reset();
+ visualizer.loadFile(file);
+ visualizer.device.initOnReset = false;
+ };
+ };
+});
+$e("#openAudio").addEventListener("click", async function () {
+ useMidiBus = false;
+ midwIndicator.classList.off("active");
+ if (audioBlob) {
+ URL.revokeObjectURL(audioBlob);
+ };
+ audioBlob = await fileOpen(propsAud);
+ audioPlayer.src = URL.createObjectURL(audioBlob);
+});
+midwIndicator.addEventListener("click", function () {
+ stDemo.to(-1);
+ if (audioBlob) {
+ URL.revokeObjectURL(audioBlob);
+ };
+ audioBlob = null;
+ audioPlayer.src = "";
+ visualizer.reset();
+ useMidiBus = true;
+ midwIndicator.classList.on("active");
+});
+
+visualizer.addEventListener("meta", function (ev) {
+ if (!visualizer.songTitle) {
+ ev.data.forEach(function (e) {
+ if (!visualizer.songTitle && e.meta == 3) {
+ visualizer.songTitle = e.data;
+ };
+ });
+ };
+});
+
+// Get canvas
+let dispCanv = $e("#qyScreen");
+let dispCtx = dispCanv.getContext("2d");
+let mixerView = false;
+dispCanv.addEventListener("wheel", function (ev) {
+ ev.preventDefault();
+ let ch = visualizer.getCh();
+ if (ev.deltaY > 0) {
+ visualizer.setCh(ch + 1);
+ } else {
+ visualizer.setCh(ch - 1);
+ };
+ ev.preventDefault();
+ ev.stopImmediatePropagation();
+});
+/* dispCanv.addEventListener("contextmenu", function (ev) {
+ ev.preventDefault();
+ ev.stopImmediatePropagation();
+}); */
+dispCanv.addEventListener("mousedown", function (ev) {
+ let ch = visualizer.getCh();
+ if (ev.button == 0) {
+ if (ev.offsetX < 64) {
+ visualizer.setCh(ch - 1);
+ } else if (ev.offsetX >= 717) {
+ visualizer.setCh(ch + 1);
+ } else if (ev.offsetY < 72) {
+ mixerView = !mixerView;
+ };
+ };
+});
+
+// Allow channel switching in browser console
+self.toCh = function (ch) {
+ visualizer.setCh(ch);
+};
+
+// Render frames
+let audioPlayer = $e("#audioPlayer");
+audioPlayer.onended = function () {
+ visualizer.reset();
+ audioPlayer.currentTime = 0;
+};
+(async function () {
+ visualizer.reset();
+ let midiBlob = await (await fetch("./demo/KANDI8.mid")).blob();
+ demoBlobs.KANDI8 = {};
+ demoBlobs.KANDI8.midi = midiBlob;
+ visualizer.loadFile(midiBlob);
+ if (audioBlob) {
+ URL.revokeObjectURL(audioBlob);
+ };
+ audioBlob = await (await fetch("./demo/KANDI8.opus")).blob();
+ demoBlobs.KANDI8.wave = audioBlob;
+ audioPlayer.src = URL.createObjectURL(audioBlob);
+})();
+let lastTime = 0;
+let renderThread = setInterval(function () {
+ if (/*!audioPlayer.paused*/true) {
+ let curTime = audioPlayer.currentTime - (self.audioDelay || 0);
+ if (curTime < lastTime) {
+ };
+ visualizer.render(curTime, dispCtx, mixerView, useMidiBus ? 0 : demoId);
+ lastTime = curTime;
+ };
+}, 20);
+
+getBridge().addEventListener("message", function (ev) {
+ if (useMidiBus) {
+ visualizer.sendCmd(ev.data);
+ };
+});
diff --git a/src/fakeSc/index.js b/src/fakeSc/index.js
new file mode 100644
index 00000000..a1ca59ea
--- /dev/null
+++ b/src/fakeSc/index.js
@@ -0,0 +1,258 @@
+"use strict";
+
+import {} from "../../libs/lightfelt@ltgcgo/main/cssClass.js";
+import {$e, $a} from "../../libs/lightfelt@ltgcgo/main/quickPath.js";
+import ScDisplay from "../disp/disp_sc.mjs";
+import {fileOpen} from "../../libs/browser-fs-access@GoogleChromeLabs/browser_fs_access.min.js";
+import {
+ getBridge
+} from "../bridge/index.mjs";
+import {SheetData} from "../basic/sheetLoad.js";
+
+let demoBlobs = {};
+let demoModes = [];
+demoModes[9] = "gm";
+let useMidiBus = false;
+
+// Standard switching
+let stSwitch = $a("b.mode");
+let stSwitchMode = [];
+stSwitch.to = function (i) {
+ stSwitch.forEach(function (e) {
+ e.classList.off("active");
+ });
+ if (i > -1) {
+ stSwitch[i].classList.on("active");
+ };
+};
+stSwitch.forEach(function (e, i, a) {
+ stSwitchMode[i] = e.title;
+ e.addEventListener("click", function () {
+ visualizer.switchMode(e.title, true);
+ stSwitch.to(i);
+ });
+});
+
+// Standard demo switching
+
+let demoPool = new SheetData();
+let stList = $e("span#demo-list"), stDemo = [];
+const srcPaths = ['../../midi-demo-data/collection/octavia/', './demo/'];
+let getBlobFrom = async function (filename) {
+ let i = 0;
+ while (i < srcPaths.length) {
+ let e = srcPaths[i];
+ let response = await fetch(`${e}${filename}`);
+ if (response.status < 400) {
+ return response;
+ };
+ i ++;
+ };
+ console.error(`Loading of data ${filename} failed.`);
+};
+getBlobFrom(`list.tsv`).then(async (response) => {
+ await demoPool.load(await response.text());
+ //console.info(demoPool.data);
+ demoPool.data.forEach((e, i) => {
+ if (i) {
+ let space = document.createElement("span");
+ space.innerHTML = " ";
+ stList.appendChild(space);
+ } else {
+ stList.innerText = "";
+ };
+ let demoChoice = document.createElement("b");
+ demoChoice.innerText = e.text;
+ demoChoice.title = e.file;
+ demoChoice.classList.on("demo");
+ stDemo.push(demoChoice);
+ stList.appendChild(demoChoice);
+ });
+ stDemo.to = function (i) {
+ stDemo.forEach(function (e) {
+ e.classList.off("active");
+ });
+ if (i > -1) {
+ stDemo[i].classList.on("active");
+ };
+ };
+ stDemo.forEach(function (e, i, a) {
+ e.addEventListener("click", async function () {
+ audioPlayer.pause();
+ let demoId = e.innerText.charCodeAt(0);
+ if (demoId <= 122 && demoId > 96) {
+ demoId -= 32;
+ };
+ visualizer.device.setLetterDisplay([76, 111, 97, 100, 105, 110, 103, 32, 100, 101, 109, 111, 32, demoId]);
+ if (!demoBlobs[e.title]?.midi) {
+ demoBlobs[e.title] = {};
+ audioPlayer.src = "about:blank";
+ demoBlobs[e.title].midi = await (await getBlobFrom(`${e.title}.mid`)).blob();
+ demoBlobs[e.title].wave = await (await getBlobFrom(`${e.title}.opus`)).blob();
+ };
+ audioPlayer.currentTime = 0;
+ visualizer.reset();
+ visualizer.loadFile(demoBlobs[e.title].midi);
+ if (audioBlob) {
+ URL.revokeObjectURL(audioBlob);
+ };
+ audioBlob = demoBlobs[e.title].wave;
+ audioPlayer.src = URL.createObjectURL(audioBlob);
+ if (demoModes[i]?.length > 0) {
+ visualizer.switchMode(demoModes[i]);
+ };
+ visualizer.device.setLetterDisplay([76, 111, 97, 100, 101, 100, 32, 100, 101, 109, 111, 32, demoId]);
+ stDemo.to(i);
+ });
+ });
+});
+
+let title = "";
+// Start the visualizers
+self.visualizer = new ScDisplay();
+visualizer.addEventListener("reset", function (e) {
+ console.info("Processor reset.");
+ title = "";
+});
+
+// Listen to mode switches
+visualizer.addEventListener("mode", function (ev) {
+ stSwitch.to(stSwitchMode.indexOf(ev.data));
+ let textArr = Array.from(`Sys:${{"g2":"GM2","mt32":"MT-32","ag10":"AG-10","05rw":"05R/W","k11":"GMega","krs":"KROSS 2","s90es":"S90 ES","motif":"Motif ES"}[ev.data]||ev.data.toUpperCase()}`);
+ textArr.forEach((e, i, a) => {
+ a[i] = e.charCodeAt(0);
+ });
+ visualizer.device.setLetterDisplay(textArr);
+});
+visualizer.addEventListener("meta", function (ev) {
+ if (!title) {
+ ev.data.forEach(function (e) {
+ if (!title && e.meta == 3) {
+ title = e.data;
+ };
+ });
+ if (title) {
+ let textCmd = [];
+ Array.from(title).forEach(function (e) {
+ let charCode = e.charCodeAt(0);
+ if (charCode < 128) {
+ textCmd.push(charCode);
+ };
+ });
+ visualizer.device.setLetterDisplay(textCmd);
+ };
+ };
+});
+
+// Open the files
+let midwIndicator = $e("#openMidw");
+let audioBlob;
+const propsMid = JSON.parse('{"extensions":[".mid",".MID",".kar",".KAR",".syx",".SYX",".s7e",".S7E"],"startIn":"music","id":"midiOpener","description":"Open a MIDI file"}'),
+propsAud = JSON.parse('{"mimeTypes":["audio/*"],"startIn":"music","id":"audioOpener","description":"Open an audio file"}');
+$e("#openMidi").addEventListener("click", async function () {
+ useMidiBus = false;
+ midwIndicator.classList.off("active");
+ let file = await fileOpen(propsMid);
+ let fileSplit = file.name.lastIndexOf("."), ext = "";
+ if (fileSplit > -1) {
+ ext = file.name.slice(fileSplit + 1).toLowerCase();
+ };
+ switch (ext) {
+ case "syx": {
+ // Load SysEx blobs
+ visualizer.sendCmd({type: 15, track: 0, data: new Uint8Array(await file.arrayBuffer())});
+ break;
+ };
+ case "s7e": {
+ // Load sound banks
+ visualizer.device.loadBank(ext, file);
+ break;
+ };
+ default: {
+ // Load MIDI files
+ stDemo.to(-1);
+ visualizer.reset();
+ visualizer.loadFile(file);
+ visualizer.device.initOnReset = false;
+ };
+ };
+});
+$e("#openAudio").addEventListener("click", async function () {
+ useMidiBus = false;
+ midwIndicator.classList.off("active");
+ if (audioBlob) {
+ URL.revokeObjectURL(audioBlob);
+ };
+ visualizer.sendCmd({type: 15, track: 0, data: [67, 16, 76, 6, 0, 0, 76, 111, 97, 100, 105, 110, 103, 32, 97, 117, 100, 105, 111, 32, 102, 105, 108, 101]});
+ audioBlob = await fileOpen(propsAud);
+ audioPlayer.src = URL.createObjectURL(audioBlob);
+ visualizer.sendCmd({type: 15, track: 0, data: [67, 16, 76, 6, 0, 0, 65, 117, 100, 105, 111, 32, 108, 111, 97, 100, 101, 100]});
+});
+midwIndicator.addEventListener("click", function () {
+ stDemo.to(-1);
+ if (audioBlob) {
+ URL.revokeObjectURL(audioBlob);
+ };
+ audioBlob = null;
+ audioPlayer.src = "";
+ visualizer.reset();
+ useMidiBus = true;
+ midwIndicator.classList.on("active");
+});
+
+// Get canvas
+let dispCanv = $e("#rlndSc");
+let dispCtx = dispCanv.getContext("2d");
+dispCanv.addEventListener("wheel", function (ev) {
+ ev.preventDefault();
+ let ch = visualizer.getCh();
+ if (ev.deltaY > 0) {
+ visualizer.setCh(ch + 1);
+ } else {
+ visualizer.setCh(ch - 1);
+ };
+});
+dispCanv.addEventListener("mousedown", function (ev) {
+ let ch = visualizer.getCh();
+ if (ev.offsetX < 64) {
+ visualizer.setCh(ch - 1);
+ } else if (ev.offsetX >= 776) {
+ visualizer.setCh(ch + 1);
+ };
+});
+
+// Render frames
+let audioPlayer = $e("#audioPlayer");
+audioPlayer.onended = function () {
+ visualizer.reset();
+ audioPlayer.currentTime = 0;
+};
+(async function () {
+ visualizer.reset();
+ let midiBlob = await (await fetch("./demo/KANDI8.mid")).blob();
+ demoBlobs.KANDI8 = {};
+ demoBlobs.KANDI8.midi = midiBlob;
+ visualizer.loadFile(midiBlob);
+ if (audioBlob) {
+ URL.revokeObjectURL(audioBlob);
+ };
+ audioBlob = await (await fetch("./demo/KANDI8.opus")).blob();
+ demoBlobs.KANDI8.wave = audioBlob;
+ audioPlayer.src = URL.createObjectURL(audioBlob);
+})();
+let lastTime = 0;
+let renderThread = setInterval(function () {
+ if (/*!audioPlayer.paused*/true) {
+ let curTime = audioPlayer.currentTime - (self.audioDelay || 0);
+ if (curTime < lastTime) {
+ };
+ visualizer.render(curTime, dispCtx);
+ lastTime = curTime;
+ };
+}, 20);
+
+getBridge().addEventListener("message", function (ev) {
+ if (useMidiBus) {
+ visualizer.sendCmd(ev.data);
+ };
+});
diff --git a/src/state/.prefix.js b/src/state/.prefix.js
new file mode 100644
index 00000000..3918c74e
--- /dev/null
+++ b/src/state/.prefix.js
@@ -0,0 +1 @@
+"use strict";
diff --git a/src/state/bankDecoder.js b/src/state/bankDecoder.js
new file mode 100644
index 00000000..8602e942
--- /dev/null
+++ b/src/state/bankDecoder.js
@@ -0,0 +1,127 @@
+"use strict";
+
+import {BlobDecoder} from "./decoders.mjs";
+
+// Utils
+let same = function (origin, arr) {
+ let same = true;
+ arr.forEach((e, i) => {
+ same = same && origin[i] == e;
+ });
+ return same;
+};
+let readInt = function (arr) {
+ let sum = 0;
+ arr.forEach((e) => {
+ sum *= 256;
+ sum += e;
+ });
+ return sum;
+};
+let utf8Dec = new TextDecoder();
+
+// Register decoders
+let bankDecoder = new BlobDecoder();
+bankDecoder.set("s7e", async function (blob) {
+ let s7eBlob = new Uint8Array(await blob.slice(0, 65536).arrayBuffer());
+ let voiceMap = "MSB LSB PRG NME";
+ // Constants
+ const nullHead = [0, 0, 0, 0];
+ const globalOffset = 32;
+ let ptr = 0, mode = 0, resume = true;
+ let sections = [], sectPtr = 0;
+ while (resume) {
+ let rwin = s7eBlob.subarray(ptr);
+ ([() => {
+ // Waiting for header read
+ if (utf8Dec.decode(rwin.subarray(0, 4)) == "YSFC") {
+ ptr += 80;
+ mode = 1;
+ } else {
+ ptr ++;
+ };
+ }, () => {
+ // Read offsets of each section
+ if (same(rwin.subarray(0, 4), nullHead)) {
+ sections.forEach((e, i, a) => {
+ let length = readInt(s7eBlob.subarray(e.start + 4, e.start + 8));
+ e.length = length;
+ });
+ mode = 2;
+ } else {
+ let type = utf8Dec.decode(rwin.subarray(0, 4)),
+ start = readInt(rwin.subarray(4, 8));
+ //console.error(`Section ${type} begins at ${start}.`);
+ sections.push({type, start});
+ ptr += 8;
+ };
+ }, () => {
+ // Read sections
+ let section = sections[sectPtr];
+ let sectWin = s7eBlob.subarray(section.start, section.start + section.length);
+ let entryLen = 32;
+ switch (section.type) {
+ case "ENVC": {
+ // Encoded Normal Voice Config
+ let entryStart = globalOffset;
+ while (entryStart < sectWin.length) {
+ let entryWin = sectWin.subarray(entryStart, entryStart + entryLen);
+ let voiceName = utf8Dec.decode(entryWin.subarray(0, 10)).trimEnd();
+ if (voiceName.slice(0, 5) == "Init ") {
+ voiceName = "";
+ };
+ if (voiceName) {
+ voiceMap += `\n063 ${(entryWin[17] + 13).toString().padStart(3, "0")} ${entryWin[19].toString().padStart(3, "0")} ${voiceName}`;
+ };
+ entryStart += entryLen;
+ };
+ break;
+ };
+ case "EDVC": {
+ // Encoded Drum Voice Config
+ let entryStart = globalOffset;
+ while (entryStart < sectWin.length) {
+ let entryWin = sectWin.subarray(entryStart, entryStart + entryLen);
+ let voiceName = utf8Dec.decode(entryWin.subarray(0, 10)).trimEnd();
+ if (voiceName.slice(0, 5) == "Init ") {
+ voiceName = "";
+ };
+ if (voiceName) {
+ voiceMap += `\n063 024 ${entryWin[19].toString().padStart(3, "0")} ${voiceName}`;
+ };
+ entryStart += entryLen;
+ };
+ break;
+ };
+ case "EPVC": {
+ // Encoded Plugin Voice Config
+ let entryLen = 32, entryStart = globalOffset;
+ while (entryStart < sectWin.length) {
+ let entryWin = sectWin.subarray(entryStart, entryStart + entryLen);
+ let voiceName = utf8Dec.decode(entryWin.subarray(0, 10)).trimEnd();
+ if (voiceName == "----------") {
+ voiceName = "";
+ };
+ if (voiceName) {
+ voiceMap += `\n063 ${(entryWin[17] + 1).toString().padStart(3, "0")} ${entryWin[19].toString().padStart(3, "0")} ${voiceName}`;
+ };
+ entryStart += entryLen;
+ };
+ break;
+ };
+ };
+ sectPtr ++;
+ if (sectPtr >= sections.length) {
+ mode = 3;
+ resume = false;
+ };
+ }][mode] || (() => {
+ resume = false;
+ }))();
+ };
+ return voiceMap;
+});
+
+export {
+ bankDecoder
+};
diff --git a/src/state/bankReader.js b/src/state/bankReader.js
new file mode 100644
index 00000000..fa68f3d1
--- /dev/null
+++ b/src/state/bankReader.js
@@ -0,0 +1,534 @@
+"use strict";
+
+import {ccToPos} from "../state/index.mjs";
+
+const sgCrit = ["MSB", "PRG", "LSB"];
+
+let halfHex = function (n) {
+ let segA = Math.floor(n / 10), segB = n % 10;
+ return `${segA.toString(16)}${segB}`;
+};
+
+let VoiceBank = class {
+ #bankInfo;
+ strictMode = false;
+ get(msb = 0, prg = 0, lsb = 0, mode) {
+ let sid = [msb, prg, lsb];
+ let bankName;
+ let args = Array.from(arguments);
+ switch (mode) {
+ case "xg": {
+ if (msb == 32) {
+ args[2] += 4; // PLG-150AP redirection
+ } else if (msb == 33 || msb == 35 || msb == 36) {
+ args[2] += 5; // PLG-150VL/DX/AN redirection
+ } else if (msb == 79) {
+ args[0] = 95; // PLG-150DR + PLG-150PC redirection
+ } else if (msb == 80) {
+ args[0] = 96; // PLG-150PF + PLG-150AP redirection
+ } else if (msb == 81) {
+ args[0] = 97; // PLG-150VL redirection
+ } else if (msb == 82) {
+ args[0] = 98; // PLG-100SG redirection
+ } else if (msb == 83) {
+ args[0] = 99; // PLG-100DX redirection
+ } else if (msb == 84) {
+ args[0] = 100; // PLG-100AN redirection
+ };
+ break;
+ };
+ case "gs": {
+ if (msb == 0 && lsb < 5) {
+ args[2] = 0;
+ } else if (msb > 125 && lsb < 5 && lsb != 2) {
+ // Temporary fix for C/M bank under SC-55 mode
+ // SC-88 do care incorrect LSB selection
+ args[2] = msb;
+ args[0] = 0;
+ };
+ break;
+ };
+ case "sg": {
+ if (msb == 8 && lsb == 0) {
+ args[2] = 5;
+ };
+ break;
+ };
+ case "s90es": {
+ if (lsb < 8) {
+ args[2] += 17;
+ } else if (lsb < 32) {
+ args[2] += 13;
+ } else {
+ args[2] = (args[2] >> 3) + 19;
+ };
+ break;
+ };
+ case "motif": {
+ if (lsb < 8) {
+ args[2] += 28;
+ } else if (lsb < 32) {
+ args[2] += 13;
+ } else {
+ args[2] = (args[2] >> 3) + 19;
+ };
+ break;
+ };
+ };
+ let ending = " ", sect = `M`, useLsb = false, baseShift = 0;
+ // Section test
+ switch (args[0]) {
+ case 0: {
+ if (args[2] == 127) {
+ sect = "MT-a";
+ } else if (args[2] == 126) {
+ sect = "MT-b";
+ } else if (args[2] == 7) {
+ sect = "GM-k"; // KAWAI GMega LX
+ } else if (args[2] == 5) {
+ sect = "SG-a"; // AKAI SG01k
+ } else if (args[2] == 4) {
+ sect = "SP-l"; // KAWAI GMega SP
+ } else if (args[2] == 0) {
+ sect = "GM-a";
+ } else if (mode == "gs" && args[2] < 5) {
+ sect = "GM-a";
+ } else {
+ sect = "y";
+ useLsb = true;
+ };
+ break;
+ };
+ case 8: {
+ if (mode == "sg") {
+ sect = "GM-s";
+ } else {
+ sect = "r:";
+ };
+ break;
+ };
+ case 48: {
+ sect = `yM${(args[2] >> 3).toString().padStart(2, "0")}`;
+ useLsb = true;
+ break;
+ };
+ case 56: {
+ sect = "GM-b";
+ break;
+ };
+ case 61:
+ case 120: {
+ sect = "rDrm";
+ break;
+ };
+ case 62: {
+ sect = "kDrm";
+ break;
+ };
+ case 63: {
+ if (args[2] < 17) {
+ let kLsb = args[2];
+ sect = (kLsb < 10) ? "kP:" : "kC:";
+ sect += kLsb % 10;
+ } else if (args[2] < 34) {
+ sect = ["Pre1", "Pre2", "Pre3", "Pre4", "Usr1", "Usr2", "DrmP", "DrmU", "Plg1", "Plg2", "Plg3", "Pre1", "Pre2", "Pre3", "Pre4", "Pre5", "Pre6"][args[2] - 17];
+ } else {
+ sect = `Ds`;
+ };
+ break;
+ };
+ case 64: {
+ sect = "ySFX";
+ break;
+ };
+ case 67: {
+ sect = "DX:S";
+ break;
+ };
+ case 80:
+ case 81:
+ case 82:
+ case 83: {
+ sect = `Prg${"UABC"[args[0] - 80]}`;
+ break;
+ };
+ case 88:
+ case 89:
+ case 90:
+ case 91: {
+ sect = `Cmb${"UABC"[args[0] - 88]}`;
+ break;
+ };
+ case 95: {
+ sect = `${["DR", "PC"][args[2]]}-d`;
+ break;
+ };
+ case 96: {
+ sect = (args[2] == 106 ? "AP-a" : "PF");
+ if (args[2] > 63) {
+ baseShift = 63;
+ };
+ useLsb = true;
+ break;
+ };
+ case 97: {
+ sect = "VL:";
+ useLsb = true;
+ baseShift = 112;
+ break;
+ };
+ case 98: {
+ sect = "SG-a";
+ break;
+ };
+ case 99: {
+ sect = `DX`;
+ if (args[2] > 63) {
+ baseShift = 63;
+ };
+ useLsb = true;
+ break;
+ };
+ case 100: {
+ sect = `AN`;
+ if (args[2] > 63) {
+ baseShift = 63;
+ };
+ useLsb = true;
+ break;
+ };
+ case 121: {
+ sect = `GM-${args[2] ? "" : "a"}`;
+ useLsb = true;
+ break;
+ };
+ case 122: {
+ sect = "lDrm";
+ break;
+ };
+ case 126: {
+ sect = "yDrS";
+ break;
+ };
+ case 127: {
+ if (args[2] == 127) {
+ sect = "rDrm";
+ } else {
+ sect = "yDrm";
+ };
+ break;
+ };
+ default: {
+ if (args[0] < 48) {
+ sect = "r:";
+ } else {
+ sect = "M";
+ };
+ };
+ };
+ if (sect.length < 4) {
+ sect += `${(useLsb ? lsb : msb) - baseShift}`.padStart(4 - sect.length, "0");
+ };
+ // Hijack XG MU2000 sampler
+ if (mode == "xg" && msb == 16) {
+ bankName = `Voice${(lsb * 128 + prg + 1).toString().padStart(3, "0")}`;
+ ending = " ";
+ };
+ // Internal ID
+ let iid = [args[0], args[1], args[2]];
+ // Bank read
+ while (!(bankName?.length >= 0)) {
+ bankName = this.#bankInfo[args[1] || 0][(args[0] << 7) + args[2]];
+ if (!bankName) {
+ if (!this.strictMode) {
+ /* if (mode != "gs" && mode != "ns5r") {
+ args[2] = 0;
+ ending = "^";
+ }; */
+ if (!this.#bankInfo[args[1] || 0][args[0] << 7]) {
+ if (msb == 48) {
+ args[0] = 0;
+ args[2] = 0;
+ ending = "!";
+ } else if (msb == 62) {
+ args[1] --;
+ ending = " ";
+ if (args[1] < 1 && !bankName?.length) {
+ args[0] = 0;
+ ending = "!";
+ };
+ } else if (msb < 63) {
+ if (args[0] == 0) {
+ args[2] = 0;
+ ending = "^";
+ } else {
+ if (args[2] < 1) {
+ args[0] = 0;
+ ending = "*";
+ } else {
+ args[2] --; // Descending bank search
+ };
+ };
+ } else if (msb == 80) {
+ bankName = `PrgU:${prg.toString().padStart(3, "0")}`;
+ ending = "!";
+ } else if (msb == 88) {
+ bankName = `CmbU:${prg.toString().padStart(3, "0")}`;
+ ending = "!";
+ } else if (msb == 121) {
+ bankName = `GM2Vox0${lsb}`;
+ ending = "#";
+ } else if (msb == 122) {
+ if (args[1] == 32) {
+ args[1] == 0;
+ } else {
+ args[1] %= 7;
+ };
+ bankName = this.#bankInfo[args[1] || 0][(args[0] << 7) + args[2]];
+ if (bankName) {
+ ending = " ";
+ } else {
+ bankName = "";
+ ending = "*";
+ };
+ } else if (args[1] == 0) {
+ bankName = `${msb.toString().padStart(3, "0")} ${prg.toString().padStart(3, "0")} ${lsb.toString().padStart(3, "0")}`;
+ ending = "!";
+ } else {
+ if (args[0] == 0) {
+ args[2] = 0;
+ ending = "^";
+ } else if (args[2] > 0) {
+ args[2] --;
+ } else if (args[1] > 0) {
+ args[1] = 0;
+ ending = "!";
+ } else {
+ args[0] = 0;
+ ending = "?";
+ };
+ };
+ } else {
+ if (args[0] == 0) {
+ args[2] = 0;
+ ending = "^";
+ } else if (args[2] < 1) {
+ args[0] = 0;
+ ending = "*";
+ } else {
+ args[2] --; // Descending bank search
+ ending = "^";
+ };
+ };
+ } else {
+ bankName = "";
+ ending = "?";
+ };
+ };
+ };
+ // End ID
+ let eid = [args[0], args[1], args[2]];
+ if ((mode == "gs" || mode == "ns5r") && ending == "^") {
+ ending = " ";
+ };
+ if (msb == 127 && ending == "^") {
+ ending = " ";
+ };
+ if (ending != " ") {
+ if (self.debugMode) {
+ bankName = "";
+ };
+ };
+ let standard = "??";
+ switch (args[0]) {
+ case 0: {
+ if (args[2] == 0) {
+ standard = "GM";
+ } else if (args[2] == 5 || args[2] == 7) {
+ standard = "KG";
+ } else if (args[2] < 120) {
+ standard = "XG";
+ } else if (args[2] == 127) {
+ standard = "MT";
+ };
+ break;
+ };
+ case 48: {
+ standard = "MU"; // MU-100 Native
+ break;
+ };
+ case 56: {
+ standard = "AG";
+ break;
+ };
+ case 61:
+ case 80:
+ case 83:
+ case 88:
+ case 89:
+ case 91: {
+ standard = "AI";
+ break;
+ };
+ case 62:
+ case 82:
+ case 90: {
+ standard = "XD";
+ break;
+ };
+ case 63: {
+ if (args[2] < 17) {
+ standard = "KR";
+ } else if (args[2] < 34) {
+ standard = "ES";
+ } else {
+ standard = "DS";
+ };
+ break;
+ };
+ case 64:
+ case 126: {
+ standard = "XG";
+ break;
+ };
+ case 67:
+ case 99: {
+ standard = "DX"; // PLG-150DX
+ break;
+ };
+ case 81: {
+ standard = "RW";
+ break;
+ };
+ case 95: {
+ standard = ["DR", "PC"][args[2]]; // PLG-150DR/PC
+ break;
+ };
+ case 96: {
+ standard = args[2] == 106 ? "AP" : "PF";
+ break;
+ };
+ case 97: {
+ standard = "VL"; // PLG-150VL / SONDIUS-XG
+ break;
+ };
+ case 98: {
+ standard = "SG"; // PLG-100SG
+ break;
+ };
+ case 100: {
+ standard = "AN"; // PLG-150AN
+ break;
+ };
+ case 120: {
+ standard = "GS";
+ break;
+ };
+ case 121: {
+ standard = args[2] ? "G2" : "GM";
+ break;
+ };
+ case 122: {
+ standard = "KG";
+ break;
+ };
+ case 127: {
+ standard = args[2] == 127 ? "MT" : (prg == 0 ? "GM" : "XG");
+ break;
+ };
+ default: {
+ if (args[0] < 48) {
+ if (args[0] == 16 && mode == "xg") {
+ standard = "XG";
+ } else {
+ standard = "GS";
+ };
+ };
+ };
+ };
+ return {
+ name: bankName || `${halfHex(msb || 0)} ${halfHex(prg || 0)} ${halfHex(lsb || 0)}`,
+ iid,
+ eid,
+ sid,
+ ending,
+ sect,
+ standard
+ };
+ };
+ async load(text, allowOverwrite, name) {
+ let upThis = this;
+ let sig = []; // Significance
+ let loadCount = 0, allCount = 0;
+ text.split("\n").forEach(function (e, i) {
+ let assign = e.split("\t"), to = [];
+ if (i == 0) {
+ assign.forEach(function (e0, i0) {
+ sig[sgCrit.indexOf(e0)] = i0;
+ });
+ //console.debug(`Bank map significance: ${sig}`);
+ } else {
+ assign.forEach(async function (e1, i1) {
+ if (i1 > 2) {
+ upThis.#bankInfo[to[sig[1]]] = upThis.#bankInfo[to[sig[1]]] || [];
+ if (!upThis.#bankInfo[to[sig[1]]][(to[sig[0]] << 7) + to[sig[2]]]?.length || allowOverwrite) {
+ upThis.#bankInfo[to[sig[1]]][(to[sig[0]] << 7) + to[sig[2]]] = assign[3];
+ loadCount ++;
+ } else {
+ //console.debug(`Skipped overwriting ${to[sig[0]]},${to[sig[1]]},${to[sig[2]]}: [${upThis.#bankInfo[to[sig[1]]][(to[sig[0]] << 7) + to[sig[2]]]}] to [${assign[3]}]`);
+ };
+ allCount ++;
+ } else {
+ to.push(parseInt(assign[i1]));
+ };
+ });
+ };
+ });
+ if (!allowOverwrite) {
+ console.debug(`Map "${name || "(internal)"}": ${allCount} total, ${loadCount} loaded.`);
+ };
+ };
+ clearRange(options) {
+ let prg = options.prg != undefined ? (options.prg.constructor == Array ? options.prg : [options.prg, options.prg]) : [0, 127],
+ msb = options.msb != undefined ? (options.msb.constructor == Array ? options.msb : [options.msb, options.msb]) : [0, 127],
+ lsb = options.lsb != undefined ? (options.lsb.constructor == Array ? options.lsb : [options.lsb, options.lsb]) : [0, 127];
+ for (let cMsb = msb[0]; cMsb <= msb[1]; cMsb ++) {
+ let precalMsb = cMsb << 7;
+ for (let cLsb = lsb[0]; cLsb <= lsb[1]; cLsb ++) {
+ let precalBnk = precalMsb + cLsb;
+ for (let cPrg = prg[0]; cPrg <= prg[1]; cPrg ++) {
+ delete this.#bankInfo[cPrg][precalBnk];
+ };
+ };
+ };
+ };
+ init() {
+ this.#bankInfo = [];
+ for (let prg = 0; prg < 128; prg ++) {
+ this.#bankInfo.push([""]);
+ };
+ };
+ async loadFiles(...type) {
+ this.init();
+ let upThis = this;
+ type.forEach(async function (e, i) {
+ try {
+ await fetch(`./data/bank/${e}.tsv`).then(function (response) {
+ //console.debug(`Parsing voice map "${e}".`);
+ return response.text();
+ }).then((text) => {
+ upThis.load(text, false, e);
+ });
+ } catch (err) {
+ console.error(`Failed loading "${e}.tsv".`);
+ };
+ });
+ };
+ constructor(...args) {
+ this.loadFiles(...args);
+ };
+};
+
+export {
+ VoiceBank
+};
diff --git a/src/state/decoders.mjs b/src/state/decoders.mjs
new file mode 100644
index 00000000..49020e00
--- /dev/null
+++ b/src/state/decoders.mjs
@@ -0,0 +1,22 @@
+"use strict";
+
+let BlobDecoder = class {
+ #collection = {};
+ context;
+ set(format, decoder) {
+ this.#collection[format] = decoder;
+ };
+ has(format) {
+ return !!this.#collection[format];
+ };
+ async read(format, blob) {
+ if (!this.has(format)) {
+ throw(new Error(`No decoder registered for "${format}"`));
+ };
+ return await this.#collection[format].call(this.context || this, blob);
+ };
+};
+
+export {
+ BlobDecoder
+};
diff --git a/src/state/emitGlobal.js b/src/state/emitGlobal.js
new file mode 100644
index 00000000..9672b0e5
--- /dev/null
+++ b/src/state/emitGlobal.js
@@ -0,0 +1,82 @@
+"use strict";
+
+import {gsChecksum} from "./utils.js";
+
+const sysexHead = {
+ xg: new Uint8Array([240, 67, 16, 76, 7]), // XG
+ gs: new Uint8Array([240, 65, 16, 69, 18, 16]), // GS
+ ns5r: new Uint8Array([240, 66, 48, 66, 18, 8, 0, 32]) // NS5R
+};
+
+let sysexBitmap = function (frameData, type = "xg", frameId = 0, noCopy) {
+ if (!frameData?.length) {
+ throw Error(`Blank frame data`);
+ };
+ // 0 for XG, 1 for GS, 2 for NS5R
+ let targetBuffer, targetFrame, startOffset = 8,
+ canvasWidth = 16 << ((frameData.length - 1) >> 8),
+ canvasHeight = 16,
+ workWidth = 16, workBit = 7;
+ switch (type) {
+ case "xg": {
+ if (frameData.length > 256) {
+ throw(new Error(`Bitmap too large: ${frameData.length} > 256`));
+ };
+ targetBuffer = new Uint8Array(56);
+ targetBuffer.set(sysexHead[type], 0);
+ targetBuffer[55] = 247;
+ targetFrame = frameData;
+ startOffset = 7;
+ break;
+ };
+ case "gs": {
+ if (frameData.length > 256) {
+ throw(new Error(`Bitmap too large: ${frameData.length} > 256`));
+ };
+ targetBuffer = new Uint8Array(74);
+ targetBuffer.set(sysexHead[type], 0);
+ targetBuffer[73] = 247;
+ targetBuffer[6] = frameId + 1;
+ targetFrame = frameData;
+ workBit = 5;
+ break;
+ };
+ case "ns5r": {
+ if (frameData.length > 512) {
+ throw(new Error(`Bitmap too large: ${frameData.length} > 512`));
+ };
+ targetBuffer = new Uint8Array(89);
+ targetBuffer.set(sysexHead[type], 0);
+ targetBuffer[88] = 247;
+ // Duplicate the pixel data if the length is smaller than or equal to 256
+ if (frameData.length <= 256 && !noCopy) {
+ targetFrame = new Uint8Array(frameData.length * 2);
+ frameData.forEach((e, i) => {
+ targetFrame[i << 1] = e;
+ targetFrame[1 + (i << 1)] = e;
+ });
+ } else {
+ targetFrame = frameData;
+ };
+ workWidth = 32;
+ break;
+ };
+ default: {
+ throw(new Error(`Unknown device target ${type}`));
+ };
+ };
+ // Packing bits into bytes
+ targetFrame.forEach((e, i) => {
+ let canvasX = i % workWidth, canvasY = Math.floor(i / workWidth);
+ let pointer = Math.floor(canvasX / workBit) * canvasHeight + canvasY, shifter = workBit - canvasX % workBit - 1;
+ targetBuffer[startOffset + pointer] ^= (e ? 1 : 0) << shifter;
+ });
+ if (type == "gs") {
+ targetBuffer[72] = gsChecksum(targetBuffer.subarray(5, 72));
+ };
+ return targetBuffer;
+};
+
+export {
+ sysexBitmap
+};
diff --git a/src/state/gsValues.js b/src/state/gsValues.js
new file mode 100644
index 00000000..cb7dff92
--- /dev/null
+++ b/src/state/gsValues.js
@@ -0,0 +1,152 @@
+"use strict";
+
+let gsRevType = [
+ "room 1",
+ "room 2",
+ "room 3",
+ "hall 1",
+ "hall 2",
+ "plate",
+ "delay",
+ "panning delay"
+];
+let gsChoType = [
+ "chorus 1",
+ "chorus 2",
+ "chorus 3",
+ "chorus 4",
+ "feedback",
+ "flanger",
+ "short delay",
+ "short delay feedback"
+];
+let gsDelType = [
+ "delay 1",
+ "delay 2",
+ "delay 3",
+ "delay 4",
+ "pan delay 1",
+ "pan delay 2",
+ "pan delay 3",
+ "pan delay 4",
+ "delay to reverb",
+ "pan repeat"
+];
+let gsParts = [9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15];
+
+let gsEfx = {
+ 0x0000: "thru",
+ 0x0100: "stereo EQ",
+ 0x0101: "spectrum",
+ 0x0102: "enhancer",
+ 0x0103: "humanizer",
+ 0x0110: "overdrive",
+ 0x0111: "distortion",
+ 0x0120: "phaser",
+ 0x0121: "auto wah",
+ 0x0122: "rotary",
+ 0x0123: "stereo flanger",
+ 0x0124: "step flanger",
+ 0x0125: "tremelo",
+ 0x0126: "auto pan",
+ 0x0130: "compressor",
+ 0x0131: "limiter",
+ 0x0140: "hexa chorus",
+ 0x0141: "tremelo chorus",
+ 0x0142: "stereo chorus",
+ 0x0143: "space D",
+ 0x0144: "3D chorus",
+ 0x0150: "stereo delay",
+ 0x0151: "modulated delay",
+ 0x0152: "3-tap delay",
+ 0x0153: "4-tap delay",
+ 0x0154: "tremelo control delay",
+ 0x0155: "reverb",
+ 0x0156: "gate reverb",
+ 0x0157: "3D delay",
+ 0x0160: "2-pitch shifter",
+ 0x0161: "feedback pitch shifter",
+ 0x0170: "3D auto",
+ 0x0171: "3D manual",
+ 0x0172: "Lo-Fi 1",
+ 0x0173: "Lo-Fi 2",
+ 0x0200: "overdrive - chorus",
+ 0x0201: "overdrive - flanger",
+ 0x0202: "overdrive - delay",
+ 0x0203: "distortion - chorus",
+ 0x0204: "distortion - flanger",
+ 0x0205: "distortion - delay",
+ 0x0206: "enhancer - chorus",
+ 0x0207: "enhancer - flanger",
+ 0x0208: "enhancer - delay",
+ 0x0209: "chorus - delay",
+ 0x020a: "flanger - delay",
+ 0x020b: "chorus - flanger",
+ 0x020c: "rotary multi",
+ 0x0400: "guitar multi 1",
+ 0x0401: "guitar multi 2",
+ 0x0402: "guitar multi 3",
+ 0x0403: "clean guitar multi 1",
+ 0x0404: "clean guitar multi 2",
+ 0x0405: "bass multi",
+ 0x0406: "rhodes multi",
+ 0x0500: "keyboard multi",
+ 0x1100: "chorus / delay",
+ 0x1101: "flanger / delay",
+ 0x1102: "chorus / flanger",
+ 0x1103: "overdrive / distortion",
+ 0x1104: "overdrive / rotary",
+ 0x1105: "overdrive / phaser",
+ 0x1106: "overdrive / auto wah",
+ 0x1107: "phaser / rotary",
+ 0x1108: "phaser / auto wah"
+},
+gsEfxDesc = {
+ 0x010303: ["drive"],
+ 0x010305: ["vowel", (e) => {
+ return "aiueo"[e];
+ }],
+ 0x017203: ["pre-filter"],
+ 0x017204: ["Lo-Fi type"],
+ 0x017205: ["post-filter"],
+ 0x017303: ["Lo-Fi type"],
+ 0x017304: ["fill type", (e) => {
+ return ["off", "LPF", "HPF"][e];
+ }],
+ 0x017308: ["noise type", (e) => {
+ return ["white", "pink"][e];
+ }],
+ 0x01730b: ["disc type", (e) => {
+ return ["LP", "SP", "EP", "RND"];
+ }],
+ 0x01730e: ["hum type", (e) => {
+ return `${e + 5}0Hz`;
+ }],
+ 0x017311: ["M/S", (e) => {
+ return ["mono", "stereo"][e];
+ }]
+},
+getGsEfx = function (arr) {
+ return gsEfx[((arr[0] - 32) << 8) + arr[1]] || `0x${arr[0].toString(16).padStart(2, "0")}${arr[1].toString(16).padStart(2, "0")}`;
+},
+getGsEfxDesc = function (arr, param, value) {
+ let id = ((arr[0] - 32) << 16) + (arr[1] << 8) + param,
+ target = gsEfxDesc[id] || {},
+ desc = target[0];
+ if (desc?.length) {
+ desc += `: ${(target[1] || function () {})(value) || value}`;
+ return desc;
+ };
+};
+
+let mt32DefProg = [68, 48, 95, 78, 41, 3, 110, 122, 0];
+
+export {
+ gsRevType,
+ gsChoType,
+ gsDelType,
+ gsParts,
+ getGsEfx,
+ getGsEfxDesc,
+ mt32DefProg
+};
diff --git a/src/state/index.mjs b/src/state/index.mjs
new file mode 100644
index 00000000..266f3d4a
--- /dev/null
+++ b/src/state/index.mjs
@@ -0,0 +1,3899 @@
+"use strict";
+
+import {BinaryMatch} from "../../libs/lightfelt@ltgcgo/ext/binMatch.js";
+import {CustomEventSource} from "../../libs/lightfelt@ltgcgo/ext/customEvents.js";
+import {VoiceBank} from "./bankReader.js";
+import {bankDecoder} from "./bankDecoder.js";
+import {
+ xgEffType,
+ xgPartMode,
+ xgSgVocals,
+ xgDelOffset,
+ xgNormFreq,
+ xgLfoFreq,
+ getSgKana,
+ getXgRevTime,
+ getXgDelayOffset,
+ getVlCtrlSrc
+} from "./xgValues.js";
+import {
+ gsRevType,
+ gsChoType,
+ gsDelType,
+ gsParts,
+ getGsEfx,
+ getGsEfxDesc,
+ mt32DefProg
+} from "./gsValues.js";
+import {
+ toDecibel,
+ gsChecksum,
+ korgFilter,
+ x5dSendLevel
+} from "./utils.js";
+
+const modeIdx = [
+ "?",
+ "gm", "gs", "xg", "g2",
+ "mt32", "ns5r",
+ "ag10", "x5d", "05rw",
+ "k11", "sg",
+ "krs", "s90es", "motif"
+];
+const substList = [
+ [0, 0, 0, 0, 121, 0, 0, 56, 82, 81, 0, 0, 63, 63, 63],
+ [0, 0, 4, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+];
+const drumMsb = [120, 127, 120, 127, 120, 127, 61, 62, 62, 62, 120, 122, 122, 127];
+const passedMeta = [0, 3, 81, 84, 88]; // What is meta event 32?
+const eventTypes = {
+ 8: "Off",
+ 9: "On",
+ 10: "Note aftertouch",
+ 11: "cc",
+ 12: "pc",
+ 13: "Channel aftertouch",
+ 14: "Pitch"
+};
+
+const useRpnMap = {
+ 0: 0,
+ 1: 1,
+ 2: 3,
+ 5: 4
+},
+rpnCap = [
+ [0, 24],
+ [0, 127],
+ [0, 127],
+ [40, 88],
+ [0, 127],
+ [0, 127]
+],
+useNormNrpn = [36, 37],
+useDrumNrpn = [20, 21, 22, 23, 24, 25, 26, 28, 29, 30, 31, 36, 37, 64, 65],
+ccAccepted = [
+ 0, 1, 2, 4, 5, 6, 7, 8, 10, 11, 32,
+ 38, 64, 65, 66, 67, 68, 69, 70, 71,
+ 72, 73, 74, 75, 76, 77, 78, 84, 91,
+ 92, 93, 94, 95, 98, 99, 100, 101,
+ 128, // Dry level (internal register for Octavia)
+ 12, 13, // General-purpose effect controllers
+ 16, 17, 18, 19 // General-purpose sound controllers
+], // 96, 97, 120 to 127 all have special functions
+aceCandidates = [12, 13, 16, 17, 18, 19],
+nrpnCcMap = [33, 99, 100, 32, 102, 8, 9, 10]; // cc71 to cc78
+
+const korgDrums = [0, 16, 25, 40, 32, 64, 26, 48];
+
+let modeMap = {};
+modeIdx.forEach((e, i) => {
+ modeMap[e] = i;
+});
+let ccToPos = {
+ length: ccAccepted.length
+};
+ccAccepted.forEach((e, i) => {
+ ccToPos[e] = i;
+});
+let dnToPos = {
+ length: useDrumNrpn.length
+};
+useDrumNrpn.forEach((e, i) => {
+ dnToPos[e] = i;
+});
+
+let getDebugState = function () {
+ return !!self.Bun || self.debugMode || false; // If run on Bun.js, output all possible logs
+};
+let sysExSplitter = function (seq) {
+ let seqArr = [];
+ let seqStart = 0;
+ seq?.forEach(function (e, i) {
+ if (e == 247) {
+ // End of SysEx
+ seqArr.push(seq.subarray(seqStart, i));
+ } else if (e == 240) {
+ seqStart = i + 1;
+ } else {
+ //seqArr[seqArr.length - 1].push(e);
+ };
+ });
+ if (!seqArr.length) {
+ seqArr.push(seq.subarray(0));
+ };
+ if (getDebugState()) {
+ console.debug(seqArr);
+ };
+ return seqArr;
+};
+let showTrue = function (data, prefix = "", suffix = "", length = 2) {
+ return data ? `${prefix}${data.toString().padStart(length, "0")}${suffix}` : "";
+};
+
+const allocated = {
+ ch: 128, // channels
+ cc: ccAccepted.length, // control changes
+ nn: 128, // notes per channel
+ pl: 512, // polyphony
+ tr: 256, // tracks
+ cmt: 14, // C/M timbre storage size
+ rpn: 6,
+ ace: 8, // active custom effect
+ drm: 8, // Drum setup slots
+ dpn: useDrumNrpn.length, // Drum setup params
+ dnc: 128, // note 0 to 127
+ efx: 7
+};
+
+let OctaviaDevice = class extends CustomEventSource {
+ // Constants
+ NOTE_IDLE = 0;
+ NOTE_ATTACK = 1;
+ NOTE_DECAY = 2;
+ NOTE_SUSTAIN = 3;
+ NOTE_HELD = 4;
+ NOTE_RELEASE = 5;
+ NOTE_SOSTENUTO_ATTACK = 8;
+ NOTE_SOSTENUTO_DECAY = 9;
+ NOTE_SOSTENUTO_SUSTAIN = 10;
+ NOTE_SOSTENUTO_HELD = 11;
+ CH_MELODIC = 0;
+ CH_DRUMS = 1;
+ CH_DRUM1 = 2;
+ CH_DRUM2 = 3;
+ CH_DRUM3 = 4;
+ CH_DRUM4 = 5;
+ CH_DRUM5 = 6;
+ CH_DRUM6 = 7;
+ CH_DRUM7 = 8;
+ CH_DRUM8 = 9;
+ // Values
+ #mode = 0;
+ #bitmapPage = 0;
+ #bitmapExpire = 0;
+ #bitmapStore = new Array(11); // 10 pages of bitmaps, 1 KORG bitmap
+ get #bitmap() {
+ return this.#bitmapStore[this.#bitmapPage];
+ };
+ set #bitmap(value) {
+ this.#bitmapStore[this.#bitmapPage] = value;
+ };
+ #chActive = new Uint8Array(allocated.ch); // Whether the channel is in use
+ #chReceive = new Uint8Array(allocated.ch); // Determine the receiving channel
+ #chType = new Uint8Array(allocated.ch); // Types of channels
+ #cc = new Uint8Array(allocated.ch * allocated.cc); // 64 channels, 128 controllers
+ #ace = new Uint8Array(allocated.ace); // 4 active custom effects
+ #prg = new Uint8Array(allocated.ch);
+ #velo = new Uint8Array(allocated.ch * allocated.nn); // 64 channels. 128 velocity registers
+ #mono = new Uint8Array(allocated.ch); // Mono/poly mode
+ #poly = new Uint16Array(allocated.pl); // 512 polyphony allowed
+ #polyState = new Uint8Array(allocated.pl); // State of each active voice.
+ #pitch = new Int16Array(allocated.ch); // Pitch for channels, from -8192 to 8191
+ #rawStrength = new Uint8Array(allocated.ch);
+ #dataCommit = 0; // 0 for RPN, 1 for NRPN
+ #rpn = new Uint8Array(allocated.ch * allocated.rpn); // RPN registers (0 pitch MSB, 1 fine tune MSB, 2 fine tune LSB, 3 coarse tune MSB, 4 mod sensitivity MSB, 5 mod sensitivity LSB)
+ #nrpn = new Int8Array(allocated.ch * useNormNrpn.length); // Normal section of NRPN registers
+ #drum = new Uint8Array(allocated.drm * allocated.dpn * allocated.dnc); // Drum setup
+ #bnCustom = new Uint8Array(allocated.ch); // Custom name activation
+ #cmTPatch = new Uint8Array(128); // C/M part patch storage
+ #cmTTimbre = new Uint8Array(allocated.cmt * 8); // C/M part timbre storage
+ #cmPatch = new Uint8Array(1024); // C/M device patch storage
+ #cmTimbre = new Uint8Array(allocated.cmt * 64); // C/M device timbre storage (64)
+ #efxBase = new Uint8Array(allocated.efx * 3); // Base register for EFX types
+ #subMsb = 0; // Allowing global bank switching
+ #subLsb = 0;
+ #masterVol = 100;
+ #metaChannel = 0;
+ #noteLength = 500;
+ #convertLastSyllable = 0;
+ #letterDisp = "";
+ #letterExpire = 0;
+ #selectPort = 0;
+ #receiveRS = true; // Receive remote switch
+ #modeKaraoke = false;
+ #receiveTree;
+ // Temporary EFX storage
+ #gsEfxSto = new Uint8Array(2);
+ // Metadata text events
+ #metaTexts = [];
+ // GS Track Occupation
+ #trkRedir = new Uint8Array(allocated.ch);
+ #trkAsReq = new Uint8Array(allocated.tr); // Track Assignment request
+ baseBank = new VoiceBank("gm", "gm2", "xg", "gs", "ns5r", "gmega", "plg-150vl", "plg-150pf", "plg-150dx", "plg-150an", "plg-150dr", "plg-100sg", "kross", "s90es"); // Load all possible voice banks
+ userBank = new VoiceBank("gm"); // User-defined bank for MT-32, X5DR and NS5R
+ initOnReset = false; // If this is true, Octavia will re-init upon mode switches
+ aiEfxName = "";
+ chRedir(part, track, noConquer) {
+ if (this.#trkAsReq[track]) {
+ // Allow part assigning via meta
+ let metaChosen = (this.#trkAsReq[track] - 1) * 16 + part;
+ return metaChosen;
+ } else if ([2, 3].indexOf(this.#subLsb) > -1) {
+ // Do not conquer channels if requested.
+ if (noConquer == 1) {
+ return part;
+ };
+ let shift = 0, unmet = true;
+ while (unmet) {
+ if (this.#trkRedir[part + shift] == 0) {
+ this.#trkRedir[part + shift] = track;
+ console.debug(`Assign track ${track} to channel ${part + shift + 1}.`);
+ unmet = false;
+ } else if (this.#trkRedir[part + shift] == track) {
+ unmet = false;
+ } else {
+ shift += 16;
+ if (shift >= 128) {
+ shift = 0;
+ unmet = false;
+ };
+ };
+ };
+ return part + shift;
+ } else {
+ return part;
+ };
+ };
+ // Exec Pools
+ // Meta event pool
+ #metaRun = [];
+ // Sequencer specific meta pool
+ #metaSeq;
+ // Universal actions
+ #ua = {
+ nOff: (part, note) => {
+ // Note off
+ let rawNote = part * 128 + note;
+ let polyIdx = this.#poly.lastIndexOf(rawNote);
+ if (polyIdx > -1) {
+ if (this.#cc[allocated.cc * part + ccToPos[64]] > 63) {
+ // Held by cc64
+ this.#polyState[polyIdx] = this.NOTE_HELD;
+ this.dispatchEvent("note", {
+ part,
+ note,
+ velo: this.#velo[rawNote],
+ state: this.NOTE_HELD
+ });
+ } else if (this.#cc[allocated.cc * part + ccToPos[66]] > 63 && this.#polyState[polyIdx] == this.NOTE_SOSTENUTO_SUSTAIN) {
+ // Held by cc66
+ this.#polyState[polyIdx] = this.NOTE_SOSTENUTO_HELD;
+ this.dispatchEvent("note", {
+ part,
+ note,
+ velo: this.#velo[rawNote],
+ state: this.NOTE_SOSTENUTO_HELD
+ });
+ } else {
+ this.#poly[polyIdx] = 0;
+ this.#velo[rawNote] = 0;
+ this.#polyState[polyIdx] = this.NOTE_IDLE;
+ this.dispatchEvent("note", {
+ part,
+ note,
+ velo: 0,
+ state: this.NOTE_IDLE
+ });
+ };
+ };
+ },
+ nOn: (part, note, velo) => {
+ // Note on
+ let rawNote = part * 128 + note;
+ let place = 0;
+ if (this.#mono[part]) {
+ // Shut all previous notes off in mono mode
+ this.#ua.ano(part);
+ };
+ while (this.#polyState[place] > 0 && this.#poly[place] != rawNote) {
+ // If just by judging whether a polyphonic voice is occupied,
+ // "multi" mode is considered active.
+ // If "rawNote" is also taken into consideration,
+ // this will be "single" mode instead.
+ // 0: idle
+ // 1: attack
+ // 2: decay
+ // 3: sustain (active)
+ // 4: hold
+ // 5: release
+ // 6: sostenuto sustain
+ // 7: sostenuto hold
+ place ++;
+ };
+ if (place < allocated.pl) {
+ this.#poly[place] = rawNote;
+ this.#velo[rawNote] = velo;
+ this.#polyState[place] = this.NOTE_SUSTAIN;
+ if (this.#rawStrength[part] < velo) {
+ this.#rawStrength[part] = velo;
+ };
+ this.dispatchEvent("note", {
+ part,
+ note,
+ velo,
+ state: this.NOTE_SUSTAIN
+ });
+ //console.debug(place);
+ } else {
+ console.error("Polyphony exceeded.");
+ };
+ },
+ nAt: (part, note, velo) => {
+ // Note/polyphonic aftertouch
+ },
+ cAt: (part, velo) => {
+ // Channel aftertouch
+ },
+ hoOf: (part) => {
+ // Scan and turn off all notes held by cc64
+ this.#polyState.forEach((e, i) => {
+ if (e == this.NOTE_HELD) {
+ // Held by cc64
+ let rawNote = this.#poly[i];
+ let channel = rawNote >> 7;
+ if (part == channel) {
+ this.#polyState[i] = this.NOTE_IDLE;
+ this.#poly[i] = 0;
+ this.#velo[rawNote] = 0;
+ this.dispatchEvent("note", {
+ part,
+ note: rawNote & 127,
+ velo: 0,
+ state: this.NOTE_IDLE
+ });
+ };
+ };
+ });
+ },
+ soOn: (part) => {
+ // Scan and convert all unoccupied active notes to be managed by sostenuto
+ this.#polyState.forEach((e, i) => {
+ let emitEvent;
+ switch (e) {
+ case this.NOTE_ATTACK: {
+ emitEvent = this.NOTE_SOSTENUTO_ATTACK;
+ break;
+ };
+ case this.NOTE_DECAY: {
+ emitEvent = this.NOTE_SOSTENUTO_DECAY;
+ break;
+ };
+ case this.NOTE_SUSTAIN: {
+ emitEvent = this.NOTE_SOSTENUTO_SUSTAIN;
+ break;
+ };
+ };
+ if (emitEvent) {
+ this.#polyState[i] = emitEvent;
+ let rawNote = this.#poly[i];
+ this.dispatchEvent("note", {
+ part,
+ note: rawNote & 127,
+ velo: this.#velo[rawNote],
+ state: emitEvent
+ });
+ };
+ });
+ },
+ soOf: (part) => {
+ // Scan and turn off all notes held by cc66
+ this.#polyState.forEach((e, i) => {
+ if (e == this.NOTE_SOSTENUTO_HELD) {
+ // Held by cc66
+ let rawNote = this.#poly[i];
+ let channel = rawNote >> 7;
+ if (part == channel) {
+ this.#polyState[i] = this.NOTE_IDLE;
+ this.#poly[i] = 0;
+ this.#velo[rawNote] = 0;
+ this.dispatchEvent("note", {
+ part,
+ note: rawNote & 127,
+ velo: 0,
+ state: this.NOTE_IDLE
+ });
+ };
+ };
+ });
+ },
+ ano: (part) => {
+ // All notes off
+ // Current implementation uses the static velocity register
+ this.#poly.forEach((e, i, a) => {
+ let ch = e >> 7, no = e & 127;
+ if (e == 0 && this.#velo[0] == 0) {
+ } else if (ch == part) {
+ this.#ua.nOff(ch, no);
+ };
+ });
+ }
+ };
+ // Channel event pool
+ #runChEvent = {
+ 8: function (det) {
+ let part = det.channel;
+ // Note off, velocity should be ignored.
+ let rawNote = det.data[0];
+ this.#ua.nOff(part, rawNote);
+ },
+ 9: function (det) {
+ let part = det.channel;
+ // Note on, but should be off if velocity is 0.
+ // Set channel active
+ this.#chActive[part] = 1;
+ let rawNote = det.data[0];
+ let velocity = det.data[1];
+ if (velocity > 0) {
+ this.#ua.nOn(part, rawNote, velocity);
+ } else {
+ this.#ua.nOff(part, rawNote);
+ };
+ },
+ 10: function (det) {
+ let part = det.channel;
+ // Note aftertouch.
+ // Currently it directly changes velocity to set value.
+ let rawNote = part * 128 + det.data[0];
+ let polyIdx = this.#poly.indexOf(rawNote);
+ if (polyIdx > -1) {
+ this.#velo[rawNote] = data[1];
+ this.dispatchEvent("note", {
+ part,
+ note: det.data[0],
+ velo: det.data[1],
+ state: this.NOTE_SUSTAIN
+ });
+ };
+ },
+ 11: function (det) {
+ let part = det.channel;
+ // CC event, directly assign values to the register.
+ if ([0, 32].indexOf(det.data[0]) > -1) {
+ (() => {
+ switch(this.#mode) {
+ case modeMap.s90es:
+ case modeMap.motif: {
+ if (det.data[0] == 0) {
+ ([0, 63].indexOf(det.data[1]) > -1) && (this.#chActive[part] = 1);
+ break;
+ };
+ det.data[1] && (this.#chActive[part] = 1);
+ break;
+ };
+ default: {
+ this.#chActive[part] = 1;
+ break;
+ };
+ };
+ })();
+ };
+ let chOffset = part * allocated.cc;
+ // Non-store CC messages
+ switch (det.data[0]) {
+ case 96: {
+ // RPN Data increment
+ return;
+ break;
+ };
+ case 97: {
+ // RPN Data decrement
+ return;
+ break;
+ };
+ case 120: {
+ // All sound off, but keys stay on
+ return;
+ break;
+ };
+ case 121: {
+ // Reset controllers
+ this.#ua.ano(part);
+ this.#pitch[part] = 0;
+ let chOff = part * allocated.cc;
+ // Reset to zero
+ this.#cc[chOff + ccToPos[1]] = 0; // Modulation
+ this.#cc[chOff + ccToPos[5]] = 0; // Portamento Time
+ this.#cc[chOff + ccToPos[64]] = 0; // Sustain
+ this.#cc[chOff + ccToPos[65]] = 0; // Portamento
+ this.#cc[chOff + ccToPos[66]] = 0; // Sostenuto
+ this.#cc[chOff + ccToPos[67]] = 0; // Soft Pedal
+ // Reset to full
+ this.#cc[chOff + ccToPos[11]] = 127; // Expression
+ // RPN/NRPN to null
+ this.#cc[chOff + ccToPos[101]] = 127;
+ this.#cc[chOff + ccToPos[100]] = 127;
+ this.#cc[chOff + ccToPos[99]] = 127;
+ this.#cc[chOff + ccToPos[98]] = 127;
+ return;
+ break;
+ };
+ case 123: {
+ // All notes off
+ this.#ua.ano(part);
+ return;
+ break;
+ };
+ case 124: {
+ // Omni off
+ this.#ua.ano(part);
+ return;
+ break;
+ };
+ case 125: {
+ // Omni on
+ this.#ua.ano(part);
+ return;
+ break;
+ };
+ case 126: {
+ // Mono mode
+ this.#mono[part] = 1;
+ this.#ua.ano(part);
+ return;
+ break;
+ };
+ case 127: {
+ // Poly mode
+ this.#mono[part] = 0;
+ this.#ua.ano(part);
+ return;
+ break;
+ };
+ };
+ // Check if control change is accepted
+ if (ccToPos[det.data[0]] == undefined) {
+ console.warn(`cc${det.data[0]} is not accepted.`);
+ } else {
+ // ACE allocation
+ if (aceCandidates.indexOf(det.data[0]) > -1) {
+ this.allocateAce(det.data[0]);
+ };
+ // Stored CC messages
+ switch (det.data[0]) {
+ case 0: {
+ // Detect mode via bank MSB
+ if (getDebugState()) {
+ console.debug(`${modeIdx[this.#mode]}, CH${part + 1}: ${det.data[1]}`);
+ };
+ if (this.#mode == 0) {
+ if (det.data[1] < 48) {
+ // Do not change drum channel to a melodic
+ if (this.#chType[part] > 0) {
+ det.data[1] = this.#cc[chOffset];
+ det.data[1] = 120;
+ console.debug(`Forced channel ${part + 1} to stay drums.`);
+ };
+ if (det.data[1] > 0) {
+ console.debug(`Roland GS detected with MSB: ${det.data[1]}`);
+ this.switchMode("gs");
+ };
+ } else if (det.data[1] == 62) {
+ this.switchMode("x5d");
+ } else if (det.data[1] == 63) {
+ this.switchMode("krs");
+ } else if (det.data[1] == 64 || det.data[1] == 127) {
+ this.switchMode("xg");
+ };
+ } else if (this.#mode == modeMap.gs) {
+ if (det.data[1] < 56) {
+ // Do not change drum channel to a melodic
+ if (this.#chType[part] > 0) {
+ det.data[1] = this.#cc[chOffset];
+ det.data[1] = 120;
+ console.debug(`Forced channel ${part + 1} to stay drums.`);
+ };
+ };
+ } else if (this.#mode == modeMap.gm) {
+ if (det.data[1] < 48) {
+ // Do not change drum channel to a melodic
+ if (this.#chType[part] > 0) {
+ det.data[1] = 120;
+ this.switchMode("gs", true);
+ console.debug(`Forced channel ${part + 1} to stay drums.`);
+ };
+ } else if (det.data[1] == 64 || det.data[1] == 127) {
+ this.switchMode("xg", true);
+ };
+ } else if (this.#mode == modeMap.x5d) {
+ if (det.data[1] > 0 && det.data[1] < 8) {
+ this.switchMode("05rw", true);
+ } else if (det.data[1] == 56) {
+ let agCount = 0;
+ for (let c = 0; c < 16; c ++) {
+ let d = this.#cc[allocated.cc * c];
+ if (d == 56 || d == 62) {
+ agCount ++;
+ };
+ };
+ if (agCount > 14) {
+ this.switchMode("ag10", true);
+ };
+ };
+ };
+ switch (this.#mode) {
+ case modeMap.xg: {
+ if ([126, 127].indexOf(det.data[1]) > -1) {
+ if (this.#chType[part] == 0) {
+ this.setChType(part, this.CH_DRUM2);
+ console.debug(`CH${part + 1} set to drums by MSB.`);
+ };
+ } else {
+ if (this.#chType[part] > 0) {
+ this.setChType(part, this.CH_MELODIC);
+ console.debug(`CH${part + 1} set to melodic by MSB.`);
+ };
+ };
+ break;
+ };
+ case modeMap["05rw"]:
+ case modeMap.x5d:
+ case modeMap.ns5r: {
+ if ([61, 62, 126, 127].indexOf(det.data[1]) > -1) {
+ if (this.#chType[part] == 0) {
+ this.setChType(part, this.CH_DRUM2);
+ console.debug(`CH${part + 1} set to drums by MSB.`);
+ };
+ } else {
+ if (this.#chType[part] > 0) {
+ this.setChType(part, this.CH_MELODIC);
+ console.debug(`CH${part + 1} set to melodic by MSB.`);
+ };
+ };
+ break;
+ };
+ case modeMap.g2: {
+ if (det.data[1] == 120) {
+ if (this.#chType[part] == 0) {
+ this.setChType(part, this.CH_DRUMS);
+ console.debug(`CH${part + 1} set to drums by MSB.`);
+ };
+ } else {
+ if (this.#chType[part] > 0) {
+ this.setChType(part, this.CH_MELODIC);
+ console.debug(`CH${part + 1} set to melodic by MSB.`);
+ };
+ };
+ break;
+ };
+ };
+ this.dispatchEvent("voice", {
+ part
+ });
+ break;
+ };
+ case 6: {
+ // Show RPN and NRPN
+ if (this.#dataCommit) {
+ // Commit supported NRPN values
+ if ([modeMap.xg, modeMap.gs, modeMap.ns5r].indexOf(this.#mode) < 0) {
+ console.warn(`NRPN commits are not available under "${modeIdx[this.#mode]}" mode, even when they are supported in Octavia.`);
+ };
+ let msb = this.#cc[chOffset + ccToPos[99]],
+ lsb = this.#cc[chOffset + ccToPos[98]];
+ if (msb == 1) {
+ let toCc = nrpnCcMap.indexOf(lsb);
+ if (toCc > -1) {
+ this.#cc[chOffset + ccToPos[71 + toCc]] = det.data[1];
+ getDebugState() && console.debug(`Redirected NRPN 1 ${lsb} to cc${71 + toCc}.`);
+ this.dispatchEvent("cc", {
+ part,
+ cc: 71 + toCc,
+ data: det.data[1]
+ });
+ } else {
+ let nrpnIdx = useNormNrpn.indexOf(lsb);
+ if (nrpnIdx > -1) {
+ this.#nrpn[part * 10 + nrpnIdx] = det.data[1] - 64;
+ } else {
+ console.warn(`NRPN 0x01${lsb.toString(16).padStart(2, "0")} is not supported.`);
+ };
+ getDebugState() && console.debug(`CH${part + 1} voice NRPN ${lsb} commit`);
+ };
+ } else {
+ let nrpnIdx = useDrumNrpn.indexOf(msb);
+ if (nrpnIdx < 0) {
+ let dPref = `NRPN 0x${msb.toString(16).padStart(2, "0")}${lsb.toString(16).padStart(2, "0")} `;
+ if (msb == 127) {
+ console.warn(`${dPref}is not necessary. Consider removing it.`);
+ } else {
+ console.warn(`${dPref}is not supported.`);
+ };
+ } else {
+ let targetSlot = this.#chType[part] - 2;
+ if (targetSlot < 0) {
+ console.warn(`CH${part + 1} cannot accept drum NRPN as type ${xgPartMode[this.#chType[part]]}.`);
+ } else {
+ this.#drum[(targetSlot * allocated.dpn + dnToPos[msb]) * allocated.dnc + lsb] = det.data[1] - 64;
+ };
+ };
+ getDebugState() && console.debug(`CH${part + 1} (${xgPartMode[this.#chType[part]]}) drum NRPN ${msb} commit`);
+ };
+ } else {
+ // Commit supported RPN values
+ let rpnIndex = useRpnMap[this.#cc[chOffset + ccToPos[100]]];
+ if (this.#cc[chOffset + ccToPos[101]] == 0 && rpnIndex != undefined) {
+ getDebugState() && console.debug(`CH${part + 1} RPN 0 ${this.#cc[chOffset + ccToPos[100]]} commit: ${det.data[1]}`);
+ det.data[1] = Math.min(Math.max(det.data[1], rpnCap[rpnIndex][0]), rpnCap[rpnIndex][1]);
+ this.#rpn[part * allocated.rpn + rpnIndex] = det.data[1];
+ };
+ };
+ break;
+ };
+ case 32: {
+ switch (this.#mode) {
+ case modeMap.s90es:
+ case modeMap.motif: {
+ this.#chType[part] = +([32, 40].indexOf(det.data[1]) > -1) << 1;
+ break;
+ };
+ };
+ this.dispatchEvent("voice", {
+ part
+ });
+ break;
+ };
+ case 38: {
+ // Show RPN and NRPN
+ if (!this.#dataCommit) {
+ // Commit supported RPN values
+ if (this.#cc[chOffset + 101] == 0 && useRpnMap[this.#cc[chOffset + 100]] != undefined) {
+ this.#rpn[part * allocated.rpn + useRpnMap[this.#cc[chOffset + 100]] + 1] = det.data[1];
+ };
+ } else {
+ //console.debug(`${part + 1} LSB ${det.data[1]} ${this.#dataCommit ? "NRPN" : "RPN"} ${this.#dataCommit ? this.#cc[chOffset + 99] : this.#cc[chOffset + 101]} ${this.#dataCommit ? this.#cc[chOffset + 98] : this.#cc[chOffset + 100]}`);
+ };
+ break;
+ };
+ case 64: {
+ // cc64: hold
+ if (det.data[1] < 64) {
+ this.#ua.hoOf(part);
+ };
+ break;
+ };
+ case 66: {
+ // cc66: sostenuto
+ if (det.data[1] >> 6) {
+ // Sostenuto on
+ this.#ua.soOn(part);
+ } else {
+ // Sostenuto off
+ this.#ua.soOf(part);
+ };
+ break;
+ };
+ case 98:
+ case 99: {
+ this.#dataCommit = 1;
+ break;
+ };
+ case 100:
+ case 101: {
+ this.#dataCommit = 0;
+ break;
+ };
+ };
+ this.#cc[chOffset + ccToPos[det.data[0]]] = det.data[1];
+ this.dispatchEvent("cc", {
+ part,
+ cc: det.data[0],
+ data: det.data[1]
+ });
+ };
+ },
+ 12: function (det) {
+ let part = det.channel;
+ // Program change
+ switch (this.#mode) {
+ case modeMap.s90es:
+ case modeMap.motif: {
+ det.data && (this.#chActive[part] = 1);
+ break;
+ };
+ default: {
+ this.#chActive[part] = 1;
+ };
+ };
+ this.#prg[part] = det.data;
+ this.#bnCustom[part] = 0;
+ if (getDebugState()) {
+ console.debug(`T:${det.track} C:${part} P:${det.data}`);
+ };
+ this.dispatchEvent("voice", {
+ part
+ });
+ },
+ 13: function (det) {
+ // Channel aftertouch
+ let upThis = this;
+ let part = det.channel;
+ this.#poly.forEach(function (e) {
+ let realCh = e >> 7;
+ if (part == realCh) {
+ upThis.#velo[e] = det.data;
+ upThis.dispatchEvent("note", {
+ part,
+ note: e & 127,
+ velo: det.data,
+ state: upThis.NOTE_SUSTAIN
+ });
+ };
+ });
+ },
+ 14: function (det) {
+ let part = det.channel;
+ // Pitch bending
+ this.#pitch[part] = det.data[1] * 128 + det.data[0] - 8192;
+ this.dispatchEvent("pitch", {
+ part,
+ pitch: this.getPitchShift(part)
+ });
+ },
+ 15: function (det) {
+ // SysEx
+ sysExSplitter(det.data).forEach((seq) => {
+ let manId = seq[0],
+ deviceId = seq[1];
+ (this.#seMan[manId] || function () {
+ console.debug(`Unknown manufacturer ${manId}.`);
+ })(deviceId, seq.subarray(2), det.track);
+ //upThis.#seMain.run(seq, det.track);
+ });
+ },
+ 248: function (det) {
+ // MIDI clock
+ },
+ 250: function (det) {
+ // MIDI start
+ },
+ 251: function (det) {
+ // MIDI continue
+ },
+ 252: function (det) {
+ // MIDI stop
+ },
+ 254: function (det) {
+ // Active sense
+ },
+ 255: function (det) {
+ // Meta
+ (this.#metaRun[det.meta] || function (data, track, meta) {}).call(this, det.data, det.track, det.meta);
+ if (det.meta != 32) {
+ this.#metaChannel = 0;
+ };
+ let useReply = passedMeta.indexOf(det.meta) > -1;
+ if (getDebugState()) {
+ console.debug(det);
+ };
+ if (useReply) {
+ det.reply = "meta";
+ return det;
+ };
+ }
+ };
+ // SysEx manufacturer table
+ #seMan = {
+ 64: (id, msg, track) => {
+ // Kawai
+ this.#seKg.run(msg, track, id);
+ },
+ 65: (id, msg, track) => {
+ // Roland
+ // CmdId is usually 18 (DT1)
+ // D-50: [20, CmdId]
+ // C/M: [22, CmdId]
+ // GS: [66, CmdId, HH, MM, LL, ...DD, Checksum]
+ if (msg[0] < 16) {
+ this.#seGs.run(msg, track, id);
+ console.warn(`Unknown device SysEx!`);
+ } else {
+ let sentCs = msg[msg.length - 1];
+ let calcCs = gsChecksum(msg.subarray(2, msg.length - 1));
+ if (sentCs == calcCs) {
+ this.#seGs.run(msg.subarray(0, msg.length - 1), track, id);
+ } else {
+ console.warn(`Bad GS checksum ${sentCs}. Should be ${calcCs}.`);
+ };
+ };
+ },
+ 66: (id, msg, track) => {
+ // Korg
+ this.#seAi.run(msg, track, id);
+ },
+ 67: (id, msg, track) => {
+ // Yamaha
+ // XG: [76, HH, MM, LL, ...DD]
+ this.#seXg.run(msg, track, id);
+ },
+ 68: (id, msg, track) => {
+ // Casio
+ this.#seCs.run(msg, track, id);
+ },
+ 71: (id, msg, track) => {
+ // Akai
+ this.#seSg.run(msg, track, id);
+ },
+ 126: (id, msg, track) => {
+ // Universal non-realtime
+ this.#seUnr.run(msg, track, id);
+ },
+ 127: (id, msg, track) => {
+ // Universal realtime
+ this.switchMode("gm");
+ this.#seUr.run(msg, track, id);
+ }
+ };
+ #seUnr; // Universal non-realtime
+ #seUr; // Universal realtime
+ #seXg; // YAMAHA
+ #seGs; // Roland
+ #seAi; // KORG
+ #seKg; // Kawai
+ #seSg; // Akai
+ #seCs; // Casio
+ buildRchTree() {
+ // Build a receiving tree from currently set receive channels
+ // Now builds from the ground up each time
+ // Can be optimized to move elements instead
+ let tree = [];
+ this.#chReceive.forEach((e, i) => {
+ if (!tree[e]?.constructor) {
+ tree[e] = [];
+ };
+ tree[e].push(i);
+ });
+ this.#receiveTree = tree;
+ //console.debug(tree);
+ };
+ getActive() {
+ let result = this.#chActive.slice();
+ if (this.#mode == modeMap.mt32) {
+ //result[0] = 0;
+ };
+ return result;
+ };
+ getCc(channel) {
+ // Return channel CC registers
+ let start = channel * allocated.cc;
+ let arr = this.#cc.subarray(start, start + allocated.cc);
+ arr[ccToPos[0]] = arr[ccToPos[0]] || this.#subMsb;
+ arr[ccToPos[32]] = arr[ccToPos[32]] || this.#subLsb;
+ return arr;
+ };
+ getCcCh(channel, cc) {
+ if (ccAccepted.indexOf(cc) < 0) {
+ throw(new Error("CC number not accepted"));
+ };
+ return this.#cc[allocated.cc * channel + ccToPos[cc]];
+ };
+ getCcAll() {
+ // Return all CC registers
+ let arr = this.#cc.slice();
+ for (let c = 0; c < allocated.ch; c ++) {
+ let chOff = c * allocated.cc;
+ arr[chOff + ccToPos[0]] = arr[chOff + ccToPos[0]] || this.#subMsb;
+ arr[chOff + ccToPos[32]] = arr[chOff + ccToPos[32]] || this.#subLsb;
+ };
+ return arr;
+ };
+ getChType() {
+ return this.#chType;
+ };
+ setChType(part, type, mode = this.#mode) {
+ type &= 15;
+ this.#chType[part] = type;
+ if (type > 0) {
+ this.#cc[part * allocated.cc + ccToPos[0]] = drumMsb[mode];
+ };
+ };
+ getPitch() {
+ return this.#pitch;
+ };
+ getProgram() {
+ return this.#prg;
+ };
+ getTexts() {
+ return this.#metaTexts.slice();
+ };
+ getVel(channel) {
+ // Return all pressed keys with velocity in a channel
+ let notes = new Map();
+ let upThis = this;
+ upThis.#poly.forEach(function (e, i) {
+ let realCh = Math.floor(e / 128),
+ realNote = e % 128;
+ if (channel == realCh && upThis.#velo[e] > 0) {
+ notes.set(realNote, {
+ v: upThis.#velo[e], // Short for velocity
+ s: upThis.#polyState[i] // Short for state
+ });
+ };
+ });
+ return notes;
+ };
+ getBitmap() {
+ return {
+ bitmap: this.#bitmap,
+ expire: this.#bitmapExpire
+ };
+ };
+ getLetter() {
+ return {
+ text: this.#letterDisp,
+ expire: this.#letterExpire
+ };
+ };
+ getMode() {
+ return modeIdx[this.#mode];
+ };
+ getMaster() {
+ return {
+ volume: this.#masterVol
+ };
+ };
+ getRawStrength() {
+ // 0 to 127
+ let upThis = this;
+ this.#poly.forEach(function (e) {
+ let channel = Math.floor(e / 128);
+ if (upThis.#velo[e] > upThis.#rawStrength[channel]) {
+ upThis.#rawStrength[channel] = upThis.#velo[e];
+ };
+ });
+ return this.#rawStrength;
+ };
+ getStrength() {
+ // 0 to 255
+ // Should later become 0 to 65535
+ let str = [], upThis = this;
+ this.getRawStrength().forEach(function (e, i) {
+ str[i] = Math.floor(e * upThis.#cc[i * allocated.cc + ccToPos[7]] * upThis.#cc[i * allocated.cc + ccToPos[11]] * upThis.#masterVol / 803288);
+ });
+ return str;
+ };
+ getRpn() {
+ return this.#rpn;
+ };
+ getNrpn() {
+ return this.#nrpn;
+ };
+ getVoice(msbO, prgO, lsbO, mode) {
+ let msb = msbO || this.#subMsb,
+ prg = prgO,
+ lsb = lsbO || this.#subLsb;
+ if (modeIdx[this.#mode] == "ns5r") {
+ if (msb > 0 && msb < 56) {
+ lsb = 3; // Use SC-88 Pro map
+ };
+ };
+ let bank = this.userBank.get(msb, prg, lsb, mode);
+ if (modeIdx[this.#mode] == "mt32") {
+ // Reload MT-32 user bank transparently
+ if (bank.name.indexOf("MT-m:") == 0) {
+ // Device patch
+ let patch = parseInt(bank.name.slice(5)),
+ timbreOff = patch * allocated.cmt,
+ userBank = "";
+ this.#cmTimbre.subarray(timbreOff, timbreOff + 10).forEach((e) => {
+ if (e > 31) {
+ userBank += String.fromCharCode(e);
+ };
+ });
+ this.userBank.load(`MSB\tLSB\tPRG\n0\t127\t${prg}\t${userBank}`, true);
+ bank.name = userBank;
+ bank.ending = " ";
+ };
+ };
+ if (bank.ending != " " || !bank.name.length) {
+ bank = this.baseBank.get(msb, prg, lsb, mode);
+ };
+ return bank;
+ };
+ getChVoice(part) {
+ let voice = this.getVoice(this.#cc[part * allocated.cc + ccToPos[0]], this.#prg[part], this.#cc[part * allocated.cc + ccToPos[32]], modeIdx[this.#mode]);
+ if (this.#bnCustom[part]) {
+ switch (this.#mode) {
+ case modeMap.mt32: {
+ voice.ending = "~";
+ voice.name = "";
+ this.#cmTTimbre.subarray(14 * (part - 1), 14 * (part - 1) + 10).forEach((e) => {
+ if (e > 31) {
+ voice.name += String.fromCharCode(e);
+ };
+ });
+ };
+ };
+ };
+ return voice;
+ };
+ getPitchShift(part) {
+ let rpnOff = part * allocated.rpn;
+ return this.#pitch[part] / 8192 * this.#rpn[rpnOff] + (this.#rpn[rpnOff + 3] - 64) + ((this.#rpn[rpnOff + 1] << 7) + this.#rpn[rpnOff + 2] - 8192) / 8192;
+ };
+ getEffectType(slot = 0) {
+ let index = 3 * slot + 1;
+ return this.#efxBase.subarray(index, index + 2);
+ };
+ setEffectTypeRaw(slot = 0, isLsb, value) {
+ let efxbOff = 3 * slot;
+ this.#efxBase[efxbOff] = 1;
+ this.#efxBase[efxbOff + 1 + +isLsb] = value;
+ };
+ setEffectType(slot = 0, msb, lsb) {
+ this.setEffectTypeRaw(slot, false, msb);
+ this.setEffectTypeRaw(slot, true, lsb);
+ };
+ setLetterDisplay(data, source, offset = 0, delay = 3200) {
+ let upThis = this,
+ invalidCp;
+ upThis.#letterDisp = " ".repeat(offset);
+ data.forEach((e) => {
+ upThis.#letterDisp += String.fromCharCode(e > 31 ? e : 32);
+ if (e < 32) {
+ invalidCp = invalidCp || new Set();
+ invalidCp.add(e);
+ };
+ });
+ upThis.#letterExpire = Date.now() + 3200;
+ upThis.#letterDisp = upThis.#letterDisp.padEnd(32, " ");
+ if (invalidCp) {
+ invalidCp = Array.from(invalidCp);
+ invalidCp.forEach((e, i, a) => {
+ a[i] = e.toString(16).padStart(2, "0");
+ });
+ console.warn(`${source}${source ? " " : ""}invalid code point${invalidCp.length > 1 ? "s" : ""}: 0x${invalidCp.join(", 0x")}`);
+
+ };
+ };
+ allocateAce(cc) {
+ // Allocate active custom effect
+ // Off, cc1~cc95, CAT, velo, PB
+ if (!cc || cc > 95) {
+ console.warn(`cc${cc} cannot be allocated as an active custom effect.`);
+ return;
+ };
+ let continueScan = true, pointer = 0;
+ while (continueScan && pointer < allocated.ace) {
+ if (this.#ace[pointer] == cc) {
+ continueScan = false;
+ } else if (!this.#ace[pointer]) {
+ continueScan = false;
+ this.#ace[pointer] = cc;
+ console.info(`Allocated cc${cc} to ACE slot ${pointer}.`);
+ };
+ pointer ++;
+ };
+ if (pointer >= allocated.ace) {
+ console.warn(`ACE slots are full.`);
+ };
+ };
+ getAce() {
+ return this.#ace;
+ };
+ getChAce(part, aceSlot) {
+ // Get channel ACE value
+ if (aceSlot < 0 || aceSlot >= allocated.ace) {
+ throw(new RangeError(`No such ACE slot`));
+ };
+ let cc = this.#ace[aceSlot];
+ if (!cc) {
+ return 0;
+ } else if (ccAccepted.indexOf(cc) >= 0) {
+ return this.#cc[part * allocated.cc + ccToPos[cc]];
+ } else {
+ throw(new Error(`Invalid ACE source: ${cc}`));
+ };
+ };
+ init(type = 0) {
+ // Type 0 is full reset
+ // Type 1 is almost-full reset
+ // Full reset, except the loaded banks
+ this.dispatchEvent("mode", "?");
+ this.#mode = 0;
+ this.#subMsb = 0;
+ this.#subLsb = 0;
+ this.#metaChannel = 0;
+ this.#chActive.fill(0);
+ this.#cc.fill(0);
+ this.#ace.fill(0);
+ this.#prg.fill(0);
+ this.#velo.fill(0);
+ this.#poly.fill(0);
+ this.#rawStrength.fill(0);
+ this.#pitch.fill(0);
+ this.#nrpn.fill(0);
+ this.#drum.fill(0);
+ this.#masterVol = 100;
+ this.#metaTexts = [];
+ this.#noteLength = 500;
+ this.#convertLastSyllable = 0;
+ this.#letterExpire = 0;
+ this.#letterDisp = "";
+ this.#bitmapExpire = 0;
+ this.#bitmapPage = 0;
+ this.#bitmap.fill(0);
+ this.#modeKaraoke = false;
+ this.#selectPort = 0;
+ this.#receiveRS = true;
+ // Reset MIDI receive channel
+ this.#chReceive.forEach(function (e, i, a) {
+ a[i] = i;
+ });
+ this.buildRchTree();
+ // Reset channel redirection
+ if (type == 0) {
+ this.#trkRedir.fill(0);
+ this.#trkAsReq.fill(0);
+ };
+ // Channel 10 to drum set
+ this.#cc[allocated.cc * 9] = drumMsb[0];
+ this.#cc[allocated.cc * 25] = drumMsb[0];
+ this.#cc[allocated.cc * 41] = drumMsb[0];
+ this.#cc[allocated.cc * 57] = drumMsb[0];
+ // Channel types
+ this.#chType.fill(this.CH_MELODIC);
+ this.#chType[9] = this.CH_DRUM1;
+ this.#chType[25] = this.CH_DRUM3;
+ this.#chType[41] = this.CH_DRUMS;
+ this.#chType[57] = this.CH_DRUMS;
+ this.#chType[73] = this.CH_DRUM5;
+ this.#chType[89] = this.CH_DRUM7;
+ this.#chType[105] = this.CH_DRUMS;
+ this.#chType[121] = this.CH_DRUMS;
+ // Reset MT-32 user patch and timbre storage
+ this.#cmPatch.fill(0);
+ this.#cmTimbre.fill(0);
+ this.#cmTPatch.fill(0);
+ this.#cmTTimbre.fill(0);
+ this.#bnCustom.fill(0);
+ // Reset EFX base registers
+ this.#efxBase.fill(0);
+ // Reset AI EFX display name
+ this.aiEfxName = "";
+ // Reset MT-32 user bank
+ this.userBank.clearRange({msb: 0, lsb: 127, prg: [0, 127]});
+ for (let ch = 0; ch < allocated.ch; ch ++) {
+ let chOff = ch * allocated.cc;
+ // Reset to full
+ this.#cc[chOff + ccToPos[7]] = 100; // Volume
+ this.#cc[chOff + ccToPos[11]] = 127; // Expression
+ // Reset to centre
+ this.#cc[chOff + ccToPos[10]] = 64; // Pan
+ this.#cc[chOff + ccToPos[71]] = 64; // Resonance
+ this.#cc[chOff + ccToPos[72]] = 64; // Release Time
+ this.#cc[chOff + ccToPos[73]] = 64; // Attack Time
+ this.#cc[chOff + ccToPos[74]] = 64; // Brightness
+ this.#cc[chOff + ccToPos[75]] = 64; // Decay Time
+ this.#cc[chOff + ccToPos[76]] = 64; // Vibrato Rate
+ this.#cc[chOff + ccToPos[77]] = 64; // Vibrato Depth
+ this.#cc[chOff + ccToPos[78]] = 64; // Vibrato Delay
+ // Extra default values
+ this.#cc[chOff + ccToPos[91]] = 40; // Reverb
+ // RPN/NRPN to null
+ this.#cc[chOff + ccToPos[101]] = 127;
+ this.#cc[chOff + ccToPos[100]] = 127;
+ this.#cc[chOff + ccToPos[99]] = 127;
+ this.#cc[chOff + ccToPos[98]] = 127;
+ // RPN reset
+ let rpnOff = ch * allocated.rpn;
+ this.#rpn[rpnOff] = 2; // Pitch bend sensitivity
+ this.#rpn[rpnOff + 1] = 64; // Fine tune MSB
+ this.#rpn[rpnOff + 2] = 0; // Fine tune LSB
+ this.#rpn[rpnOff + 3] = 64; // Coarse tune MSB
+ this.#rpn[rpnOff + 4] = 0; // Mod sensitivity MSB
+ this.#rpn[rpnOff + 5] = 0; // Mod sensitivity LSB
+ // NRPN drum section reset
+ };
+ return;
+ };
+ switchMode(mode, forced = false) {
+ let idx = modeIdx.indexOf(mode);
+ if (idx > -1) {
+ if (this.#mode == 0 || forced) {
+ let oldMode = this.#mode;
+ this.#mode = idx;
+ this.#bitmapPage = 0; // Restore page
+ this.#subMsb = substList[0][idx];
+ this.#subLsb = substList[1][idx];
+ for (let ch = 0; ch < allocated.ch; ch ++) {
+ if (this.#chType[ch] > 0 && this.#cc[ch * allocated.cc + ccToPos[0]] == drumMsb[oldMode]) {
+ // Switch drum MSBs.
+ this.#cc[ch * allocated.cc] = drumMsb[idx];
+ };
+ //this.initOnReset && forced && this.#ua.ano(ch);
+ };
+ if (this.initOnReset && forced) {
+ //this.init(1);
+ };
+ // Bank defaults
+ switch (idx) {
+ case modeMap.mt32: {
+ mt32DefProg.forEach((e, i) => {
+ let ch = i + 1;
+ if (!this.#chActive[ch]) {
+ this.#prg[ch] = e;
+ this.#cc[ch * allocated.cc + ccToPos[91]] = 127;
+ };
+ });
+ break;
+ };
+ };
+ // EFX defaults
+ let efxDefault;
+ switch (idx) {
+ case modeMap.gs: {
+ efxDefault = [40, 4, 40, 18, 40, 32, 32, 0, 0, 0, 0, 0, 0, 0];
+ break;
+ };
+ case modeMap.x5d:
+ case modeMap.ns5r: {
+ efxDefault = [44, 1, 44, 19, 44, 0, 44, 0, 0, 0, 0, 0, 0, 0];
+ break;
+ };
+ default: {
+ efxDefault = [1, 0, 65, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0];
+ };
+ };
+ for (let i = 0; i < allocated.efx; i ++) {
+ if (!this.#efxBase[3 * i]) {
+ this.#efxBase[3 * i + 1] = efxDefault[2 * i];
+ this.#efxBase[3 * i + 2] = efxDefault[2 * i + 1];
+ };
+ };
+ this.dispatchEvent("mode", mode);
+ };
+ } else {
+ throw(new Error(`Unknown mode ${mode}`));
+ };
+ };
+ newStrength() {
+ this.#rawStrength.fill(0);
+ };
+ runJson(json) {
+ // Execute transformed JSON event
+ if (json.type > 14) {
+ if (json.type == 15 && json.data.constructor != Uint8Array) {
+ json.data = Uint8Array.from(json.data);
+ };
+ return this.#runChEvent[json.type].call(this, json);
+ } else {
+ // Universal MIDI channel receive support.
+ let rcvPart = this.chRedir(json.part, json.track),
+ executed = false;
+ this.#receiveTree[rcvPart]?.forEach((e) => {
+ json.channel = e;
+ executed = true;
+ this.#runChEvent[json.type].call(this, json);
+ });
+ /* this.#chReceive.forEach((e, i) => {
+ if (e == rcvPart) {
+ //json.channel = this.chRedir(i, json.track);
+ json.channel = i;
+ executed = true;
+ this.#runChEvent[json.type].call(this, json);
+ };
+ }); */
+ if (!executed) {
+ console.warn(`${eventTypes[json.type] ? eventTypes[json.type] : json.type}${[11, 12].includes(json.type) ? (json.data[0] != undefined ? json.data[0] : json.data).toString() : ""} event sent to CH${rcvPart + 1} without any recipient.`);
+ };
+ };
+ if (this.#metaTexts.length > 100) {
+ this.#metaTexts.splice(100, this.#metaTexts.length - 99);
+ };
+ };
+ runRaw(midiArr) {
+ // Translate raw byte stream into JSON MIDI event
+ };
+ async loadBank(format, blob) {
+ format = format.toLowerCase();
+ switch (format) {
+ case "s7e": {
+ this.userBank.clearRange({msb: 63, lsb: [21, 22]});
+ this.userBank.clearRange({msb: 63, lsb: [24, 27]});
+ break;
+ };
+ default: {
+ throw(new Error(`Unknown bank format ${format}`));
+ };
+ };
+ switch (format) {
+ case "s7e": {
+ bankDecoder.context = this;
+ this.userBank.load(await bankDecoder.read(format, blob));
+ break;
+ };
+ };
+ };
+ constructor() {
+ super();
+ let upThis = this;
+ this.#bitmap = new Uint8Array(256);
+ this.#bitmapStore[10] = new Uint8Array(512);
+ this.#metaSeq = new BinaryMatch();
+ this.userBank.strictMode = true;
+ // Prevent bank readers from getting stalled
+ this.userBank.load(`MSB\tPRG\tLSB\tNME\n062\t000\t000\t\n122\t000\t000\t\n122\t001\t000\t\n122\t002\t000\t\n122\t003\t000\t\n122\t004\t000\t\n122\t005\t000\t\n122\t006\t000\t`);
+ // Metadata events
+ // Should be moved to somewhere else
+ this.#metaRun[1] = function (data) {
+ // Normal text
+ switch (data.slice(0, 2)) {
+ case "@I": {
+ this.#modeKaraoke = true;
+ this.#metaTexts.unshift(`Kar.Info: ${data.slice(2)}`);
+ break;
+ };
+ case "@K": {
+ this.#modeKaraoke = true;
+ this.#metaTexts.unshift(`Karaoke mode active.`);
+ console.debug(`Karaoke mode active: ${data.slice(2)}`);
+ break;
+ };
+ case "@L": {
+ this.#modeKaraoke = true;
+ this.#metaTexts.unshift(`Language: ${data.slice(2)}`);
+ break;
+ };
+ case "@T": {
+ this.#modeKaraoke = true;
+ this.#metaTexts.unshift(`Ka.Title: ${data.slice(2)}`);
+ break;
+ };
+ case "@V": {
+ this.#modeKaraoke = true;
+ this.#metaTexts.unshift(`Kara.Ver: ${data.slice(2)}`);
+ break;
+ };
+ case "XF": {
+ // XG File Data section
+ let dataArr = data.slice(2).split(":");
+ switch (dataArr[0]) {
+ case "hd": {
+ dataArr.slice(1).forEach((e, i) => {
+ e.length && this.#metaTexts.unshift(`${[
+ "SongDate", "SnRegion", "SongCat.", "SongBeat",
+ "SongInst", "Sn.Vocal", "SongCmp.", "SongLrc.",
+ "SongArr.", "SongPerf", "SongPrg.", "SongTags"
+ ][i]}: ${e}`);
+ });
+ break;
+ };
+ case "ln": {
+ dataArr.slice(1).forEach((e, i) => {
+ e.length && this.#metaTexts.unshift(`${[
+ "Kar.Lang", "Kar.Name", "Kar.Cmp.", "Kar.Lrc.",
+ "kar.Arr.", "Kar.Perf", "Kar.Prg."
+ ][i]}: ${e}`);
+ });
+ break;
+ };
+ default: {
+ this.#metaTexts.unshift(`XGF_Data: ${data}`);
+ };
+ };
+ break;
+ };
+ default: {
+ if (this.#modeKaraoke) {
+ if (data[0] == "\\") {
+ // New section
+ this.#metaTexts.unshift(`@ ${data.slice(1)}`);
+ } else if (data[0] == "/") {
+ // New line
+ this.#metaTexts.unshift(data.slice(1));
+ } else {
+ // Normal append
+ this.#metaTexts[0] += data;
+ };
+ } else {
+ this.#metaTexts[0] = data;
+ this.#metaTexts.unshift("");
+ };
+ };
+ };
+ };
+ this.#metaRun[2] = function (data) {
+ this.#metaTexts.unshift(`Copyrite: ${data}`);
+ };
+ this.#metaRun[3] = function (data, track) {
+ // Filter overly annoying meta events
+ if (track < 1 && this.#metaChannel < 1) {
+ this.#metaTexts.unshift(`TrkTitle: ${data}`);
+ };
+ };
+ this.#metaRun[4] = function (data, track) {
+ //if (track < 1 && this.#metaChannel < 1) {
+ this.#metaTexts.unshift(`${showTrue(this.#metaChannel, "", " ")}Instrmnt: ${data}`);
+ //};
+ };
+ this.#metaRun[5] = function (data) {
+ if (data.trim() == "") {
+ this.#metaTexts.unshift("");
+ } else {
+ this.#metaTexts[0] += `${data}`;
+ };
+ };
+ this.#metaRun[6] = function (data) {
+ this.#metaTexts.unshift(`${showTrue(this.#metaChannel, "", " ")}C.Marker: ${data}`);
+ };
+ this.#metaRun[7] = function (data) {
+ this.#metaTexts.unshift(`CuePoint: ${data}`);
+ };
+ this.#metaRun[32] = function (data) {
+ this.#metaChannel = data[0] + 1;
+ };
+ this.#metaRun[33] = function (data, track) {
+ console.debug(`Track ${track} requests to get assigned to output ${data}.`);
+ upThis.#trkAsReq[track] = data + 1;
+ };
+ this.#metaRun[81] = function (data, track) {
+ upThis.#noteLength = data / 1000;
+ };
+ this.#metaRun[127] = function (data, track) {
+ //console.debug(`Sequencer specific on track ${track}: `, data);
+ upThis.#metaSeq.run(data, track);
+ };
+ // Sequencer specific meta event
+ // No refactoring needed.
+ this.#metaSeq.default = function (seq) {
+ console.warn(`Unrecognized sequencer-specific byte sequence: ${seq}`);
+ };
+ this.#metaSeq.add([67, 0, 1], function (msg, track) {
+ //console.debug(`XGworks requests assigning track ${track} to output ${msg[0]}.`);
+ upThis.#trkAsReq[track] = msg[0] + 1;
+ });
+ // Binary match should be avoided in favour of a circular structure
+ this.#seUnr = new BinaryMatch("universal non-realtime");
+ this.#seUr = new BinaryMatch("universal realtime");
+ this.#seXg = new BinaryMatch("Yamaha");
+ this.#seGs = new BinaryMatch("Roland");
+ this.#seAi = new BinaryMatch("Korg");
+ this.#seKg = new BinaryMatch("Kawai");
+ this.#seSg = new BinaryMatch("Akai");
+ this.#seCs = new BinaryMatch("Casio");
+ // Notifies unrecognized SysEx strings with their vendors
+ let syxDefaultErr = function (msg) {
+ console.info(`Unrecognized SysEx in "${this.name}" set.`, msg);
+ };
+ this.#seUnr.default = syxDefaultErr;
+ this.#seUr.default = syxDefaultErr;
+ this.#seXg.default = syxDefaultErr;
+ this.#seGs.default = syxDefaultErr;
+ this.#seAi.default = syxDefaultErr;
+ this.#seKg.default = syxDefaultErr;
+ this.#seSg.default = syxDefaultErr;
+ this.#seCs.default = syxDefaultErr;
+ // The new SysEx engine only defines actions when absolutely needed.
+ // Mode reset section
+ this.#seUnr.add([9], (msg) => {
+ // General MIDI reset.
+ upThis.switchMode(["gm", "?", "g2"][msg[0] - 1], true);
+ upThis.#modeKaraoke = upThis.#modeKaraoke || false;
+ console.info(`MIDI reset: ${["GM", "Init", "GM2"][msg[0] - 1]}`);
+ if (msg[0] == 2) {
+ upThis.init();
+ };
+ });
+ // GM SysEx section
+ this.#seUr.add([4, 1], (msg) => {
+ // Master volume
+ upThis.#masterVol = ((msg[1] << 7) + msg[0]) / 16383 * 100;
+ }).add([4, 3], (msg) => {
+ // Master fine tune
+ return (((msg[1] << 7) + msg[0] - 8192) / 8192);
+ }).add([4, 4], (msg) => {
+ // Master coarse tune
+ return (msg[1] - 64);
+ });
+ // XG SysEx section
+ this.#seXg.add([76, 0, 0], (msg) => {
+ switch (msg[0]) {
+ case 125: {
+ // XG drum reset
+ console.info(`XG drum setup reset: ${msg}`);
+ break;
+ };
+ case 126: {
+ // Yamaha XG reset
+ upThis.switchMode("xg", true);
+ upThis.#modeKaraoke = false;
+ console.info("MIDI reset: XG");
+ break;
+ };
+ default: {
+ let mTune = [0, 0, 0, 0];
+ let writeTune = (e, i) => {
+ // XG master fine tune
+ mTune[i] = e;
+ };
+ msg.subarray(1).forEach((e, i) => {
+ let addr = i + msg[0];
+ ([
+ writeTune, writeTune, writeTune, writeTune,
+ (e) => {
+ // XG master volume
+ this.#masterVol = e * 129 / 16383 * 100;
+ },
+ (e) => {/* XG master attenuator */},
+ (e) => {/* XG master coarse tune */}
+ ][addr] || (() => {}))(e, i);
+ });
+ if (msg[0] < 4) {
+ // Commit master tune
+ let rTune = 0;
+ mTune.forEach((e) => {
+ rTune = rTune << 4;
+ rTune += e;
+ });
+ rTune -= 1024;
+ };
+ };
+ };
+ }).add([76, 2, 1], (msg) => {
+ // XG reverb, chorus and variation
+ let dPref = "XG ";
+ if (msg[0] < 32) {
+ // XG reverb
+ dPref += "reverb ";
+ msg.subarray(1).forEach((e, i) => {
+ ([(e) => {
+ upThis.setEffectTypeRaw(0, false, e);
+ console.info(`${dPref}main type: ${xgEffType[e]}`);
+ }, (e) => {
+ upThis.setEffectTypeRaw(0, true, e);
+ console.debug(`${dPref}sub type: ${e + 1}`);
+ }, (e) => {
+ console.debug(`${dPref}time: ${getXgRevTime(e)}s`);
+ }, (e) => {
+ console.debug(`${dPref}diffusion: ${e}`);
+ }, (e) => {
+ console.debug(`${dPref}initial delay: ${e}`);
+ }, (e) => {
+ console.debug(`${dPref}HPF cutoff: ${xgNormFreq[e]}Hz`);
+ }, (e) => {
+ console.debug(`${dPref}LPF cutoff: ${xgNormFreq[e]}Hz`);
+ }, (e) => {
+ console.debug(`${dPref}width: ${e}`);
+ }, (e) => {
+ console.debug(`${dPref}height: ${e}`);
+ }, (e) => {
+ console.debug(`${dPref}depth: ${e}`);
+ }, (e) => {
+ console.debug(`${dPref}wall type: ${e}`);
+ }, (e) => {
+ console.debug(`${dPref}dry/wet: ${e}`);
+ }, (e) => {
+ console.debug(`${dPref}send: ${toDecibel(e)}dB`);
+ }, (e) => {
+ console.debug(`${dPref}pan: ${e - 64}`);
+ }, false, false, (e) => {
+ console.debug(`${dPref}delay: ${e}`);
+ }, (e) => {
+ console.debug(`${dPref}density: ${e}`);
+ }, (e) => {
+ console.debug(`${dPref}balance: ${e}`);
+ }, (e) => {
+ }, (e) => {
+ console.debug(`${dPref}feedback: ${e}`);
+ }, (e) => {
+ }][msg[0] + i] || function () {
+ console.warn(`Unknown XG reverb address: ${msg[0]}.`);
+ })(e);
+ });
+ } else if (msg[0] < 64) {
+ // XG chorus
+ dPref += "chorus ";
+ msg.subarray(1).forEach((e, i) => {
+ ([(e) => {
+ upThis.setEffectTypeRaw(1, false, e);
+ console.info(`${dPref}main type: ${xgEffType[e]}`);
+ }, (e) => {
+ upThis.setEffectTypeRaw(1, true, e);
+ console.debug(`${dPref}sub type: ${e + 1}`);
+ }, (e) => {
+ console.debug(`${dPref}LFO: ${xgLfoFreq[e]}Hz`);
+ }, (e) => {
+ //console.debug(`${dPref}LFO phase: ${e}`);
+ }, (e) => {
+ console.debug(`${dPref}feedback: ${e}`);
+ }, (e) => {
+ console.debug(`${dPref}delay offset: ${getXgDelayOffset(e)}ms`);
+ }, (e) => {
+ }, (e) => {
+ console.debug(`${dPref}low: ${xgNormFreq[e]}Hz`);
+ }, (e) => {
+ console.debug(`${dPref}low: ${e - 64}dB`);
+ }, (e) => {
+ console.debug(`${dPref}high: ${xgNormFreq[e]}Hz`);
+ }, (e) => {
+ console.debug(`${dPref}high: ${e - 64}dB`);
+ }, (e) => {
+ console.debug(`${dPref}dry/wet: ${e}`);
+ }, (e) => {
+ console.debug(`${dPref}send: ${toDecibel(e)}dB`);
+ }, (e) => {
+ console.debug(`${dPref}pan: ${e - 64}`);
+ }, (e) => {
+ console.debug(`${dPref}to reverb: ${toDecibel(e)}dB`);
+ }, false, (e) => {
+ }, (e) => {
+ }, (e) => {
+ }, (e) => {
+ console.debug(`${dPref}LFO phase diff: ${(e - 64) * 3}deg`);
+ }, (e) => {
+ console.debug(`${dPref}input mode: ${e ? "stereo" : "mono"}`);
+ }, (e) => {
+ }][msg[0] - 32 + i] || function () {
+ console.warn(`Unknown XG chorus address: ${msg[0]}.`);
+ })(e);
+ });
+ } else if (msg[0] < 86) {
+ // XG variation section 1
+ dPref += "variation ";
+ msg.subarray(1).forEach((e, i) => {
+ ([(e) => {
+ upThis.setEffectTypeRaw(2, false, e);
+ console.info(`${dPref}main type: ${xgEffType[e]}`);
+ }, (e) => {
+ upThis.setEffectTypeRaw(2, true, e);
+ console.debug(`${dPref}sub type: ${e + 1}`);
+ }][msg[0] - 64 + i] || function () {
+ //console.warn(`Unknown XG variation address: ${msg[0]}.`);
+ })(e);
+ });
+ } else if (msg[0] < 97) {
+ // XG variation section 2
+ dPref += "variation ";
+ msg.subarray(1).forEach((e, i) => {
+ ([(e) => {
+ console.debug(`${dPref}send: ${toDecibel(e)}dB`);
+ }, (e) => {
+ console.debug(`${dPref}pan: ${e - 64}`);
+ }, (e) => {
+ console.debug(`${dPref}to reverb: ${toDecibel(e)}dB`);
+ }, (e) => {
+ console.debug(`${dPref}to chorus: ${toDecibel(e)}dB`);
+ }, (e) => {
+ console.debug(`${dPref}connection: ${e ? "system" : "insertion"}`);
+ }, (e) => {
+ console.debug(`${dPref}channel: CH${e + 1}`);
+ }, (e) => {
+ console.debug(`${dPref}mod wheel: ${e - 64}`);
+ }, (e) => {
+ console.debug(`${dPref}bend wheel: ${e - 64}`);
+ }, (e) => {
+ console.debug(`${dPref}channel after touch: ${e - 64}`);
+ }, (e) => {
+ console.debug(`${dPref}AC1: ${e - 64}`);
+ }, (e) => {
+ console.debug(`${dPref}AC2: ${e - 64}`);
+ }][msg[0] - 86 + i])(e);
+ });
+ } else if (msg[0] > 111 && msg[0] < 118) {
+ // XG variation section 3
+ dPref += "variation ";
+ } else {
+ console.warn(`Unknown XG variation address: ${msg[0]}`);
+ };
+ }).add([76, 2, 64], (msg) => {
+ // XG 5-part EQ
+ msg.subarray(1).forEach((e, i) => {
+ let c = i + msg[0];
+ if (c == 0) {
+ console.debug(`XG EQ preset: ${["flat", "jazz", "pop", "rock", "classic"][e]}`);
+ } else {
+ let band = (c - 1) >> 2,
+ prop = (c - 1) & 3,
+ dPref = `XG EQ ${band} ${["gain", "freq", "Q", "shape"][prop]}: `;
+ [() => {
+ console.debug(`${dPref}${e - 64}dB`);
+ }, () => {
+ console.debug(`${dPref}${e} (raw)`); // HELP WANTED
+ }, () => {
+ console.debug(`${dPref}${e / 10}`);
+ }, () => {
+ console.debug(`${dPref}${["shelf", "peak"][+!!e]}`);
+ }][prop]();
+ };
+ });
+ }).add([76, 3], (msg) => {
+ // XG insertion effects
+ let varSlot = msg[0], offset = msg[1];
+ let dPref = `XG Insertion ${msg[0] + 1} `;
+ msg.subarray(2).forEach((e, i) => {
+ ([(e) => {
+ upThis.setEffectTypeRaw(3 + varSlot, false, e);
+ console.info(`${dPref}main type: ${xgEffType[e]}`);
+ }, (e) => {
+ upThis.setEffectTypeRaw(3 + varSlot, true, e);
+ console.debug(`${dPref}sub type: ${e + 1}`);
+ }][offset + i] || function () {
+ //console.warn(`Unknown XG variation address: ${msg[0]}.`);
+ })(e);
+ });
+ }).add([76, 6, 0], (msg) => {
+ // XG Letter Display
+ let offset = msg[0];
+ if (offset < 64) {
+ upThis.setLetterDisplay(msg.subarray(1), "XG letter display", offset);
+ } else {
+ // Expire all existing letter display
+ upThis.#letterExpire = Date.now();
+ };
+ }).add([76, 7, 0], (msg) => {
+ // XG Bitmap Display
+ let offset = msg[0];
+ upThis.#bitmapPage = 0;
+ upThis.#bitmapExpire = Date.now() + 3200;
+ upThis.#bitmap.fill(0); // Init
+ let workArr = msg.subarray(1);
+ for (let index = 0; index < offset; index ++) {
+ workArr.unshift(0);
+ };
+ workArr.forEach(function (e, i) {
+ let ln = Math.floor(i / 16), co = i % 16;
+ let pt = (co * 3 + ln) * 7, threshold = 7, bi = 0;
+ pt -= co * 5;
+ if (ln == 2) {
+ threshold = 2;
+ };
+ while (bi < threshold) {
+ upThis.#bitmap[pt + bi] = (e >> (6 - bi)) & 1;
+ bi ++;
+ };
+ });
+ }).add([76, 8], (msg, track) => {
+ // XG part setup
+ let part = upThis.chRedir(msg[0], track, true),
+ id = msg[1],
+ chOff = allocated.cc * part,
+ dPref = `XG CH${part + 1} `,
+ errMsg = `Unknown XG part address ${id}.`;
+ msg.subarray(2).forEach((e, i) => {
+ // There is a bug here, but I don't have time right now
+ if (id < 1) {
+ console.debug(errMsg);
+ } else if (id < 41) {
+ // CC manipulation can be further shrunk
+ ([() => {
+ upThis.#cc[chOff + ccToPos[0]] = e; // MSB
+ }, () => {
+ upThis.#cc[chOff + ccToPos[32]] = e; // LSB
+ }, () => {
+ upThis.#prg[part] = e; // program
+ }, () => {
+ let ch = upThis.chRedir(e, track, true);
+ upThis.#chReceive[part] = ch; // Rx CH
+ if (part != ch) {
+ upThis.buildRchTree();
+ console.info(`${dPref}receives from CH${ch + 1}`);
+ };
+ }, () => {
+ upThis.#mono[part] = +!e; // mono/poly
+ }, () => {
+ // same note key on assign?
+ }, () => {
+ upThis.setChType(part, e, modeMap.xg);
+ console.debug(`${dPref}type: ${xgPartMode[e] || e}`);
+ }, () => {
+ // coarse tune
+ upThis.#rpn[allocated.rpn * part + 3] = e;
+ }, false, false, () => {
+ upThis.#cc[chOff + ccToPos[7]] = e; // volume
+ }, false, false, () => {
+ upThis.#cc[chOff + ccToPos[10]] = e || 128; // pan
+ }, false, false, () => {
+ upThis.#cc[chOff + ccToPos[128]] = e; // dry level
+ }, () => {
+ upThis.#cc[chOff + ccToPos[93]] = e; // chorus
+ }, () => {
+ upThis.#cc[chOff + ccToPos[91]] = e; // reverb
+ }, () => {
+ upThis.#cc[chOff + ccToPos[94]] = e; // variation
+ }, () => {
+ upThis.#cc[chOff + ccToPos[76]] = e; // vib rate
+ }, () => {
+ upThis.#cc[chOff + ccToPos[77]] = e; // vib depth
+ }, () => {
+ upThis.#cc[chOff + ccToPos[78]] = e; // vib delay
+ }, () => {
+ upThis.#cc[chOff + ccToPos[74]] = e; // brightness
+ }, () => {
+ upThis.#cc[chOff + ccToPos[71]] = e; // resonance
+ }, () => {
+ upThis.#cc[chOff + ccToPos[73]] = e; // attack
+ }, () => {
+ upThis.#cc[chOff + ccToPos[75]] = e; // decay
+ }, () => {
+ upThis.#cc[chOff + ccToPos[72]] = e; // release
+ }][id + i - 1] || (() => {}))();
+ } else if (id < 48) {
+ console.debug(errMsg);
+ } else if (id < 111) {
+ if (id > 102 && id < 105) {
+ upThis.#cc[chOff + ccToPos[[5, 65][id & 1]]] = e; // portamento
+ };
+ } else if (id < 114) {
+ console.debug(errMsg);
+ } else if (id < 116) {
+ console.debug(`${dPref}EQ ${["bass", "treble"][id & 1]} gain: ${e - 64}dB`);
+ } else if (id < 118) {
+ console.debug(errMsg);
+ } else if (id < 120) {
+ console.debug(`${dPref}EQ ${["bass", "treble"][id & 1]} freq: ${e}`);
+ } else {
+ console.debug(errMsg);
+ };
+ });
+ }).add([76, 9], (msg, track) => {
+ // PLG-150VL Part Setup
+ let part = upThis.chRedir(msg[0], track, true),
+ id = msg[1];
+ let dPref = `PLG-150VL CH${part + 1} `;
+ msg.subarray(2).forEach((e, i) => {
+ let ri = i + id;
+ switch (ri) {
+ case 1: {
+ console.info(`${dPref}breath mode: ${["system", "breath", "velocity", "touch EG"][e]}`);
+ break;
+ };
+ case 0:
+ case 27:
+ case 28: {
+ break;
+ };
+ default: {
+ if (ri < 27) {
+ let pType = [
+ "pressure",
+ "embouchure",
+ "tonguing",
+ "scream",
+ "breath noise",
+ "growl",
+ "throat formant",
+ "harmonic enhancer",
+ "damping",
+ "absorption",
+ "amplification",
+ "brightness"
+ ][(ri - 3) >> 1];
+ if (ri & 1) {
+ if (ri < 23) {
+ console.debug(`${dPref}${pType} control source: ${getVlCtrlSrc(e)}`);
+ if (e && e < 96) {
+ upThis.allocateAce(e);
+ };
+ } else {
+ // These actually belong to 0x57, not 0x4c
+ console.debug(`${dPref}${pType} scale break point: ${e}`);
+ };
+ } else {
+ console.debug(`${dPref}${pType} depth: ${e - 64}`);
+ };
+ };
+ };
+ };
+ });
+ }).add([76, 10], (msg) => {
+ // XG HPF cutoff at 76, 10, nn, 32
+ // Won't implement for now
+ }).add([76, 16], (msg) => {
+ // XG A/D part, won't implement for now
+ }).add([76, 17, 0, 0], (msg) => {
+ // XG A/D mono/stereo mode, won't implement for now
+ }).add([76, 112], (msg) => {
+ // XG plugin board generic
+ console.debug(`XG enable PLG-1${["50VL", "00SG", "50DX"][msg[0]]} for CH${msg[2] + 1}.`);
+ }).add([73, 0, 0], (msg, track) => {
+ // MU1000/2000 System
+ let offset = msg[0];
+ msg.subarray(1).forEach((e, i) => {
+ let ri = offset + i;
+ if (ri == 8) {
+ console.debug(`MU1000 set LCD contrast to ${e}.`);
+ } else if (ri > 9 && ri < 16) {
+ // Octavia custom SysEx
+ [() => {
+ upThis.dispatchEvent("channelactive", e);
+ }, () => {
+ if (e < 8) {
+ upThis.dispatchEvent("channelmin", (e << 4));
+ console.info(`Octavia System: Minimum CH${(e << 4) + 1}`);
+ } else {
+ upThis.dispatchEvent("channelreset");
+ console.info(`Octavia System: Clear channel ranges`);
+ };
+ }, () => {
+ if (e < 8) {
+ upThis.dispatchEvent("channelmax", (e << 4) + 15);
+ console.info(`Octavia System: Maximum CH${(e << 4) + 16}`);
+ } else {
+ upThis.dispatchEvent("channelreset");
+ console.info(`Octavia System: Clear channel ranges`);
+ };
+ }, () => {
+ upThis.dispatchEvent("channelreset");
+ console.info(`Octavia System: Clear channel ranges`);
+ }, () => {
+ upThis.#receiveRS = !!e;
+ console.info(`Octavia System: RS receiving ${["dis", "en"][e]}abled.`);
+ }][ri - 10]();
+ };
+ });
+ }).add([73, 10, 0], (msg, track) => {
+ // MU1000 remote switch
+ // But in practice... They are channel switching commands.
+ let cmd = msg[0];
+ let dPref = `MU1000 RS${upThis.#receiveRS ? "" : " (ignored)"}: `;
+ if (cmd < 16) {
+ switch (cmd) {
+ case 2: {
+ // Show all 64 channels
+ let e = upThis.chRedir(0, track, true);
+ if (upThis.#receiveRS) {
+ upThis.dispatchEvent("channelmin", e);
+ upThis.dispatchEvent("channelmax", e + 63);
+ };
+ console.info(`${dPref}Show CH1~64`);
+ break;
+ };
+ case 3: {
+ // Show 32 channels
+ let e = upThis.chRedir(msg[1] << 5, track, true);
+ upThis.#receiveRS && upThis.dispatchEvent("channelmin", e);
+ upThis.#receiveRS && upThis.dispatchEvent("channelmax", e + 31);
+ console.info(`${dPref}Show CH${e + 1}~CH${e + 32}`);
+ break;
+ };
+ default: {
+ console.debug(`${dPref}unknown switch ${cmd} invoked.`);
+ };
+ };
+ } else if (cmd < 32) {
+ if (upThis.#receiveRS) {
+ let e = upThis.chRedir(cmd - 16 + (upThis.#selectPort << 4), track, true);
+ upThis.dispatchEvent("channelactive", e);
+ };
+ } else if (cmd < 36) {
+ let e = upThis.chRedir((cmd - 32) << 4, track, true);
+ if (upThis.#receiveRS) {
+ upThis.dispatchEvent("channelmin", e);
+ upThis.dispatchEvent("channelmax", e + 15);
+ upThis.#selectPort = cmd - 32;
+ };
+ console.info(`${dPref}Show CH${e + 1}~CH${e + 16}`);
+ };
+ }).add([93, 3], (msg, track) => {
+ // PLG-100SG singing voice
+ let part = upThis.chRedir(msg[0], track, true),
+ dPref = `PLG-100SG CH${part + 1} `,
+ timeNow = Date.now();
+ if (msg[1] == 0) {
+ // Vocal information
+ let vocal = "",
+ length = 0;
+ msg.subarray(2).forEach((e, i) => {
+ if (i % 2 == 0) {
+ vocal += xgSgVocals[e] || e.toString().padStart("0");
+ } else {
+ length += e * 13; // 7.5ms
+ };
+ });
+ if (timeNow >= upThis.#convertLastSyllable) {
+ upThis.#metaTexts.unshift("SG Lyric: ");
+ };
+ upThis.#metaTexts[0] += `${getSgKana(vocal)}`;
+ upThis.#convertLastSyllable = timeNow + Math.ceil(length / 2) + upThis.#noteLength;
+ if (getDebugState()) {
+ console.debug(`${dPref}vocals: ${vocal}`);
+ };
+ } else {
+ console.warn(`Unknown PLG-100SG data: ${msg}`);
+ };
+ });
+ this.#seXg.add([76, 48], (msg) => {
+ // XG drum setup 1
+ }).add([76, 49], (msg) => {
+ // XG drum setup 2
+ }).add([76, 50], (msg) => {
+ // XG drum setup 3
+ }).add([76, 51], (msg) => {
+ // XG drum setup 4
+ });
+ // MU1000/2000 EPROM write
+ this.#seXg.add([89, 0], (msg, track, id) => {
+ // EPROM trail write
+ if (upThis.eprom) {
+ let length = msg[0];
+ let addr = (msg[1] << 14) + (msg[2] << 7) + msg[3] + (upThis.eprom.offset || 0);
+ getDebugState() && console.debug(`MU1000 EPROM trail to 0x${addr.toString(16).padStart(6, "0")}, ${length} bytes.`);
+ let target = upThis.eprom.data;
+ msg.subarray(4).forEach((e, i) => {
+ // Overlay decoding
+ let secId = i >> 3, secIdx = i & 7;
+ if (secIdx == 7) {
+ for (let bi = 0; bi < 7; bi ++) {
+ target[addr + 7 * secId + bi] += ((e >> (6 - bi)) & 1) << 7;
+ };
+ } else {
+ target[addr + 7 * secId + secIdx] = e;
+ };
+ });
+ };
+ }).add([89, 1], (msg, track, id) => {
+ // EPROM base pointer jump
+ let addr = (msg[0] << 21) + (msg[1] << 14) + (msg[2] << 7) + msg[3];
+ getDebugState() && console.debug(`MU1000 EPROM jump to 0x${addr.toString(16).padStart(6, "0")}.`);
+ if (upThis.eprom) {
+ upThis.eprom.offset = addr;
+ };
+ }).add([89, 2], (msg, track, id) => {
+ // EPROM bulk write
+ // The first byte always seem to be zero
+ if (upThis.eprom) {
+ let addr = (msg[0] << 21) + (msg[1] << 14) + (msg[2] << 7) + msg[3] + (upThis.eprom.offset || 0);
+ getDebugState() && console.debug(`MU1000 EPROM write to 0x${addr.toString(16).padStart(6, "0")}.`);
+ let target = upThis.eprom.data;
+ msg.subarray(4).forEach((e, i) => {
+ // Overlay decoding
+ let secId = i >> 3, secIdx = i & 7;
+ if (secIdx == 7) {
+ for (let bi = 0; bi < 7; bi ++) {
+ target[addr + 7 * secId + bi] += ((e >> (6 - bi)) & 1) << 7;
+ };
+ } else {
+ target[addr + 7 * secId + secIdx] = e;
+ };
+ });
+ };
+ }).add([89, 3], (msg, track, id) => {
+ // Unknown instruction
+ });
+ // XG drum setup would be blank for now
+ // TG300 SysEx section, the parent of XG
+ this.#seXg.add([39, 48], (msg, track, id) => {
+ // TG100 pool
+ }).add([43, 0, 0], (msg, track, id) => {
+ // TG300 master setup
+ let mTune = [0, 0, 0, 0];
+ let writeTune = (e, i) => {
+ // GS master fine tune
+ mTune[i] = e;
+ };
+ msg.subarray(1).forEach((e, i) => {
+ let addr = i + msg[0];
+ ([
+ writeTune,
+ writeTune,
+ writeTune,
+ writeTune,
+ () => {
+ this.#masterVol = e * 129 / 16383 * 100;
+ },
+ () => {
+ return e - 64;
+ },
+ () => {
+ return e || 128;
+ },
+ () => {
+ return e;
+ },
+ () => {
+ return e;
+ },
+ () => {
+ console.debug(`TG300 variation on cc${e}.`);
+ }
+ ] || (() => {}))[addr](e, addr);
+ });
+ if (msg[0] < 4) {
+ // Commit master tune
+ let rTune = 0;
+ mTune.forEach((e) => {
+ rTune = rTune << 4;
+ rTune += e;
+ });
+ rTune -= 1024;
+ };
+ }).add([43, 1, 0], (msg, track, id) => {
+ // TG300 effect (R C V) setup
+ }).add([43, 2], (msg, track, id) => {
+ // TG300 part setup
+ let part = upThis.chRedir(msg[0], track, true);
+ let offset = msg[1];
+ let chOff = allocated.cc * part;
+ let dPref = `TG300 CH${part + 1} `;
+ msg.subarray(2).forEach((e, i) => {
+ if (i < 5) {
+ ([() => {
+ // element reserve
+ }, () => {
+ upThis.#cc[chOff + ccToPos[0]] = e;
+ }, () => {
+ upThis.#cc[chOff + ccToPos[32]] = e;
+ }, () => {
+ upThis.#prg[part] = e;
+ }, () => {
+ let ch = upThis.chRedir(e, track, true);
+ upThis.#chReceive[part] = ch; // Rx CH
+ if (part != ch) {
+ upThis.buildRchTree();
+ console.info(`${dPref}receives from CH${ch + 1}`);
+ };
+ }][i + offset] || (() => {}))(e, i + offset);
+ } else if (i < 21) {} else if (i < 47) {
+ ([() => {
+ upThis.#mono[part] = +!e;
+ }, () => {
+ // same key on assign
+ }, () => {
+ // part mode
+ }, () => {
+ // coarse tune
+ upThis.#rpn[allocated.rpn * part + 3] = e;
+ }, () => {
+ // absolute detune
+ }, () => {
+ upThis.#cc[chOff + ccToPos[7]] = e;
+ }, false
+ , false
+ , () => {
+ upThis.#cc[chOff + ccToPos[10]] = e || 128;
+ }, false
+ , false
+ , () => {
+ console.debug(`${dPref} AC1 at cc${e}`);
+ }, () => {
+ console.debug(`${dPref} AC2 at cc${e}`);
+ }, () => {
+ // Dry level
+ upThis.#cc[chOff + ccToPos[128]] = e;
+ }, () => {
+ upThis.#cc[chOff + ccToPos[93]] = e;
+ }, () => {
+ upThis.#cc[chOff + ccToPos[91]] = e;
+ }, () => {
+ upThis.#cc[chOff + ccToPos[94]] = e;
+ }, () => {
+ upThis.#cc[chOff + ccToPos[76]] = e;
+ }, () => {
+ upThis.#cc[chOff + ccToPos[77]] = e;
+ }, () => {
+ upThis.#cc[chOff + ccToPos[74]] = e;
+ }, () => {
+ upThis.#cc[chOff + ccToPos[71]] = e;
+ }, () => {
+ upThis.#cc[chOff + ccToPos[73]] = e;
+ }, () => {
+ upThis.#cc[chOff + ccToPos[75]] = e;
+ }, () => {
+ upThis.#cc[chOff + ccToPos[72]] = e;
+ }, () => {
+ upThis.#cc[chOff + ccToPos[78]] = e;
+ }][i + offset - 21] || (() => {}))(e, i + offset);
+ } else if (i < 95) {} else {
+ ([() => {
+ upThis.#cc[chOff + ccToPos[65]] = e;
+ }, () => {
+ upThis.#cc[chOff + ccToPos[5]] = e;
+ }][i + offset - 95] || (() => {}))(e, i + offset);
+ };
+ });
+ }).add([43, 7, 0], (msg, track, id) => {
+ // TG300 display letter
+ // Same as XG letter display
+ let offset = msg[0];
+ upThis.setLetterDisplay(msg.subarray(1), "TG300 letter display", offset);
+ }).add([43, 7, 1], (msg, track, id) => {
+ // TG300 display bitmap
+ // Same as XG bitmap display
+ upThis.#bitmapPage = 0;
+ upThis.#bitmapExpire = Date.now() + 3200;
+ upThis.#bitmap.fill(0); // Init
+ msg.forEach(function (e, i) {
+ let ln = Math.floor(i / 16), co = i % 16;
+ let pt = (co * 3 + ln) * 7, threshold = 7, bi = 0;
+ pt -= co * 5;
+ if (ln == 2) {
+ threshold = 2;
+ };
+ while (bi < threshold) {
+ upThis.#bitmap[pt + bi] = (e >> (6 - bi)) & 1;
+ bi ++;
+ };
+ });
+ });
+ // TG drum setup would also be blank
+ // GS SysEx section
+ this.#seGs.add([66, 18, 0, 0, 127], (msg, track, id) => {
+ // GS mode set
+ upThis.switchMode("gs", true);
+ upThis.#cc[allocated.cc * 9] = 120;
+ upThis.#cc[allocated.cc * 25] = 120;
+ upThis.#cc[allocated.cc * 41] = 120;
+ upThis.#cc[allocated.cc * 57] = 120;
+ upThis.#subLsb = 3; // Use SC-88 Pro map by default
+ upThis.#modeKaraoke = false;
+ upThis.#trkRedir.fill(0);
+ console.info(`GS system to ${["single", "dual"][msg[0]]} mode.`);
+ }).add([66, 18, 64, 0], (msg, track, id) => {
+ switch (msg[0]) {
+ case 127: {
+ // Roland GS reset
+ upThis.switchMode("gs", true);
+ upThis.#cc[allocated.cc * 9] = 120;
+ upThis.#cc[allocated.cc * 25] = 120;
+ upThis.#cc[allocated.cc * 41] = 120;
+ upThis.#cc[allocated.cc * 57] = 120;
+ upThis.#modeKaraoke = false;
+ upThis.#trkRedir.fill(0);
+ console.info("MIDI reset: GS");
+ break;
+ };
+ default: {
+ let mTune = [0, 0, 0, 0];
+ let writeTune = (e, i) => {
+ // GS master fine tune
+ mTune[i] = e;
+ };
+ msg.subarray(1).forEach((e, i) => {
+ let addr = i + msg[0];
+ [
+ writeTune, writeTune, writeTune, writeTune,
+ (e) => {
+ // XG master volume
+ this.#masterVol = e * 129 / 16383 * 100;
+ },
+ (e) => {/* XG master coarse tune */},
+ (e) => {/* XG master pan */}
+ ][addr](e, i);
+ });
+ if (msg[0] < 4) {
+ // Commit master tune
+ let rTune = 0;
+ mTune.forEach((e) => {
+ rTune = rTune << 4;
+ rTune += e;
+ });
+ rTune -= 1024;
+ };
+ };
+ };
+ }).add([66, 18, 64, 1], (msg) => {
+ // GS patch params
+ let offset = msg[0];
+ if (offset < 16) {
+ // GS patch name (what for?)
+ let string = "".padStart(offset, " ");
+ msg.subarray(1).forEach((e, i) => {
+ string += String.fromCharCode(Math.max(32, e));
+ });
+ string = string.padEnd(16, " ");
+ console.debug(`GS patch name: ${string}`);
+ } else if (offset < 48) {
+ // GS partial reserve
+ } else if (offset < 65) {
+ // GS reverb and chorus
+ msg.subarray(1).forEach((e, i) => {
+ let dPref = `GS ${(offset + i) > 55 ? "chorus" : "reverb"} `;
+ ([() => {
+ console.info(`${dPref}type: ${gsRevType[e]}`);
+ upThis.setEffectType(0, 40, e);
+ }, () => {// character
+ }, () => {// pre-LPF
+ }, () => {// level
+ }, () => {// time
+ }, () => {// delay feedback
+ }, false, () => {
+ console.debug(`${dPref}predelay: ${e}ms`);
+ }, () => {
+ console.info(`${dPref}type: ${gsChoType[e]}`);
+ upThis.setEffectType(1, 40, 16 + e);
+ }, () => {// pre-LPF
+ }, () => {// level
+ }, () => {// feedback
+ }, () => {// delay
+ }, () => {// rate
+ }, () => {// depth
+ }, () => {
+ console.debug(`${dPref}to reverb: ${toDecibel(e)}`);
+ }, () => {
+ console.debug(`${dPref}to delay: ${toDecibel(e)}`);
+ }][offset + i - 48] || (() => {}))();
+ });
+ } else if (offset < 80) {
+ console.debug(`Unknown GS patch address: ${offset}`);
+ } else if (offset < 91) {
+ // GS delay
+ msg.subarray(1).forEach((e, i) => {
+ let dPref = `GS delay `;
+ ([() => {
+ console.info(`${dPref}type: ${gsDelType[e]}`);
+ upThis.setEffectType(2, 40, 32 + e);
+ }, () => {// pre-LPF
+ }, () => {// time C
+ }, () => {// time L
+ }, () => {// time R
+ }, () => {// level C
+ }, () => {// level L
+ }, () => {// level R
+ }, () => {// level
+ }, () => {// feedback
+ }, () => {
+ console.debug(`${dPref}to reverb: ${toDecibel(e)}`);
+ }][offset + i - 80] || (() => {}))();
+ });
+ } else {
+ console.debug(`Unknown GS patch address: ${offset}`);
+ };
+ }).add([66, 18, 64, 2], (msg) => {
+ // GS EQ
+ let dPref = `GS EQ `;
+ msg.subarray(1).forEach((e, i) => {
+ ([() => {
+ console.debug(`${dPref}low freq: ${[200, 400][e]}Hz`);
+ }, () => {
+ console.debug(`${dPref}low gain: ${e - 64}dB`);
+ }, () => {
+ console.debug(`${dPref}high freq: ${[3E3, 6E3][e]}Hz`);
+ }, () => {
+ console.debug(`${dPref}high gain: ${e - 64}dB`);
+ }][msg[0] + i] || function () {
+ console.warn(`Unknown GS EQ address: ${msg[0] + i}`);
+ })();
+ });
+ }).add([66, 18, 64, 3], (msg) => {
+ // GS EFX
+ let dPref = `GS EFX `;
+ let prefDesc = function (e, i) {
+ let desc = getGsEfxDesc(upThis.#efxBase.subarray(10, 12), i, e);
+ if (desc) {
+ console.debug(`${dPref}${getGsEfx(upThis.#efxBase.subarray(10, 12))} ${desc}`);
+ };
+ };
+ msg.subarray(1).forEach((e, i) => {
+ ([() => {
+ upThis.setEffectTypeRaw(3, false, 32 + e);
+ }, () => {
+ upThis.setEffectTypeRaw(3, true, e);
+ console.info(`${dPref}type: ${getGsEfx(upThis.#efxBase.subarray(10, 12))}`);
+ }, false,
+ prefDesc, prefDesc, prefDesc, prefDesc, prefDesc,
+ prefDesc, prefDesc, prefDesc, prefDesc, prefDesc,
+ prefDesc, prefDesc, prefDesc, prefDesc, prefDesc,
+ prefDesc, prefDesc, prefDesc, prefDesc, prefDesc,
+ () => {
+ console.debug(`${dPref}to reverb: ${toDecibel(e)}dB`);
+ }, () => {
+ console.debug(`${dPref}to chorus: ${toDecibel(e)}dB`);
+ }, () => {
+ console.debug(`${dPref}to delay: ${toDecibel(e)}dB`);
+ }, false, () => {
+ console.debug(`${dPref}1 source: ${e}`);
+ if (e && e < 96) {
+ upThis.allocateAce(e);
+ };
+ }, () => {
+ console.debug(`${dPref}1 depth: ${e - 64}`);
+ }, () => {
+ console.debug(`${dPref}2 source: ${e}`);
+ if (e && e < 96) {
+ upThis.allocateAce(e);
+ };
+ }, () => {
+ console.debug(`${dPref}2 depth: ${e - 64}`);
+ }, () => {
+ console.debug(`${dPref}to EQ: ${e ? "ON" : "OFF"}`);
+ }][msg[0] + i] || function (e, i) {
+ console.warn(`Unknown GS EFX address: ${i}`);
+ })(e, msg[0] + i);
+ });
+ }).add([66, 18, 65], (msg) => {
+ // GS drum setup
+ }).add([69, 18, 16], (msg) => {
+ // GS display section
+ switch (msg[0]) {
+ case 0: {
+ // GS display letter
+ let offset = msg[1];
+ upThis.setLetterDisplay(msg.subarray(2), "GS display text", offset);
+ break;
+ };
+ case 32: {
+ upThis.#bitmapExpire = Date.now() + 3200;
+ if (msg[1] == 0) {
+ // GS display page
+ upThis.#bitmapPage = Math.max(Math.min(msg[2] - 1, 9), 0);
+ };
+ break;
+ };
+ default: {
+ if (msg[0] < 11) {
+ // GS display bitmap
+ if (upThis.#bitmapPage > 9) {
+ upThis.#bitmapPage = 0;
+ };
+ upThis.#bitmapExpire = Date.now() + 3200;
+ if (!upThis.#bitmapStore[msg[0] - 1]?.length) {
+ upThis.#bitmapStore[msg[0] - 1] = new Uint8Array(256);
+ };
+ let target = upThis.#bitmapStore[msg[0] - 1];
+ let offset = msg[1];
+ target.fill(0); // Init
+ let workArr = msg.subarray(2);
+ for (let index = 0; index < offset; index ++) {
+ workArr.unshift(0);
+ };
+ workArr.forEach(function (e, i) {
+ let ln = Math.floor(i / 16), co = i % 16;
+ let pt = (co * 4 + ln) * 5, threshold = 5, bi = 0;
+ pt -= co * 4;
+ if (ln == 3) {
+ threshold = 1;
+ };
+ while (bi < threshold) {
+ target[pt + bi] = (e >> (4 - bi)) & 1;
+ bi ++;
+ };
+ });
+ } else {
+ console.warn(`Unknown GS display section: ${msg[0]}`);
+ };
+ };
+ };
+ });
+ // GS Part setup
+ // I wanted this to also be written in a circular structure
+ // But clearly Roland hates me
+ let gsPartSec = function (msg, part, track) {
+ let offset = msg[0],
+ chOff = allocated.cc * part,
+ rpnOff = allocated.rpn * part,
+ dPref = `GS CH${part + 1} `;
+ if (offset < 3) {
+ // Program, MSB and receive channel
+ msg.subarray(1).forEach((e, i) => {
+ [() => {
+ upThis.#cc[chOff + ccToPos[0]] = e; // MSB
+ }, () => {
+ upThis.#prg[part] = e; // program
+ }, () => {
+ let ch = upThis.chRedir(e, track, true);
+ upThis.#chReceive[part] = ch; // Rx CH
+ if (part != ch) {
+ upThis.buildRchTree();
+ console.info(`${dPref}receives from CH${ch + 1}`);
+ };
+ }][offset + i]();
+ });
+ } else if (offset < 19) {} else if (offset < 44) {
+ msg.subarray(1).forEach((e, i) => {
+ ([() => {
+ upThis.#mono[part] = +!e; // mono/poly
+ }, false // assign mode
+ , () => {
+ // drum map
+ upThis.setChType(part, e << 1, modeMap.gs);
+ console.debug(`${dPref}type: ${e ? "drum " : "melodic"}${e ? e : ""}`);
+ }, () => {
+ // coarse tune
+ upThis.#rpn[rpnOff + 3] = e;
+ }, false // pitch offset
+ , () => {
+ // volume
+ upThis.#cc[chOff + ccToPos[7]] = e;
+ }, false // velocity sense depth
+ , false // velocity sense offset
+ , () => {
+ // pan
+ upThis.#cc[chOff + ccToPos[10]] = e || 128;
+ }, false // note upperbound
+ , false // note lowerbound
+ , () => {
+ // general-purpose CC source A
+ console.debug(`${dPref}CC 1: cc${e}`);
+ }, () => {
+ // general-purpose CC source B
+ console.debug(`${dPref}CC 2: cc${e}`);
+ }, () => {
+ // chorus
+ upThis.#cc[chOff + ccToPos[93]] = e;
+ }, () => {
+ // reverb
+ upThis.#cc[chOff + ccToPos[91]] = e;
+ }, false // Rx bank select MSB
+ , false // Rx bank select LSB
+ , () => {
+ // fine tune MSB
+ upThis.#rpn[rpnOff + 1] = e;
+ }, () => {
+ // fine tune LSB
+ upThis.#rpn[rpnOff + 2] = e;
+ }, () => {
+ // delay (variation in XG)
+ upThis.#cc[chOff + ccToPos[94]] = e;
+ }][offset + i - 19] || (() => {}))();
+ });
+ } else if (offset < 76) {} else {
+ console.debug(`Unknown GS part address: ${offset}`);
+ };
+ },
+ gsMiscSec = function (msg, part) {
+ let offset = msg[0],
+ dPref = `GS CH${part + 1} `;
+ if (offset < 2) {
+ msg.subarray(1).forEach((e, i) => {
+ [() => {
+ // GS part LSB
+ upThis.#cc[allocated.cc * part + ccToPos[32]] = e;
+ }, () => {// GS part fallback LSB
+ }][offset + i]();
+ });
+ } else if (offset < 32) {
+ console.warn(`Unknown GS misc address: ${offset}`);
+ } else if (offset < 35) {
+ msg.subarray(1).forEach((e, i) => {
+ [() => {
+ // GS part EQ toggle
+ console.debug(`${dPref}EQ: o${["ff", "n"][e]}`);
+ }, () => {// GS part output
+ }, () => {
+ // GS part EFX toggle
+ console.debug(`${dPref}EFX: o${["ff", "n"][e]}`);
+ }][offset + i - 32]();
+ });
+ } else {
+ console.warn(`Unknown GS misc address: ${offset}`);
+ };
+ };
+ this.#seGs.add([66, 18, 64, 16], (msg, track) => {
+ gsPartSec(msg, upThis.chRedir(9, track, true), track);
+ }).add([66, 18, 64, 17], (msg, track) => {
+ gsPartSec(msg, upThis.chRedir(0, track, true), track);
+ }).add([66, 18, 64, 18], (msg, track) => {
+ gsPartSec(msg, upThis.chRedir(1, track, true), track);
+ }).add([66, 18, 64, 19], (msg, track) => {
+ gsPartSec(msg, upThis.chRedir(2, track, true), track);
+ }).add([66, 18, 64, 20], (msg, track) => {
+ gsPartSec(msg, upThis.chRedir(3, track, true), track);
+ }).add([66, 18, 64, 21], (msg, track) => {
+ gsPartSec(msg, upThis.chRedir(4, track, true), track);
+ }).add([66, 18, 64, 22], (msg, track) => {
+ gsPartSec(msg, upThis.chRedir(5, track, true), track);
+ }).add([66, 18, 64, 23], (msg, track) => {
+ gsPartSec(msg, upThis.chRedir(6, track, true), track);
+ }).add([66, 18, 64, 24], (msg, track) => {
+ gsPartSec(msg, upThis.chRedir(7, track, true), track);
+ }).add([66, 18, 64, 25], (msg, track) => {
+ gsPartSec(msg, upThis.chRedir(8, track, true), track);
+ }).add([66, 18, 64, 26], (msg, track) => {
+ gsPartSec(msg, upThis.chRedir(10, track, true), track);
+ }).add([66, 18, 64, 27], (msg, track) => {
+ gsPartSec(msg, upThis.chRedir(11, track, true), track);
+ }).add([66, 18, 64, 28], (msg, track) => {
+ gsPartSec(msg, upThis.chRedir(12, track, true), track);
+ }).add([66, 18, 64, 29], (msg, track) => {
+ gsPartSec(msg, upThis.chRedir(13, track, true), track);
+ }).add([66, 18, 64, 30], (msg, track) => {
+ gsPartSec(msg, upThis.chRedir(14, track, true), track);
+ }).add([66, 18, 64, 31], (msg, track) => {
+ gsPartSec(msg, upThis.chRedir(15, track, true), track);
+ }).add([66, 18, 64, 64], (msg, track) => {
+ gsMiscSec(msg, upThis.chRedir(9, track, true));
+ }).add([66, 18, 64, 65], (msg, track) => {
+ gsMiscSec(msg, upThis.chRedir(0, track, true));
+ }).add([66, 18, 64, 66], (msg, track) => {
+ gsMiscSec(msg, upThis.chRedir(1, track, true));
+ }).add([66, 18, 64, 67], (msg, track) => {
+ gsMiscSec(msg, upThis.chRedir(2, track, true));
+ }).add([66, 18, 64, 68], (msg, track) => {
+ gsMiscSec(msg, upThis.chRedir(3, track, true));
+ }).add([66, 18, 64, 69], (msg, track) => {
+ gsMiscSec(msg, upThis.chRedir(4, track, true));
+ }).add([66, 18, 64, 70], (msg, track) => {
+ gsMiscSec(msg, upThis.chRedir(5, track, true));
+ }).add([66, 18, 64, 71], (msg, track) => {
+ gsMiscSec(msg, upThis.chRedir(6, track, true));
+ }).add([66, 18, 64, 72], (msg, track) => {
+ gsMiscSec(msg, upThis.chRedir(7, track, true));
+ }).add([66, 18, 64, 73], (msg, track) => {
+ gsMiscSec(msg, upThis.chRedir(8, track, true));
+ }).add([66, 18, 64, 74], (msg, track) => {
+ gsMiscSec(msg, upThis.chRedir(10, track, true));
+ }).add([66, 18, 64, 75], (msg, track) => {
+ gsMiscSec(msg, upThis.chRedir(11, track, true));
+ }).add([66, 18, 64, 76], (msg, track) => {
+ gsMiscSec(msg, upThis.chRedir(12, track, true));
+ }).add([66, 18, 64, 77], (msg, track) => {
+ gsMiscSec(msg, upThis.chRedir(13, track, true));
+ }).add([66, 18, 64, 78], (msg, track) => {
+ gsMiscSec(msg, upThis.chRedir(14, track, true));
+ }).add([66, 18, 64, 79], (msg, track) => {
+ gsMiscSec(msg, upThis.chRedir(15, track, true));
+ });
+ // KORG X5DR SysEx section
+ this.#seAi.add([54, 65], (msg, track) => {
+ // X5D multi parameters (part setup)
+ upThis.switchMode("x5d");
+ let key = (msg[1] << 7) + msg[0],
+ e = (msg[3] << 7) + msg[2],
+ part = upThis.chRedir(key & 15, track, true),
+ chOff = allocated.cc * part;
+ [() => {
+ // Program change
+ if (e < 1) {
+ } else if (e < 101) {
+ upThis.setChType(part, upThis.CH_MELODIC, modeMap.x5d);
+ upThis.#prg[part] = e - 1;
+ upThis.#cc[chOff + ccToPos[0]] = 82;
+ } else if (e < 229) {
+ upThis.setChType(part, upThis.CH_MELODIC, modeMap.x5d);
+ upThis.#prg[part] = e - 101;
+ upThis.#cc[chOff + ccToPos[0]] = 56;
+ } else {
+ upThis.setChType(part, upThis.CH_DRUMS, modeMap.x5d);
+ upThis.#prg[part] = korgDrums[e - 229] || 0;
+ upThis.#cc[chOff + ccToPos[0]] = 62;
+ };
+ }, () => {
+ // Volume
+ upThis.#cc[chOff + ccToPos[7]] = e;
+ }, () => {
+ // Panpot
+ if (e < 31) {
+ upThis.#cc[chOff + ccToPos[10]] = Math.round((e - 15) * 4.2 + 64);
+ };
+ }, () => {
+ // Chorus
+ upThis.#cc[chOff + ccToPos[93]] = x5dSendLevel(e);
+ }, () => {
+ // Reverb
+ upThis.#cc[chOff + ccToPos[91]] = x5dSendLevel(e);
+ }, () => {
+ // Coarse tune
+ upThis.#rpn[part * allocated.rpn + 3] = (e > 8191 ? e - 16320 : 64 + e);
+ }, () => {
+ // Fine tune
+ upThis.#rpn[part * allocated.rpn + 1] = (e > 8191 ? e - 16320 : 64 + e);
+ }, () => {
+ // PB range
+ if (e > 0) {
+ upThis.#rpn[part * allocated.rpn] = e;
+ };
+ }, () => {
+ // program change filter
+ }][key >> 4]();
+ }).add([54, 76, 0], (msg, track) => {
+ // X5D program dump
+ upThis.switchMode("x5d", true);
+ let name = "", msb = 82, prg = 0, lsb = 0;
+ let voiceMap = "MSB\tPRG\tLSB\tNME";
+ korgFilter(msg, function (e, i) {
+ if (i < 16400) {
+ let p = i % 164;
+ switch (true) {
+ case (p < 10): {
+ if (e > 31) {
+ name += String.fromCharCode(e);
+ };
+ break;
+ };
+ case (p == 11): {
+ voiceMap += `\n${msb}\t${prg}\t${lsb}\t${name.trim().replace("Init Voice", "")}`;
+ prg ++;
+ name = "";
+ break;
+ };
+ };
+ if (prg > 99) {
+ msb = 90;
+ prg = 0;
+ };
+ };
+ });
+ upThis.userBank.clearRange({
+ msb: 82,
+ prg: [0, 99],
+ lsb: 0
+ });
+ upThis.userBank.load(voiceMap);
+ }).add([54, 77, 0], (msg, track) => {
+ // X5D combi dump
+ upThis.switchMode("x5d", true);
+ let name = "", msb = 90, prg = 0, lsb = 0;// CmbB then CmbA
+ let voiceMap = "MSB\tPRG\tLSB\tNME";
+ korgFilter(msg, function (e, i) {
+ if (i < 13600) {
+ let p = i % 136;
+ switch (true) {
+ case (p < 10): {
+ if (e > 31) {
+ name += String.fromCharCode(e);
+ };
+ break;
+ };
+ case (p == 11): {
+ voiceMap += `\n${msb}\t${prg}\t${lsb}\t${name.trim().replace("Init Combi", "")}`;
+ prg ++;
+ name = "";
+ break;
+ };
+ };
+ };
+ });
+ upThis.userBank.clearRange({
+ msb: 90,
+ prg: [0, 99],
+ lsb: 0
+ });
+ upThis.userBank.load(voiceMap);
+ }).add([54, 78], (msg, track) => {
+ // X5D mode switch
+ upThis.switchMode("x5d", true);
+ console.debug(`X5D mode switch requested: ${["combi", "combi edit", "prog", "prog edit", "multi", "global"][msg[0]]} mode.`);
+ }).add([54, 85], (msg, track) => {
+ // X5D effect dump
+ upThis.switchMode("x5d", true);
+ korgFilter(msg, (e, i) => {
+ if (i > 0 && i < 3) {
+ upThis.setEffectType(i - 1, 44, e);
+ };
+ });
+ }).add([54, 104], (msg, track) => {
+ // X5D extended multi setup
+ upThis.switchMode("x5d", true);
+ korgFilter(msg, function (e, i, a, ri) {
+ if (i < 192) {
+ let part = upThis.chRedir(Math.floor(i / 12), track, true),
+ chOff = part * allocated.cc;
+ switch (i % 12) {
+ case 0: {
+ // Program change
+ if (e < 128) {
+ upThis.setChType(part, upThis.CH_MELODIC, modeMap.x5d);
+ upThis.#cc[chOff + ccToPos[0]] = 82;
+ upThis.#prg[part] = e;
+ } else {
+ upThis.setChType(part, upThis.CH_DRUMS, modeMap.x5d);
+ upThis.#cc[chOff + ccToPos[0]] = 62;
+ upThis.#prg[part] = korgDrums[e - 128];
+ };
+ if (e > 0) {
+ upThis.#chActive[part] = 1;
+ };
+ break;
+ };
+ case 1: {
+ // Volume
+ upThis.#cc[chOff + ccToPos[7]] = e;
+ break;
+ };
+ case 2: {
+ // Coarse tune
+ upThis.#rpn[part * allocated.rpn + 3] = (e > 127 ? e - 192 : 64 + e);
+ break;
+ };
+ case 3: {
+ // Fine tune
+ upThis.#rpn[part * allocated.rpn + 1] = (e > 127 ? e - 192 : 64 + e);
+ break;
+ };
+ case 4: {
+ // Pan
+ if (e < 31) {
+ upThis.#cc[chOff + ccToPos[10]] = Math.round((e - 15) * 4.2 + 64);
+ };
+ break;
+ };
+ case 5: {
+ // Reverb + Chorus
+ let choSend = e >> 4,
+ revSend = e & 15;
+ upThis.#cc[chOff + ccToPos[91]] = x5dSendLevel(revSend);
+ upThis.#cc[chOff + ccToPos[93]] = x5dSendLevel(choSend);
+ break;
+ };
+ case 10: {
+ // Control filter
+ //upThis.#cc[chOff] = (e & 3) ? 82 : 56;
+ break;
+ };
+ case 11: {
+ // MIDI Rc Ch + Track Switch
+ let midiCh = upThis.chRedir(e & 15, track, true),
+ trkSw = e >> 4;
+ upThis.#chReceive[part] = e;
+ if (midiCh != part || trkSw) {
+ console.info(`X5D Part CH${part + 1} receives from CH${midiCh + 1}.`);
+ upThis.buildRchTree();
+ };
+ };
+ };
+ } else {
+ let part = upThis.chRedir(i - 192, track, true);
+ // What the heck is pitch bend range 0xF4(-12) to 0x0C(12)?
+ };
+ });
+ });
+ // Roland MT-32 or C/M SysEx section
+ this.#seGs.add([22, 18, 127], (msg) => {
+ // MT-32 reset all params
+ upThis.switchMode("mt32", true);
+ upThis.#modeKaraoke = false;
+ upThis.userBank.clearRange({msb: 0, lsb: 127, prg: [0, 127]});
+ console.info("MIDI reset: MT-32");
+ }).add([22, 18, 0], (msg, track, id) => {
+ // MT-32 Part Patch Setup (temp)
+ upThis.switchMode("mt32");
+ let part = upThis.chRedir(id, track, true);
+ let offset = msg[1];
+ msg.subarray(2).forEach((e, i) => {
+ let ri = i + offset;
+ upThis.#cmTPatch[ri + (part - 1) * 16] = e;
+ ([false
+ , () => {
+ let timbreGroup = upThis.#cmTPatch[(part - 1) << 4];
+ if (timbreGroup < 3) {
+ upThis.#bnCustom[part] = 1;
+ if (timbreGroup == 2) {
+ // Copy name from timbre memory
+ for (let c = 0; c < name.length; c ++) {
+ upThis.#cmTTimbre[(part - 1) * allocated.cmt + c] = upThis.#cmTimbre[e * allocated.cmt + c];
+ };
+ } else {
+ // Copy name from bank
+ let name = upThis.baseBank.get(0, e + (timbreGroup << 6), 127, "mt32").name;
+ for (let c = 0; c < name.length; c ++) {
+ upThis.#cmTTimbre[(part - 1) * allocated.cmt + c] = name.charCodeAt(c);
+ };
+ };
+ };
+ }, () => {
+ upThis.#rpn[part * allocated.rpn + 3] = e + 40;
+ }, () => {
+ upThis.#rpn[part * allocated.rpn + 1] = e + 14;
+ }, () => {
+ upThis.#rpn[part * allocated.rpn] = e;
+ }, false
+ , () => {
+ upThis.#cc[allocated.cc * part + ccToPos[91]] = e ? 127 : 0;
+ }, false
+ , () => {
+ upThis.#cc[allocated.cc * part + ccToPos[7]] = e;
+ }, () => {
+ upThis.#cc[allocated.cc * part + ccToPos[10]] = Math.ceil(e * 9.05);
+ }][ri] || (() => {}))();
+ });
+ //console.debug(`MT-32 CH${part + 1} Patch: ${msg}`);
+ }).add([22, 18, 1], (msg, track, id) => {
+ // MT-32 Part Drum Setup (temp)
+ upThis.switchMode("mt32");
+ let part = upThis.chRedir(id, track, true);
+ //console.debug(`MT-32 CH${part + 1} Drum: ${msg}`);
+ }).add([22, 18, 2], (msg, track, id) => {
+ // MT-32 Part Timbre Setup (temp)
+ upThis.switchMode("mt32");
+ let part = upThis.chRedir(id, track, true);
+ let offset = msg[1] + (msg[0] << 7);
+ if (offset < 10) {
+ upThis.#bnCustom[part] = 1;
+ };
+ msg.subarray(2).forEach((e, i) => {
+ let ri = i + offset;
+ if (ri < 14) {
+ upThis.#cmTTimbre[(part - 1) * allocated.cmt + ri] = e;
+ };
+ });
+ }).add([22, 18, 3], (msg, track, id) => {
+ // MT-32 Part Patch Setup (dev)
+ upThis.switchMode("mt32");
+ if (msg[0]) {
+ // Rhythm setup
+ let offset = msg[1] - 16;
+ } else {
+ // Part setup
+ let offset = msg[1];
+ msg.subarray(2).forEach((e, i) => {
+ let ri = i + offset;
+ upThis.#cmTPatch[ri] = e;
+ let part = upThis.chRedir(1 + ri >> 4, track, true),
+ ptr = ri & 15;
+ ([false
+ , () => {
+ let timbreGroup = upThis.#cmTPatch[(part - 1) << 4];
+ if (timbreGroup < 3) {
+ upThis.#bnCustom[part] = 1;
+ if (timbreGroup == 2) {
+ // Copy name from timbre memory
+ for (let c = 0; c < name.length; c ++) {
+ upThis.#cmTTimbre[(part - 1) * allocated.cmt + c] = upThis.#cmTimbre[e * allocated.cmt + c];
+ };
+ } else {
+ // Copy name from bank
+ let name = upThis.baseBank.get(0, e + (timbreGroup << 6), 127, "mt32").name;
+ for (let c = 0; c < name.length; c ++) {
+ upThis.#cmTTimbre[(part - 1) * allocated.cmt + c] = name.charCodeAt(c);
+ };
+ };
+ };
+ }, () => {
+ upThis.#rpn[part * allocated.rpn + 3] = e + 40;
+ }, () => {
+ upThis.#rpn[part * allocated.rpn + 1] = e + 14;
+ }, () => {
+ upThis.#rpn[part * allocated.rpn] = e;
+ }, false
+ , () => {
+ upThis.#cc[allocated.cc * part + ccToPos[91]] = e ? 127 : 0;
+ }, false
+ , () => {
+ upThis.#cc[allocated.cc * part + ccToPos[7]] = e;
+ }, () => {
+ upThis.#cc[allocated.cc * part + ccToPos[10]] = Math.ceil(e * 9.05);
+ }][ptr] || (() => {}))();
+ });
+ };
+ //console.debug(`MT-32 Part Patch: ${msg}`);
+ }).add([22, 18, 4], (msg, track, id) => {
+ // MT-32 Part Timbre Setup (dev)
+ upThis.switchMode("mt32");
+ let offsetTotal = msg[1] + (msg[0] << 7);
+ msg.subarray(2).forEach((e, i) => {
+ let ri = i + offsetTotal;
+ let part = upThis.chRedir(Math.floor(ri / 246 + 1), track, true),
+ offset = ri % 246;
+ if (offset < 14) {
+ upThis.#cmTTimbre[(part - 1) * allocated.cmt + offset] = e;
+ };
+ if (offset < 10) {
+ upThis.#bnCustom[part] = 1;
+ };
+ });
+ }).add([22, 18, 5], (msg, track, id) => {
+ // MT-32 Patch Memory Write
+ upThis.switchMode("mt32");
+ let offset = (msg[0] << 7) + msg[1];
+ msg.subarray(2).forEach((e, i) => {
+ let realIndex = (offset + i);
+ let patch = Math.floor(realIndex / 8), slot = (realIndex & 7);
+ let patchOff = patch * 8;
+ upThis.#cmPatch[realIndex] = e;
+ ([false, () => {
+ let timbreGroup = upThis.#cmPatch[patchOff];
+ if (timbreGroup < 3) {
+ // Write for bank A, B and M
+ let name = "";
+ if (timbreGroup == 2) {
+ let timbreOff = allocated.cmt * patch;
+ name = `MT-m:${e.toString().padStart(3, "0")}`;
+ } else {
+ name = upThis.baseBank.get(0, e + (timbreGroup << 6), 127, "mt32").name;
+ };
+ upThis.userBank.clearRange({msb: 0, lsb: 127, prg: patch});
+ upThis.userBank.load(`MSB\tLSB\tPRG\tNME\n000\t127\t${patch}\t${name}`, true);
+ };
+ }][slot] || (() => {}))();
+ });
+ }).add([22, 18, 8], (msg, track, id) => {
+ // MT-32 Timbre Memory Write
+ upThis.switchMode("mt32");
+ let offset = ((msg[0] & 1) << 7) + msg[1];
+ msg.subarray(2).forEach((e, i) => {
+ let ri = offset + i;
+ if (ri < allocated.cmt) {
+ //console.debug(`MT-32 timbre written to slot ${msg[0] >> 1}.`);
+ upThis.#cmTimbre[(msg[0] >> 1) * allocated.cmt + ri] = e;
+ };
+ });
+ }).add([22, 18, 16], (msg, track, id) => {
+ // MT-32 System Setup
+ upThis.switchMode("mt32");
+ let offset = msg[1];
+ let updateRch = false;
+ let setMidiRch = function (e, i) {
+ upThis.#chReceive[i - 12] = e;
+ updateRch = true;
+ };
+ msg.subarray(2).forEach((e, i) => {
+ let ri = i + offset;
+ ([false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ setMidiRch,
+ setMidiRch,
+ setMidiRch,
+ setMidiRch,
+ setMidiRch,
+ setMidiRch,
+ setMidiRch,
+ setMidiRch,
+ setMidiRch,
+ () => {
+ upThis.#masterVol = e;
+ }][ri] || (() => {}))(e, i);
+ });
+ if (updateRch) {
+ upThis.buildRchTree();
+ };
+ }).add([22, 18, 32], (msg) => {
+ // MT-32 Text Display
+ upThis.switchMode("mt32");
+ let offset = msg[1];
+ let text = " ".repeat(offset);
+ msg.subarray(2).forEach((e) => {
+ if (e > 31) {
+ text += String.fromCharCode(e);
+ };
+ });
+ upThis.#letterDisp = text.padStart(20, " ");
+ upThis.#letterExpire = Date.now() + 3200;
+ }).add([22, 18, 82], (msg, track) => {
+ // MT-32 alt reset?
+ let partBase = upThis.chRedir(0, track, true);
+ for (let part = 0; part < 16; part ++) {
+ upThis.#ua.ano(partBase + part);
+ if (part && part < 10) {
+ upThis.#prg[partBase + part] = mt32DefProg[part - 1];
+ };
+ };
+ console.info(`MT-32 alt reset complete.`);
+ });
+ // KORG NS5R SysEx section
+ this.#seAi.add([66, 0], (msg, track) => {
+ // Mode switch
+ upThis.switchMode("ns5r", true);
+ upThis.#modeKaraoke = false;
+ console.debug(`NS5R mode switch requested: ${["global", "multi", "prog edit", "comb edit", "drum edit", "effect edit"][msg[0]]} mode.`);
+ }).add([66, 1], (msg, track) => {
+ // Map switch
+ upThis.switchMode(["ns5r", "05rw"][msg[0]], true);
+ upThis.#modeKaraoke = false;
+ }).add([66, 18, 0, 0], (msg, track) => {
+ // Master setup
+ let offset = msg[0];
+ switch (offset) {
+ case 124: // all param reset
+ case 126: // XG reset for NS5R
+ case 127: { // GS reset for NS5R
+ upThis.switchMode("ns5r", true);
+ upThis.#modeKaraoke = false;
+ break;
+ };
+ case 125: {// drum reset
+ console.info(`NS5R drum setup reset: ${msg}`);
+ break;
+ };
+ default: {
+ if (offset < 10) {
+ let mTune = [0, 0, 0, 0];
+ let writeTune = (e, i) => {
+ // NS5R master fine tune
+ mTune[i] = e;
+ };
+ msg.subarray(1).forEach((e, i) => {
+ [writeTune, writeTune, writeTune, writeTune,
+ () => {
+ upThis.#masterVol = e * 129 / 16383 * 100;
+ }, () => {
+ return (e - 64);
+ }, () => {
+ return (e - 64);
+ }, () => { // EFX MSB
+ }, () => { // EFX LSB
+ }, () => { // EFX PRG
+ }][offset + i]();
+ });
+ if (msg[0] < 4) {
+ // Commit master tune
+ let rTune = 0;
+ mTune.forEach((e) => {
+ rTune = rTune << 4;
+ rTune += e;
+ });
+ rTune -= 1024;
+ };
+ };
+ };
+ };
+ }).add([66, 18, 0, 1], (msg, track) => {
+ // Channel out port setup, trap for now
+ }).add([66, 18, 0, 2], (msg, track) => {
+ // Program out port setup, trap for now
+ }).add([66, 18, 1], (msg, track) => {
+ // Part setup
+ let part = upThis.chRedir(msg[0], track, true),
+ chOff = part * allocated.cc;
+ let offset = msg[1];
+ let dPref = `NS5R CH${part + 1} `;
+ msg.subarray(2).forEach((e, i) => {
+ let c = offset + i;
+ if (c < 3) {
+ // MSB, LSB, PRG
+ [() => {
+ upThis.#cc[chOff + ccToPos[0]] = e || 121;
+ }, () => {
+ upThis.#cc[chOff + ccToPos[32]] = e;
+ }, () => {
+ upThis.#prg[part] = e;
+ }][c]();
+ } else if (c < 8) {
+ // Trap for junk data
+ } else if (c < 14) {
+ [() => {
+ let ch = upThis.chRedir(e, track, true);
+ upThis.#chReceive[part] = ch; // Rx CH
+ if (part != ch) {
+ upThis.buildRchTree();
+ console.info(`${dPref}receives from CH${ch + 1}`);
+ };
+ }, () => {
+ upThis.#mono[part] = +!e;
+ }, () => {
+ upThis.setChType(part, e, modeMap.ns5r);
+ console.debug(`${dPref}type: ${xgPartMode[e]}`);
+ }, () => {
+ upThis.#rpn[allocated.rpn * part + 3] = e;
+ }, () => {
+ }, () => {
+ }][c - 8]();
+ } else if (c < 16) {
+ // Trap for junk data
+ } else if (c < 33) {
+ [() => {
+ upThis.#cc[chOff + ccToPos[7]] = e;
+ }, () => {
+ upThis.#cc[chOff + ccToPos[11]] = e;
+ }, () => {
+ }, () => {
+ }, () => {
+ upThis.#cc[chOff + ccToPos[10]] = e || 128;
+ }, () => {
+ }, () => {
+ }, () => {
+ upThis.#cc[chOff + ccToPos[93]] = e;
+ }, () => {
+ upThis.#cc[chOff + ccToPos[91]] = e;
+ }, () => {
+ upThis.#cc[chOff + ccToPos[76]] = e;
+ }, () => {
+ upThis.#cc[chOff + ccToPos[77]] = e;
+ }, () => {
+ upThis.#cc[chOff + ccToPos[78]] = e;
+ }, () => {
+ upThis.#cc[chOff + ccToPos[74]] = e;
+ }, () => {
+ upThis.#cc[chOff + ccToPos[71]] = e;
+ }, () => {
+ upThis.#cc[chOff + ccToPos[73]] = e;
+ }, () => {
+ upThis.#cc[chOff + ccToPos[75]] = e;
+ }, () => {
+ upThis.#cc[chOff + ccToPos[72]] = e;
+ }][c - 16]();
+ } else if (c < 112) {
+ // Trap for data not supported
+ } else if (c < 114) {
+ [() => {
+ upThis.#cc[chOff + ccToPos[5]] = e;
+ }, () => {
+ upThis.#cc[chOff + ccToPos[65]] = e;
+ }][c - 112]();
+ };
+ });
+ }).add([66, 18, 8, 0], (msg, track) => {
+ // Display (letter and bitmap)
+ let offset = msg[0];
+ if (offset < 32) {
+ // Letter display
+ upThis.setLetterDisplay(msg.subarray(1, 33), "NS5R letter display");
+ } else {
+ // Bitmap display
+ let bitOffset = offset - 32;
+ upThis.#bitmapExpire = Date.now() + 3200;
+ upThis.#bitmapPage = 10; // Use bitmap 11 that holds 512 pixels
+ upThis.#bitmap.fill(0); // Init
+ let workArr = msg.subarray(1);
+ let lastCol = 4;
+ workArr.forEach(function (e, i) {
+ let ri = i + bitOffset;
+ let tx = ri >> 4, ty = ri & 15;
+ if (ri < 80) {
+ let dummy = tx < lastCol ? e : e >> 3, shifted = 0, perspective = tx < lastCol ? 6 : 3;
+ while (dummy > 0) {
+ upThis.#bitmap[ty * 32 + tx * 7 + (perspective - shifted)] = dummy & 1;
+ dummy = dummy >> 1;
+ shifted ++;
+ };
+ };
+ });
+ };
+ }).add([66, 52], (msg, track) => {
+ // Currect effect dump
+ upThis.switchMode("ns5r", true);
+ upThis.#modeKaraoke = false;
+ let efxName = "";
+ korgFilter(msg, (e, i) => {
+ if (i < 8) {
+ if (e > 31) {
+ efxName += String.fromCharCode(e);
+ };
+ if (i == 7) {
+ upThis.aiEfxName = efxName;
+ };
+ } else if (i < 10) {
+ // AI effect ID
+ upThis.setEffectType(i - 8, 44, e);
+ };
+ });
+ }).add([66, 53], (msg, track) => {
+ // Current multi dump
+ upThis.switchMode("ns5r", true);
+ upThis.#modeKaraoke = false;
+ // I'm lazy I just ported the old code here don't judge meee
+ korgFilter(msg, function (e, i) {
+ switch (true) {
+ case i < 2944: {
+ // 32 part setup params, 2944 bytes
+ let part = upThis.chRedir(Math.floor(i / 92), track, true),
+ chOff = part * allocated.cc;
+ switch (i % 92) {
+ case 0: {
+ // MSB Bank
+ upThis.#cc[chOff + ccToPos[0]] = e || 121;
+ break;
+ };
+ case 1: {
+ // LSB Bank
+ upThis.#cc[chOff + ccToPos[32]] = e;
+ break;
+ };
+ case 2: {
+ // Program
+ upThis.#prg[part] = e;
+ if (e > 0) {
+ upThis.#chActive[part] = 1;
+ };
+ break;
+ };
+ case 3: {
+ // Receive MIDI channel
+ let ch = upThis.chRedir(e, track, true);
+ upThis.#chReceive[part] = ch;
+ if (part != ch) {
+ console.info(`NS5R CH${part + 1} receives from CH${ch + 1}.`);
+ upThis.buildRchTree();
+ };
+ };
+ case 7: {
+ // 0 for melodic, 1 for drum, 2~5 for mod drums 1~4
+ // KORG has multiple MSBs for drums, well...
+ break;
+ };
+ case 8: {
+ // Coarse Tune
+ upThis.#rpn[part * allocated.rpn + 3] = (e < 40 || e > 88) ? e + (e > 63 ? -192 : 64) : e;
+ break;
+ };
+ case 9: {
+ // Fine Tune
+ // This is trying to use absolute values.
+ };
+ case 10: {
+ // Volume
+ upThis.#cc[chOff + ccToPos[7]] = e;
+ break;
+ };
+ case 11: {
+ // Expression
+ upThis.#cc[chOff + ccToPos[11]] = e;
+ break;
+ };
+ case 14: {
+ // Pan
+ upThis.#cc[chOff + ccToPos[10]] = e || 128;
+ break;
+ };
+ case 19: {
+ // Chorus
+ upThis.#cc[chOff + ccToPos[93]] = e;
+ break;
+ };
+ case 20: {
+ // Reverb
+ upThis.#cc[chOff + ccToPos[91]] = e;
+ break;
+ };
+ case 84: {
+ // Portamento Switch
+ upThis.#cc[chOff + ccToPos[65]] = e;
+ break;
+ };
+ case 85: {
+ // Portamento Time
+ upThis.#cc[chOff + ccToPos[5]] = e;
+ break;
+ };
+ };
+ break;
+ };
+ case i < 3096: {
+ // part common params, 152 bytes
+ break;
+ };
+ case i < 3134: {
+ // current effect params, 38 bytes
+ break;
+ };
+ case i < 8566: {
+ // 4 mod drum params, 5432 bytes
+ break;
+ };
+ };
+ });
+ }).add([66, 54], (msg, track) => {
+ // All program dump
+ // Yup this one is also ported from old code
+ upThis.switchMode("ns5r", true);
+ let name = "", msb = 80, prg = 0, lsb = 0;
+ let voiceMap = "MSB\tPRG\tLSB\tNME";
+ korgFilter(msg, function (e, i) {
+ let p = i % 158;
+ switch (true) {
+ case (p < 10): {
+ if (e > 31) {
+ name += String.fromCharCode(e);
+ };
+ break;
+ };
+ case (p == 11): {
+ msb = e & 127;
+ break;
+ };
+ case (p == 12): {
+ lsb = e & 127;
+ break;
+ };
+ case (p == 13): {
+ voiceMap += `\n${msb}\t${prg}\t${lsb}\t${name.trim().replace("Init Voice", "")}`;
+ prg ++;
+ name = "";
+ break;
+ };
+ };
+ });
+ upThis.userBank.clearRange({
+ msb: 80,
+ lsb: 0
+ });
+ //console.debug(voiceMap);
+ upThis.userBank.load(voiceMap);
+ }).add([66, 55], (msg, track) => {
+ // All combination dump
+ // Just modified from above
+ upThis.switchMode("ns5r", true);
+ let name = "", msb = 88, prg = 0, lsb = 0;
+ let voiceMap = "MSB\tPRG\tLSB\tNME";
+ korgFilter(msg, function (e, i) {
+ let p = i % 126;
+ switch (true) {
+ case (p < 10): {
+ if (e > 31) {
+ name += String.fromCharCode(e);
+ };
+ break;
+ };
+ case (p == 11): {
+ //msb = e;
+ break;
+ };
+ case (p == 12): {
+ //lsb = e;
+ break;
+ };
+ case (p == 13): {
+ voiceMap += `\n${msb}\t${prg}\t${lsb}\t${name.trim().replace("Init Combi", "")}`;
+ prg ++;
+ name = "";
+ break;
+ };
+ };
+ });
+ upThis.userBank.clearRange({
+ msb: 88,
+ lsb: 0
+ });
+ upThis.userBank.load(voiceMap);
+ }).add([66, 125], (msg) => {
+ // Backlight
+ upThis.dispatchEvent("backlight", ["green", "orange", "red", false, "yellow", "blue", "purple"][msg[0]] || "white");
+ }).add([66, 127], (msg) => {
+ // NS5R screen dump
+ let screenBuffer = new Uint8Array(5760);
+ korgFilter(msg, (e, i, a) => {
+ if (i < 720) {
+ for (let bi = 0; bi < 8; bi ++) {
+ screenBuffer[i * 8 + bi] = (e >> (7 - bi)) & 1;
+ };
+ };
+ });
+ upThis.dispatchEvent("screen", {type: "ns5r", data: screenBuffer});
+ }).add([76], (msg, track, id) => {
+ // N1R to NS5R redirector
+ upThis.#seAi.run([66, ...msg], track, id);
+ });
+ // Kawai GMega
+ this.#seKg.add([16, 0, 8, 0], (msg, track, id) => {
+ // GMega system section
+ let e = (msg[2] << 4) + msg[3];
+ let dPref = "K11 ";
+ ([() => {
+ // GMega bank set
+ upThis.switchMode("k11", true);
+ upThis.#modeKaraoke = false;
+ upThis.#subLsb = e ? 4 : 0;
+ console.info("MIDI reset: GMega/K11");
+ }, () => {
+ console.debug(`${dPref}reverb type: ${e}`);
+ }, () => {
+ console.debug(`${dPref}reverb time: ${e}`);
+ }, () => {
+ console.debug(`${dPref}reverb time: ${e}`);
+ }, () => {
+ console.debug(`${dPref}reverb predelay: ${e}`);
+ }, () => {
+ console.debug(`${dPref}reverb predelay: ${e}`);
+ }, () => {
+ console.debug(`${dPref}depth high: ${e}`);
+ }, () => {
+ console.debug(`${dPref}depth high: ${e}`);
+ }, () => {
+ console.debug(`${dPref}depth low: ${e}`);
+ }, () => {
+ console.debug(`${dPref}depth low: ${e}`);
+ }][msg[0]] || (() => {}))();
+ }).add([16, 0, 8, 1], (msg, track, id) => {
+ // GMega part setup
+ let part = upThis.chRedir(msg[1], track, true),
+ chOff = allocated.cc * part,
+ rpnOff = allocated.rpn * part,
+ e = (msg[3] << 4) + msg[4];
+ let dPref = `K11 CH${part + 1} `;
+ ([() => {
+ if (e < 128) {
+ // Melodic voice
+ upThis.setChType(part, upThis.CH_MELODIC, modeMap.k11);
+ upThis.#cc[chOff + ccToPos[0]] = 0;
+ upThis.#prg[part] = e;
+ } else {
+ // Drum kit
+ upThis.setChType(part, upThis.CH_DRUMS, modeMap.k11);
+ upThis.#prg[part] = e - 128;
+ };
+ }, () => {
+ let ch = upThis.chRedir(e, track, true);
+ upThis.#chReceive[part] = ch; // Rx CH
+ if (part != ch) {
+ upThis.buildRchTree();
+ console.info(`${dPref}receives from CH${ch + 1}`);
+ };
+ }, () => {
+ upThis.#cc[chOff + ccToPos[7]] = e; // volume
+ }, () => {
+ upThis.#chActive[part] = e; // toggle channel
+ }, () => {
+ upThis.#cc[chOff + ccToPos[10]] = e; // pan
+ }, () => {
+ upThis.#rpn[rpnOff + 3] = e + 40; // coarse tune
+ }, () => {
+ upThis.#rpn[rpnOff + 1] = e >> 1; // fine tune
+ upThis.#rpn[rpnOff + 2] = e & 1;
+ }, () => {
+ upThis.#cc[chOff + ccToPos[91]] = e ? 127 : 0; // reverb
+ }, () => {
+ // What is a negative bend depth/sensitivity?
+ }, () => {
+ upThis.#cc[chOff + ccToPos[74]] = e; // brightness
+ }, () => {
+ upThis.#cc[chOff + ccToPos[73]] = e; // attack
+ }, () => {
+ upThis.#cc[chOff + ccToPos[72]] = e; // release
+ }][msg[0]] || (() => {}))();
+ }).add([16, 0, 9, 0], (msg, track, id) => {
+ // GMega LX system section
+ let e = (msg[2] << 4) + msg[3];
+ let dPref = "GMLX ";
+ ([() => {
+ console.debug(`${dPref}reverb type: ${e}`);
+ }, () => {
+ console.debug(`${dPref}reverb time: ${e}`);
+ }, () => {
+ console.debug(`${dPref}reverb predelay: ${e}`);
+ }, () => {
+ console.debug(`${dPref}depth high: ${e}`);
+ }, () => {
+ console.debug(`${dPref}depth low: ${e}`);
+ }][msg[0]] || (() => {}))();
+ }).add([16, 0, 9, 3], (msg, track, id) => {
+ // GMega LX part setup 1
+ let e = (msg[2] << 4) + msg[3];
+ let part = upThis.chRedir(msg[1], track, true),
+ chOff = part * allocated.cc;
+ [() => {
+ if (e < 128) {
+ // Melodic voice
+ upThis.setChType(part, upThis.CH_MELODIC, modeMap.k11);
+ upThis.#cc[chOff + ccToPos[0]] = 0;
+ upThis.#cc[chOff + ccToPos[32]] = 0;
+ upThis.#prg[part] = e;
+ } else if (e < 160) {
+ // Melodic voice
+ upThis.setChType(part, upThis.CH_MELODIC, modeMap.k11);
+ upThis.#cc[chOff + ccToPos[0]] = 0;
+ upThis.#cc[chOff + ccToPos[32]] = 7;
+ upThis.#prg[part] = e - 100;
+ } else {
+ // Drum kit
+ upThis.setChType(part, upThis.CH_DRUMS, modeMap.k11);
+ upThis.#cc[chOff + ccToPos[0]] = 122;
+ upThis.#cc[chOff + ccToPos[32]] = 0;
+ upThis.#prg[part] = e - 160;
+ };
+ }, () => {
+ let ch = upThis.chRedir(e, track, true);
+ upThis.#chReceive[part] = ch; // Rx CH
+ if (part != ch) {
+ upThis.buildRchTree();
+ console.info(`GMLX CH${part + 1} receives from CH${ch + 1}`);
+ };
+ }][msg[0]]();
+ }).add([16, 0, 9, 4], (msg, track, id) => {
+ // GMega LX part setup 2
+ let e = (msg[2] << 4) + msg[3];
+ let part = upThis.chRedir(msg[1], track, true),
+ chOff = part * allocated.cc,
+ rpnOff = part * allocated.rpn;
+ let dPref = `GMLX CH${part + 1} `;
+ [() => {
+ upThis.#chActive[part] = e; // toggle channel
+ }, () => {
+ upThis.#cc[chOff + ccToPos[7]] = e; // volume
+ }, () => {
+ upThis.#cc[chOff + ccToPos[10]] = e; // pan
+ }, () => {
+ upThis.#cc[chOff + ccToPos[91]] = e ? 127 : 0; // reverb
+ }, () => {
+ upThis.#rpn[rpnOff + 3] = e + 40; // coarse tune
+ }, () => {
+ upThis.#rpn[rpnOff + 1] = e; // fine tune
+ }, () => {
+ upThis.#rpn[rpnOff] = e; // pitch bend sensitivity
+ }, () => {
+ // mod depth
+ }][msg[0]]();
+ });
+ // AKAI SG
+ this.#seSg.add([66, 93, 64], (msg, track, id) => {
+ let e = msg[2];
+ switch (msg[0]) {
+ case 0: {
+ // SG system section at 0x00
+ switch (msg[1]) {
+ case 4: {
+ // master volume
+ upThis.#masterVol = e * 129 / 16383 * 100;
+ break;
+ };
+ case 5: {
+ // master key shift, [-24, 24]
+ (e - 64);
+ break;
+ };
+ case 6: {
+ // global reverb toggle
+ console.debug(`SG global reverb: ${e ? "on" : "off"}`);
+ break;
+ };
+ case 127: {
+ // SG reset
+ upThis.switchMode("sg", true);
+ break;
+ };
+ };
+ break;
+ };
+ case 1: {
+ switch (msg[1]) {
+ case 48: {
+ // SG reverb macro
+ console.debug(`SG reverb type: ${gsRevType[e]}`);
+ break;
+ };
+ };
+ break;
+ };
+ default: {
+ if ((msg[0] >> 4) == 1) {
+ // SG part setup
+ let part = upThis.chRedir(msg[0] & 15, track, true);
+ if (msg[1] == 2) {
+ // SG receive channel
+ let ch = upThis.chRedir(e, track, true);
+ upThis.#chReceive[part] = ch; // Rx CH
+ if (part != ch) {
+ upThis.buildRchTree();
+ console.info(`SG CH${part + 1} receives from CH${ch + 1}`);
+ };
+ } else if (msg[1] == 19) {
+ // SG part level
+ upThis.#cc[allocated.cc * part + ccToPos[7]] = e;
+ };
+ } else {
+ console.warn(`Unknown AKAI SG SysEx: ${msg}`);
+ };
+ };
+ };
+ });
+ this.#seCs.add([9], (msg, track, id) => {
+ // CASIO GZ-50M cc91 effect type set
+ console.debug(`GZ set effect: ${["stage reverb", "hall reverb", "room reverb", "chorus", "tremelo", "phaser", "rotary speaker", "enhancer", "flanger", "EQ"][msg[0]] || "off"}`);
+ });
+ // Yamaha S90 ES or Motif ES
+ this.#seXg.add([127, 0], (msg, track, id) => {
+ // Motif ES to S90 ES redirector
+ upThis.switchMode("motif");
+ let newMsg = new Uint8Array([127, 1, ...msg]);
+ upThis.#seXg.run(newMsg, track, id);
+ }).add([127, 1, 0, 0], (msg, track, id) => {
+ // S90 ES System
+ upThis.switchMode("s90es");
+ let dPref = "S90/Motif ES system ",
+ offset = msg[0];
+ msg.subarray(1).forEach((e, i) => {
+ ([() => {
+ upThis.#masterVol = e * 12900 / 16383;
+ }][offset + i] || (() => {
+ console.info(`Unrecognized ${dPref}ID: ${offset + i}`);
+ }))();
+ });
+ }).add([127, 1, 0, 0, 14], (msg, track, id) => {
+ // S90 ES bulk dump header
+ upThis.switchMode("s90es");
+ let dPref = "S90/Motif ES bulk header ";
+ let addrSet = [];
+ addrSet[95] = (msg, track, id) => {
+ console.debug(`${dPref}multi edit buffer: ${msg[1]}`);
+ };
+ (addrSet[msg[0]] || (() => {
+ console.info(`Unrecognized ${dPref}ID: ${msg[0]}.`);
+ }))(msg.subarray(1));
+ }).add([127, 1, 0, 0, 15], (msg, track, id) => {
+ // S90 ES bulk dump footer
+ upThis.switchMode("s90es");
+ let dPref = "S90/Motif ES bulk footer ";
+ let addrSet = [];
+ addrSet[95] = (msg, track, id) => {
+ console.debug(`${dPref}multi edit buffer: ${msg[1]}`);
+ };
+ (addrSet[msg[0]] || (() => {
+ console.info(`Unrecognized ${dPref}ID: ${msg[0]}.`);
+ }))(msg.subarray(1));
+ }).add([127, 1, 0, 58, 55], (msg, track, id) => {
+ // S90 ES bulk part setup (?)
+ upThis.switchMode("s90es");
+ let part = upThis.chRedir(msg[0], track, true),
+ chOff = allocated.cc * part,
+ offset = msg[1];
+ let dPref = `S90/Motif ES bulk CH${part < 16 ? part + 1 : "U" + (part - 95)} `;
+ console.debug(dPref, msg);
+ if (msg[0] > 15) {
+ return;
+ };
+ msg.subarray(2).forEach((e, i) => {
+ ([() => {
+ upThis.#cc[chOff + ccToPos[0]] = e;
+ }, () => {
+ e && (upThis.#chActive[part] = 1);
+ upThis.#cc[chOff + ccToPos[32]] = e;
+ upThis.#chType[part] = +([32, 40].indexOf(e) > -1) << 1;
+ }, () => {
+ e && (upThis.#chActive[part] = 1);
+ upThis.#prg[part] = e;
+ }, () => {
+ let ch = upThis.chRedir(e, track, true);
+ upThis.#chReceive[part] = ch; // Rx CH
+ if (part != ch) {
+ upThis.buildRchTree();
+ console.info(`${dPref}receives from CH${ch + 1}`);
+ };
+ }, () => {
+ upThis.#mono[part] = e ? 0 : 1;
+ }, false, false, false, false, false, false, false, false, () => {
+ upThis.#cc[chOff + ccToPos[7]] = e;
+ }, () => {
+ upThis.#cc[chOff + ccToPos[10]] = e;
+ }, false, false, false, () => {
+ upThis.#cc[chOff + ccToPos[91]] = e;
+ }, () => {
+ upThis.#cc[chOff + ccToPos[93]] = e;
+ }, () => {
+ upThis.#cc[chOff + ccToPos[94]] = e;
+ }, () => {
+ upThis.#cc[chOff + ccToPos[128]] = e;
+ }, () => {
+ // note shift, RPN
+ }, () => {
+ upThis.#cc[chOff + ccToPos[74]] = e;
+ }, () => {
+ upThis.#cc[chOff + ccToPos[71]] = e;
+ }, false, () => {
+ upThis.#cc[chOff + ccToPos[65]] = e;
+ }, () => {
+ upThis.#cc[chOff + ccToPos[5]] = e;
+ }, () => {
+ // portamento mode: fingered, fulltime
+ }][offset + i] || (() => {}))();
+ });
+ }).add([127, 1, 54, 16], (msg, track, id) => {
+ // S90 ES EQ config
+ upThis.switchMode("s90es");
+ let offset = msg[0];
+ msg.subarray(1).forEach((e, i) => {
+ let eqPart = i >> 2;
+ let dPref = `S90/Motif ES EQ${eqPart + 1} `;
+ ([() => {
+ let eqGain = e - 64;
+ //console.debug(`${dPref}gain: ${eqGain}dB`);
+ }, () => {
+ let eqFreq = xgNormFreq[e];
+ //console.debug(`${dPref}freq: ${eqFreq}Hz`);
+ }, () => {
+ let eqQFac = e / 10;
+ //console.debug(`${dPref}Q: ${eqQFac}`);
+ }, () => {
+ let eqType = e; // shelf, peak
+ //console.debug(`${dPref}type: ${["shelf", "peak"][eqTypes]}`);
+ },][(offset + i) & 3] || (() => {}))();
+ });
+ });
+ };
+};
+
+export {
+ OctaviaDevice,
+ allocated,
+ ccToPos,
+ dnToPos
+};
diff --git a/src/state/index.old.mjs b/src/state/index.old.mjs
new file mode 100644
index 00000000..b8868f17
--- /dev/null
+++ b/src/state/index.old.mjs
@@ -0,0 +1,1719 @@
+"use strict";
+
+import {BinaryMatch} from "../../libs/lightfelt@ltgcgo/ext/binMatch.js";
+import {CustomEventSource} from "../../libs/lightfelt@ltgcgo/ext/customEvents.js";
+import {
+ xgEffType,
+ xgPartMode,
+ xgDelOffset,
+ xgNormFreq,
+ xgLfoFreq,
+ getXgRevTime,
+ getXgDelayOffset
+} from "./xgValues.js";
+import {
+ gsRevType,
+ gsChoType
+} from "./gsValues.js";
+import {
+ toDecibel,
+ korgFilter,
+ x5dSendLevel
+} from "./utils.js";
+
+const modeIdx = [
+ "?",
+ "gm", "gs", "xg", "g2",
+ "mt32", "ns5r",
+ "ag10", "x5d", "05rw", "krs",
+ "k11", "sg"
+];
+const substList = [
+ [0, 0, 0, 0, 121, 0, 0, 56, 82, 81, 63, 0, 0],
+ [0, 0, 1, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0]
+];
+const drumMsb = [120, 127, 120, 127, 120, 127, 61, 62, 62, 62, 120, 122, 127];
+const passedMeta = [0, 3, 81, 84, 88]; // What is meta event 32?
+const eventTypes = {
+ 8: "Off",
+ 9: "On",
+ 10: "Note aftertouch",
+ 11: "cc",
+ 12: "pc",
+ 13: "Channel aftertouch",
+ 14: "Pitch"
+};
+
+const useRpnMap = {
+ 0: 0,
+ 1: 1,
+ 2: 3,
+ 5: 4
+},
+useNormNrpn = [8, 9, 10, 32, 33, 36, 37, 99, 100, 101],
+useDrumNrpn = [20, 21, 22, 23, 24, 25, 26, 28, 29, 30, 31, 36, 37, 64, 65],
+ccAccepted = [
+ 0, 1, 2, 4, 5, 6, 7, 8, 10, 11, 32,
+ 38, 64, 65, 66, 67, 68, 69, 70, 71,
+ 72, 73, 74, 75, 76, 77, 78, 84, 91,
+ 92, 93, 94, 95, 98, 99, 100, 101,
+ 12, 13
+]; // 96, 97, 120 to 127 all have special functions
+
+
+let modeMap = {};
+modeIdx.forEach((e, i) => {
+ modeMap[e] = i;
+});
+let ccToPos = {
+ length: ccAccepted.length
+};
+ccAccepted.forEach((e, i) => {
+ ccToPos[e] = i;
+});
+
+let toZero = function (e, i, a) {
+ a[i] = 0;
+};
+let sysExSplitter = function (seq) {
+ let seqArr = [[]];
+ seq?.forEach(function (e) {
+ if (e == 247) {
+ // End of SysEx
+ } else if (e == 240) {
+ seqArr.push([]);
+ } else {
+ seqArr[seqArr.length - 1].push(e);
+ };
+ });
+ return seqArr;
+};
+let showTrue = function (data, prefix = "", suffix = "", length = 2) {
+ return data ? `${prefix}${data.toString().padStart(length, "0")}${suffix}` : "";
+};
+
+const allocated = {
+ ch: 64, // channels
+ cc: ccAccepted.length, // control changes
+ nn: 128, // notes per channel
+ pl: 512, // polyphony
+ tr: 256, // tracks
+ rpn: 6
+};
+
+let OctaviaDevice = class extends CustomEventSource {
+ // Values
+ #mode = 0;
+ #bitmap = new Uint8Array(256);
+ #bitmapExpire = 0;
+ #chActive = new Uint8Array(allocated.ch); // Whether the channel is in use
+ #chReceive = new Uint8Array(allocated.ch); // Determine the receiving channel
+ #cc = new Uint8ClampedArray(8192); // 64 channels, 128 controllers
+ #prg = new Uint8ClampedArray(allocated.ch);
+ #velo = new Uint8ClampedArray(allocated.ch * allocated.nn); // 64 channels. 128 velocity registers
+ #mono = new Uint8Array(allocated.ch); // Mono/poly mode
+ #poly = new Uint16Array(allocated.pl); // 512 polyphony allowed
+ #pitch = new Int16Array(allocated.ch); // Pitch for channels, from -8192 to 8191
+ #customName = new Array(allocated.ch); // Allow custom naming
+ #rawStrength = new Uint8Array(allocated.ch);
+ #dataCommit = 0; // 0 for RPN, 1 for NRPN
+ #rpn = new Uint8Array(allocated.ch * allocated.rpn); // RPN registers (0 pitch MSB, 1 fine tune MSB, 2 fine tune LSB, 3 coarse tune MSB, 4 mod sensitivity MSB, 5 mod sensitivity LSB)
+ #nrpn = new Int8Array(allocated.ch * useNormNrpn.length); // Normal section of NRPN registers
+ #subMsb = 0; // Allowing global bank switching
+ #subLsb = 0;
+ #masterVol = 100;
+ #metaChannel = 0;
+ #letterDisp = "";
+ #letterExpire = 0;
+ #modeKaraoke = false;
+ #receiveTree;
+ // Metadata text events
+ #metaTexts = [];
+ // GS Track Occupation
+ #trkRedir = new Uint8Array(allocated.ch);
+ #trkAsReq = new Uint8Array(allocated.tr); // Track Assignment request
+ chRedir(part, track, noConquer) {
+ if ([modeMap.gs, modeMap.ns5r].indexOf(this.#mode) > -1) {
+ if (this.#trkAsReq[track]) {
+ // Allow part assigning via meta
+ let metaChosen = (this.#trkAsReq[track] - 1) * 16 + part;
+ return metaChosen;
+ };
+ // Do not conquer channels if requested.
+ if (noConquer == 1) {
+ return part;
+ };
+ // Trying to support 32 channel...
+ let shift = 0;
+ //console.debug(`T${track} TC${part} AT${this.#trkRedir[part]}`);
+ if (this.#trkRedir[part] == 0) {
+ this.#trkRedir[part] = track;
+ console.debug(`Assign track ${track} to channel ${part + 1}.`);
+ } else if (this.#trkRedir[part] != track) {
+ shift = 16;
+ if (this.#trkRedir[part + shift] == 0) {
+ this.#trkRedir[part + shift] = track;
+ console.debug(`Assign track ${track} to channel ${part + shift + 1}.`);
+ } else if (this.#trkRedir[part + shift] != track) {
+ shift = 0;
+ };
+ };
+ return part + shift;
+ } else {
+ return part;
+ };
+ };
+ // Exec Pools
+ // Meta event pool
+ #metaRun = [];
+ // Sequencer specific meta pool
+ #metaSeq;
+ // Universal actions
+ #ua = {
+ ano: (part) => {
+ // All notes off
+ // Current implementation uses the static velocity register
+ this.#poly.forEach((e, i, a) => {
+ let ch = e >> 7;
+ if (e == 0 && this.#velo[0] == 0) {
+ } else if (ch == part) {
+ this.#velo[e] = 0;
+ a[i] = 0;
+ };
+ });
+ }
+ };
+ // Channel event pool
+ #runChEvent = {
+ 8: function (det) {
+ let part = det.channel;
+ // Note off, velocity should be ignored.
+ let rawNote = part * 128 + det.data[0];
+ let polyIdx = this.#poly.indexOf(rawNote);
+ if (polyIdx > -1) {
+ this.#poly[polyIdx] = 0;
+ this.#velo[rawNote] = 0;
+ };
+ },
+ 9: function (det) {
+ let part = det.channel;
+ // Note on, but should be off if velocity is 0.
+ // Set channel active
+ this.#chActive[part] = 1;
+ let rawNote = part * 128 + det.data[0];
+ if (det.data[1] > 0) {
+ let place = 0;
+ while (this.#poly[place] > 0) {
+ place ++;
+ };
+ if (place < this.#poly.length) {
+ this.#poly[place] = rawNote;
+ this.#velo[rawNote] = det.data[1];
+ if (this.#rawStrength[part] < det.data[1]) {
+ this.#rawStrength[part] = det.data[1];
+ //console.info(`${part}: ${det.data[1]}`);
+ };
+ } else {
+ console.error("Polyphony exceeded.");
+ };
+ } else {
+ let polyIdx = this.#poly.indexOf(rawNote);
+ if (polyIdx > -1) {
+ this.#poly[polyIdx] = 0;
+ this.#velo[rawNote] = 0;
+ };
+ };
+ },
+ 10: function (det) {
+ let part = det.channel;
+ // Note aftertouch.
+ // Currently it directly changes velocity to set value.
+ let rawNote = part * 128 + det.data[0];
+ let polyIdx = this.#poly.indexOf(rawNote);
+ if (polyIdx > -1) {
+ this.#velo[rawNote] = data[1];
+ };
+ },
+ 11: function (det) {
+ let part = det.channel;
+ // CC event, directly assign values to the register.
+ this.#chActive[part] = 1;
+ let chOffset = part * 128;
+ // Check if control change is accepted
+ if (ccToPos[det.data[0]] == undefined) {
+ console.warn(`cc${det.data[0]} is not accepted.`);
+ };
+ // Pre interpret
+ switch (det.data[0]) {
+ case 0: {
+ // Detect mode via bank MSB
+ //console.debug(`${modeIdx[this.#mode]}, CH${part + 1}: ${det.data[1]}`);
+ if (this.#mode == modeMap.gs || this.#mode == 0) {
+ if (det.data[1] < 48) {
+ // Do not change drum channel to a melodic
+ if (this.#cc[chOffset] > 119) {
+ det.data[1] = this.#cc[chOffset];
+ if (!this.#mode) {
+ det.data[1] = 120;
+ console.debug(`Forced channel ${part + 1} to stay drums.`);
+ };
+ };
+ if (det.data[1] > 0 && !this.#mode) {
+ console.debug(`Roland GS detected with MSB: ${det.data[1]}`);
+ this.switchMode("gs");
+ };
+ } else if (det.data[1] == 62) {
+ this.switchMode("x5d");
+ } else if (det.data[1] == 63) {
+ this.switchMode("krs");
+ };
+ } else if (this.#mode == modeMap.gm) {
+ if (det.data[1] < 48) {
+ // Do not change drum channel to a melodic
+ if (this.#cc[chOffset] > 119) {
+ det.data[1] = 120;
+ this.switchMode("gs", true);
+ console.debug(`Forced channel ${part + 1} to stay drums.`);
+ };
+ };
+ } else if (this.#mode == modeMap.x5d) {
+ if (det.data[1] > 0 && det.data[1] < 8) {
+ this.switchMode("05rw", true);
+ } else if (det.data[1] == 56) {
+ let agCount = 0;
+ for (let c = 0; c < 16; c ++) {
+ let d = this.#cc[128 * c];
+ if (d == 56 || d == 62) {
+ agCount ++;
+ };
+ };
+ if (agCount > 14) {
+ this.switchMode("ag10", true);
+ };
+ };
+ };
+ break;
+ };
+ case 6: {
+ // Show RPN and NRPN
+ if (this.#dataCommit) {
+ if (this.#cc[chOffset + 99] == 1) {
+ if (this.#cc[chOffset + 98] == 32) {
+ this.#cc[chOffset + 74] = det.data[1];
+ console.debug(`Redirected NRPN to cc74.`);
+ };
+ let nrpnIdx = useNormNrpn.indexOf(this.#cc[chOffset + 98]);
+ if (nrpnIdx > -1) {
+ this.#nrpn[part * 10 + nrpnIdx] = det.data[1] - 64;
+ };
+ console.debug(`CH${part + 1} voice NRPN ${this.#cc[chOffset + 99]} ${this.#cc[chOffset + 98]} commit`);
+ } else {
+ console.debug(`CH${part + 1} drum NRPN ${this.#cc[chOffset + 99]} ${this.#cc[chOffset + 98]} commit`);
+ };
+ } else {
+ // Commit supported RPN values
+ if (this.#cc[chOffset + 101] == 0 && useRpnMap[this.#cc[chOffset + 100]] != undefined) {
+ this.#rpn[part * allocated.rpn + useRpnMap[this.#cc[chOffset + 100]]] = det.data[1];
+ console.debug(`CH${part + 1} RPN 0 ${this.#cc[chOffset + 100]} commit: ${det.data[1]}`);
+ };
+ };
+ break;
+ };
+ case 38: {
+ // Show RPN and NRPN
+ if (!this.#dataCommit) {
+ // Commit supported RPN values
+ if (this.#cc[chOffset + 101] == 0 && useRpnMap[this.#cc[chOffset + 100]] != undefined) {
+ this.#rpn[part * allocated.rpn + useRpnMap[this.#cc[chOffset + 100]] + 1] = det.data[1];
+ };
+ } else {
+ //console.debug(`${part + 1} LSB ${det.data[1]} ${this.#dataCommit ? "NRPN" : "RPN"} ${this.#dataCommit ? this.#cc[chOffset + 99] : this.#cc[chOffset + 101]} ${this.#dataCommit ? this.#cc[chOffset + 98] : this.#cc[chOffset + 100]}`);
+ };
+ break;
+ };
+ case 98:
+ case 99: {
+ this.#dataCommit = 1;
+ break;
+ };
+ case 100:
+ case 101: {
+ this.#dataCommit = 0;
+ break;
+ };
+ case 120: {
+ // All sound off, but keys stay on
+ break;
+ };
+ case 121: {
+ // Reset controllers
+ this.#ua.ano(part);
+ this.#pitch[part] = 0;
+ let chOff = part * 128;
+ // Reset to zero
+ this.#cc[chOff + 1] = 0; // Modulation
+ this.#cc[chOff + 5] = 0; // Portamento Time
+ this.#cc[chOff + 64] = 0; // Sustain
+ this.#cc[chOff + 65] = 0; // Portamento
+ this.#cc[chOff + 66] = 0; // Sostenuto
+ this.#cc[chOff + 67] = 0; // Soft Pedal
+ // Reset to full
+ this.#cc[chOff + 11] = 127; // Expression
+ // RPN/NRPN to null
+ this.#cc[chOff + 101] = 127;
+ this.#cc[chOff + 100] = 127;
+ this.#cc[chOff + 99] = 127;
+ this.#cc[chOff + 98] = 127;
+ break;
+ };
+ case 123: {
+ // All notes off
+ this.#ua.ano(part);
+ break;
+ };
+ case 124: {
+ // Omni off
+ this.#ua.ano(part);
+ break;
+ };
+ case 125: {
+ // Omni on
+ this.#ua.ano(part);
+ break;
+ };
+ case 126: {
+ // Mono mode
+ this.#mono[part] = 1;
+ this.#ua.ano(part);
+ break;
+ };
+ case 127: {
+ // Poly mode
+ this.#mono[part] = 0;
+ this.#ua.ano(part);
+ break;
+ };
+ };
+ this.#cc[chOffset + det.data[0]] = det.data[1];
+ },
+ 12: function (det) {
+ let part = det.channel;
+ // Program change
+ this.#chActive[part] = 1;
+ this.#prg[part] = det.data;
+ this.#customName[part] = 0;
+ //console.debug(`T:${det.track} C:${part} P:${det.data}`);
+ },
+ 13: function (det) {
+ // Channel aftertouch
+ let upThis = this;
+ let part = det.channel;
+ this.#poly.forEach(function (e) {
+ let realCh = e >> 7;
+ if (part == realCh) {
+ upThis.#velo[e] = det.data;
+ };
+ });
+ },
+ 14: function (det) {
+ let part = det.channel;
+ // Pitch bending
+ this.#pitch[part] = det.data[1] * 128 + det.data[0] - 8192;
+ },
+ 15: function (det) {
+ // SysEx
+ let upThis = this;
+ sysExSplitter(det.data).forEach(function (seq) {
+ upThis.#seMain.run(seq, det.track);
+ });
+ },
+ 255: function (det) {
+ // Meta
+ (this.#metaRun[det.meta] || function (data, track, meta) {}).call(this, det.data, det.track, det.meta);
+ if (det.meta != 32) {
+ this.#metaChannel = 0;
+ };
+ let useReply = passedMeta.indexOf(det.meta) > -1;
+ if (useReply) {
+ det.reply = "meta";
+ return det;
+ } else if (self.debugMode) {
+ console.debug(det);
+ };
+ }
+ };
+ // Main SysEx pool
+ #seMain;
+ // GS Part SysEx pool
+ #seGsPart;
+ #seGsPartProp;
+ // XG Part SysEx pool
+ #seXgPart;
+ #seXgDrumInst;
+ // MT-32 SysEx pool
+ #seMtSysEx;
+ buildRchTree() {
+ // Build a receiving tree from currently set receive channels
+ // Now builds from the ground up each time
+ // Can be optimized to move elements instead
+ let tree = [];
+ this.#chReceive.forEach((e, i) => {
+ if (!tree[e]?.constructor) {
+ tree[e] = [];
+ };
+ tree[e].push(i);
+ });
+ this.#receiveTree = tree;
+ //console.debug(tree);
+ };
+ getActive() {
+ let result = this.#chActive.slice();
+ if (this.#mode == modeMap.mt32) {
+ //result[0] = 0;
+ };
+ return result;
+ };
+ getCc(channel) {
+ // Return channel CC registers
+ let start = channel * 128;
+ let arr = this.#cc.slice(start, start + 128);
+ arr[0] = arr[0] || this.#subMsb;
+ arr[32] = arr[32] || this.#subLsb;
+ return arr;
+ };
+ getCcAll() {
+ // Return all CC registers
+ let arr = this.#cc.slice();
+ for (let c = 0; c < 64; c ++) {
+ let chOff = c * 128;
+ arr[chOff] = arr[chOff] || this.#subMsb;
+ arr[chOff + 32] = arr[chOff + 32] || this.#subLsb;
+ };
+ return arr;
+ };
+ getPitch() {
+ return this.#pitch;
+ };
+ getProgram() {
+ return this.#prg;
+ };
+ getTexts() {
+ return this.#metaTexts.slice();
+ };
+ getVel(channel) {
+ // Return all pressed keys with velocity in a channel
+ let notes = new Map();
+ let upThis = this;
+ this.#poly.forEach(function (e) {
+ let realCh = Math.floor(e / 128),
+ realNote = e % 128;
+ if (channel == realCh && upThis.#velo[e] > 0) {
+ notes.set(realNote, upThis.#velo[e]);
+ };
+ });
+ return notes;
+ };
+ getBitmap() {
+ return {
+ bitmap: this.#bitmap,
+ expire: this.#bitmapExpire
+ };
+ };
+ getCustomNames() {
+ return this.#customName.slice();
+ };
+ getLetter() {
+ return {
+ text: this.#letterDisp,
+ expire: this.#letterExpire
+ };
+ };
+ getMode() {
+ return modeIdx[this.#mode];
+ };
+ getMaster() {
+ return {
+ volume: this.#masterVol
+ };
+ };
+ getRawStrength() {
+ // 0 to 127
+ let upThis = this;
+ this.#poly.forEach(function (e) {
+ let channel = Math.floor(e / 128);
+ if (upThis.#velo[e] > upThis.#rawStrength[channel]) {
+ upThis.#rawStrength[channel] = upThis.#velo[e];
+ };
+ });
+ return this.#rawStrength;
+ };
+ getStrength() {
+ // 0 to 255
+ let str = [], upThis = this;
+ this.getRawStrength().forEach(function (e, i) {
+ str[i] = Math.floor(e * upThis.#cc[i * 128 + 7] * upThis.#cc[i * 128 + 11] * upThis.#masterVol / 803288);
+ });
+ return str;
+ };
+ getRpn() {
+ return this.#rpn;
+ };
+ getNrpn() {
+ return this.#nrpn;
+ };
+ init(type = 0) {
+ // Type 0 is full reset
+ // Full reset
+ this.dispatchEvent("mode", "?");
+ this.#mode = 0;
+ this.#subMsb = 0;
+ this.#subLsb = 0;
+ this.#metaChannel = 0;
+ this.#chActive.forEach(toZero);
+ this.#cc.forEach(toZero);
+ this.#prg.forEach(toZero);
+ this.#velo.forEach(toZero);
+ this.#poly.forEach(toZero);
+ this.#rawStrength.forEach(toZero);
+ this.#pitch.forEach(toZero);
+ this.#nrpn.forEach(toZero);
+ this.#masterVol = 100;
+ this.#metaTexts = [];
+ this.#letterExpire = 0;
+ this.#letterDisp = "";
+ this.#bitmapExpire = 0;
+ this.#bitmap.forEach(toZero);
+ this.#customName.forEach(toZero);
+ this.#modeKaraoke = false;
+ // Reset MIDI receive channel
+ this.#chReceive.forEach(function (e, i, a) {
+ a[i] = i;
+ });
+ this.buildRchTree();
+ // Reset channel redirection
+ this.#trkRedir.forEach(toZero);
+ this.#trkAsReq.forEach(toZero);
+ // Channel 10 to drum set
+ this.#cc[1152] = drumMsb[0];
+ this.#cc[3200] = drumMsb[0];
+ this.#cc[5248] = drumMsb[0];
+ this.#cc[7296] = drumMsb[0];
+ for (let ch = 0; ch < 64; ch ++) {
+ let chOff = ch * 128;
+ // Reset to full
+ this.#cc[chOff + 7] = 127; // Volume
+ this.#cc[chOff + 11] = 127; // Expression
+ // Reset to centre
+ this.#cc[chOff + 10] = 64; // Pan
+ this.#cc[chOff + 71] = 64; // Resonance
+ this.#cc[chOff + 72] = 64; // Release Time
+ this.#cc[chOff + 73] = 64; // Attack Time
+ this.#cc[chOff + 74] = 64; // Brightness
+ this.#cc[chOff + 75] = 64; // Decay Time
+ this.#cc[chOff + 76] = 64; // Vibrato Rate
+ this.#cc[chOff + 77] = 64; // Vibrato Depth
+ this.#cc[chOff + 78] = 64; // Vibrato Delay
+ // RPN/NRPN to null
+ this.#cc[chOff + 101] = 127;
+ this.#cc[chOff + 100] = 127;
+ this.#cc[chOff + 99] = 127;
+ this.#cc[chOff + 98] = 127;
+ // RPN reset
+ let rpnOff = ch * allocated.rpn;
+ this.#rpn[rpnOff] = 2; // Pitch bend sensitivity
+ this.#rpn[rpnOff + 1] = 64; // Fine tune MSB
+ this.#rpn[rpnOff + 2] = 0; // Fine tune LSB
+ this.#rpn[rpnOff + 3] = 64; // Coarse tune MSB
+ this.#rpn[rpnOff + 4] = 0; // Mod sensitivity MSB
+ this.#rpn[rpnOff + 5] = 0; // Mod sensitivity LSB
+ // NRPN drum section reset
+ };
+ return;
+ };
+ switchMode(mode, forced = false) {
+ let idx = modeIdx.indexOf(mode);
+ if (idx > -1) {
+ if (this.#mode == 0 || forced) {
+ this.#mode = idx;
+ this.#subMsb = substList[0][idx];
+ this.#subLsb = substList[1][idx];
+ for (let ch = 0; ch < 64; ch ++) {
+ if (drumMsb.indexOf(this.#cc[ch * 128]) > -1) {
+ this.#cc[ch * 128] = drumMsb[idx];
+ };
+ };
+ this.dispatchEvent("mode", mode);
+ };
+ } else {
+ throw(new Error(`Unknown mode ${mode}`));
+ };
+ };
+ newStrength() {
+ this.#rawStrength.forEach(toZero);
+ };
+ runJson(json) {
+ // Execute transformed JSON event
+ if (json.type > 14) {
+ return this.#runChEvent[json.type].call(this, json);
+ } else {
+ // Universal MIDI channel receive support.
+ let rcvPart = this.chRedir(json.part, json.track),
+ executed = false;
+ this.#receiveTree[rcvPart]?.forEach((e) => {
+ json.channel = e;
+ executed = true;
+ this.#runChEvent[json.type].call(this, json);
+ });
+ /* this.#chReceive.forEach((e, i) => {
+ if (e == rcvPart) {
+ //json.channel = this.chRedir(i, json.track);
+ json.channel = i;
+ executed = true;
+ this.#runChEvent[json.type].call(this, json);
+ };
+ }); */
+ if (!executed) {
+ console.warn(`${eventTypes[json.type] ? eventTypes[json.type] : json.type}${[11, 12].includes(json.type) ? (json.data[0] != undefined ? json.data[0] : json.data).toString() : ""} event sent to CH${rcvPart + 1} without any recipient.`);
+ };
+ };
+ };
+ runRaw(midiArr) {
+ // Translate raw byte stream into JSON MIDI event
+ };
+ constructor() {
+ super();
+ let upThis = this;
+ this.#metaSeq = new BinaryMatch();
+ this.#seMain = new BinaryMatch();
+ this.#seGsPart = new BinaryMatch();
+ this.#seGsPartProp = new BinaryMatch();
+ this.#seXgPart = new BinaryMatch();
+ this.#seXgDrumInst = new BinaryMatch();
+ this.#seMtSysEx = new BinaryMatch();
+ this.#metaSeq.default = function (seq, track) {
+ console.debug(`Unparsed meta 127 sequence on track ${track}: `, seq);
+ };
+ this.#seMain.default = function (sysEx) {
+ console.debug("Unparsed SysEx: ", sysEx);
+ };
+ this.#seGsPart.default = function (sysEx, channel) {
+ console.debug(`Unparsed GS Part on channel ${channel}: `, sysEx);
+ };
+ this.#seXgPart.default = function (sysEx, channel) {
+ console.debug(`Unparsed XG Part on channel ${channel}: `, sysEx);
+ };
+ this.#seXgDrumInst.default = function (sysEx, channel) {
+ console.debug(`Unparsed XG Drum Part on channel ${channel}: `, sysEx);
+ };
+ // Metadata events
+ this.#metaRun[1] = function (data) {
+ // Normal text
+ switch (data.slice(0, 2)) {
+ case "@I": {
+ this.#modeKaraoke = true;
+ this.#metaTexts.unshift(`Kar.Info: ${data.slice(2)}`);
+ break;
+ };
+ case "@K": {
+ this.#modeKaraoke = true;
+ this.#metaTexts.unshift(`Karaoke mode active.`);
+ console.debug(`Karaoke mode active: ${data.slice(2)}`);
+ break;
+ };
+ case "@L": {
+ this.#modeKaraoke = true;
+ this.#metaTexts.unshift(`Language: ${data.slice(2)}`);
+ break;
+ };
+ case "@T": {
+ this.#modeKaraoke = true;
+ this.#metaTexts.unshift(`Ka.Title: ${data.slice(2)}`);
+ break;
+ };
+ case "@V": {
+ this.#modeKaraoke = true;
+ this.#metaTexts.unshift(`Kara.Ver: ${data.slice(2)}`);
+ break;
+ };
+ default: {
+ if (this.#modeKaraoke) {
+ if (data[0] == "\\") {
+ // New section
+ this.#metaTexts.unshift(`@ ${data.slice(1)}`);
+ } else if (data[0] == "/") {
+ // New line
+ this.#metaTexts.unshift(data.slice(1));
+ } else {
+ // Normal append
+ this.#metaTexts[0] += data;
+ };
+ } else {
+ this.#metaTexts[0] = data;
+ this.#metaTexts.unshift("");
+ };
+ };
+ };
+ };
+ this.#metaRun[2] = function (data) {
+ this.#metaTexts.unshift(`Copyrite: ${data}`);
+ };
+ this.#metaRun[3] = function (data, track) {
+ // Filter overly annoying meta events
+ if (track < 1 && this.#metaChannel < 1) {
+ this.#metaTexts.unshift(`TrkTitle: ${data}`);
+ };
+ };
+ this.#metaRun[4] = function (data, track) {
+ if (track < 1 && this.#metaChannel < 1) {
+ this.#metaTexts.unshift(`${showTrue(this.#metaChannel, "", " ")}Instrmnt: ${data}`);
+ };
+ };
+ this.#metaRun[5] = function (data) {
+ if (data.trim() == "") {
+ this.#metaTexts.unshift("");
+ } else {
+ this.#metaTexts[0] += `${data}`;
+ };
+ };
+ this.#metaRun[6] = function (data) {
+ this.#metaTexts.unshift(`${showTrue(this.#metaChannel, "", " ")}C.Marker: ${data}`);
+ };
+ this.#metaRun[7] = function (data) {
+ this.#metaTexts.unshift(`CuePoint: ${data}`);
+ };
+ this.#metaRun[32] = function (data) {
+ this.#metaChannel = data[0] + 1;
+ };
+ this.#metaRun[33] = function (data, track) {
+ console.debug(`Track ${track} requests to get assigned to output ${data}.`);
+ upThis.#trkAsReq[track] = data + 1;
+ };
+ this.#metaRun[127] = function (data, track) {
+ //console.debug(`Sequencer specific on track ${track}: `, data);
+ upThis.#metaSeq.run(data, track);
+ };
+ // Standard resets
+ // Refactor this!
+ this.#seMain.add([126, 127, 9, 1], function () {
+ // General MIDI reset
+ upThis.switchMode("gm", true);
+ upThis.#modeKaraoke = upThis.#modeKaraoke || false;
+ console.info("MIDI reset: GM");
+ }).add([126, 127, 9, 3], function () {
+ // General MIDI rev. 2 reset
+ upThis.switchMode("g2", true);
+ upThis.#modeKaraoke = upThis.#modeKaraoke || false;
+ console.info("MIDI reset: GM2");
+ }).add([64, 0, 16, 0, 8, 0, 0, 0, 0], function () {
+ upThis.switchMode("k11", true);
+ upThis.#modeKaraoke = false;
+ console.info("MIDI reset: KAWAI GMega/K11");
+ }).add([65, 16, 22, 18, 127, 1], function () {
+ // MT-32 reset
+ upThis.switchMode("mt32", true);
+ upThis.#modeKaraoke = false;
+ console.info("MIDI reset: MT-32");
+ console.debug("Reset with the shorter one.");
+ }).add([65, 16, 22, 18, 127, 0, 0, 1], function () {
+ // MT-32 reset
+ upThis.switchMode("mt32", true);
+ upThis.#modeKaraoke = false;
+ console.info("MIDI reset: MT-32");
+ console.debug("Reset with the longer one.");
+ }).add([65, 16, 66, 18, 64, 0, 127, 0, 65], function () {
+ // Roland GS reset
+ upThis.switchMode("gs", true);
+ upThis.#cc[1152] = 120;
+ upThis.#cc[3200] = 120;
+ upThis.#cc[5248] = 120;
+ upThis.#cc[7296] = 120;
+ upThis.#modeKaraoke = false;
+ upThis.#trkRedir.forEach(toZero);
+ console.info("MIDI reset: GS");
+ }).add([67, 16, 76, 0, 0, 126, 0], function (msg) {
+ // Yamaha XG reset
+ upThis.switchMode("xg", true);
+ upThis.#modeKaraoke = false;
+ console.info("MIDI reset: XG");
+ });
+ // Sequencer specific meta event
+ // No refactoring needed.
+ this.#metaSeq.add([67, 0, 1], function (msg, track) {
+ //console.debug(`XGworks requests assigning track ${track} to output ${msg[0]}.`);
+ upThis.#trkAsReq[track] = msg[0] + 1;
+ });
+ // General MIDI SysEx
+ // No refactoring needed.
+ this.#seMain.add([127, 127, 4, 1], function (msg) {
+ // Master volume
+ upThis.switchMode("gm");
+ upThis.#masterVol = ((msg[1] << 7) + msg[0]) / 163.83;
+ });
+ // Yamaha XG SysEx
+ // Refactor this!
+ this.#seMain.add([67, 16, 76, 6, 0], function (msg) {
+ // XG Letter Display
+ let offset = msg[0];
+ upThis.#letterDisp = " ".repeat(offset);
+ upThis.#letterExpire = Date.now() + 3200;
+ msg.slice(1).forEach(function (e) {
+ upThis.#letterDisp += String.fromCharCode(e);
+ });
+ }).add([67, 16, 76, 7, 0, 0], function (msg) {
+ // XG Bitmap Display
+ upThis.#bitmapExpire = Date.now() + 3200;
+ while (msg.length < 48) {
+ msg.unshift(0);
+ };
+ msg.forEach(function (e, i) {
+ let ln = Math.floor(i / 16), co = i % 16;
+ let pt = (co * 3 + ln) * 7, threshold = 7, bi = 0;
+ pt -= co * 5;
+ if (ln == 2) {
+ threshold = 2;
+ };
+ while (bi < threshold) {
+ upThis.#bitmap[pt + bi] = (e >> (6 - bi)) & 1;
+ bi ++;
+ };
+ });
+ }).add([67, 16, 76, 2, 1, 0], function (msg) {
+ console.debug(`XG reverb type: ${xgEffType[msg[0]]}${msg[1] > 0 ? " " + (msg[1] + 1) : ""}`);
+ }).add([67, 16, 76, 2, 1, 2], function (msg) {
+ console.debug(`XG reverb time: ${getXgRevTime(msg)}s`);
+ }).add([67, 16, 76, 2, 1, 3], function (msg) {
+ console.debug(`XG reverb diffusion: ${msg}`);
+ }).add([67, 16, 76, 2, 1, 4], function (msg) {
+ console.debug(`XG reverb initial delay: ${msg}`);
+ }).add([67, 16, 76, 2, 1, 5], function (msg) {
+ console.debug(`XG reverb high pass cutoff: ${xgNormFreq[msg[0]]}Hz`);
+ }).add([67, 16, 76, 2, 1, 6], function (msg) {
+ console.debug(`XG reverb low pass cutoff: ${xgNormFreq[msg[0]]}Hz`);
+ }).add([67, 16, 76, 2, 1, 7], function (msg) {
+ console.debug(`XG reverb width: ${msg}`);
+ }).add([67, 16, 76, 2, 1, 8], function (msg) {
+ console.debug(`XG reverb height: ${msg}`);
+ }).add([67, 16, 76, 2, 1, 9], function (msg) {
+ console.debug(`XG reverb depth: ${msg}`);
+ }).add([67, 16, 76, 2, 1, 10], function (msg) {
+ console.debug(`XG reverb wall type: ${msg}`);
+ }).add([67, 16, 76, 2, 1, 11], function (msg) {
+ console.debug(`XG reverb dry/wet: ${msg[0]}`);
+ }).add([67, 16, 76, 2, 1, 12], function (msg) {
+ console.debug(`XG reverb return: ${msg}`);
+ }).add([67, 16, 76, 2, 1, 13], function (msg) {
+ console.debug(`XG reverb pan: ${msg[0] - 64}`);
+ }).add([67, 16, 76, 2, 1, 16], function (msg) {
+ console.debug(`XG reverb delay: ${msg}`);
+ }).add([67, 16, 76, 2, 1, 17], function (msg) {
+ console.debug(`XG density: ${msg}`);
+ }).add([67, 16, 76, 2, 1, 18], function (msg) {
+ console.debug(`XG reverb balance: ${msg}`);
+ }).add([67, 16, 76, 2, 1, 20], function (msg) {
+ console.debug(`XG reverb feedback: ${msg}`);
+ }).add([67, 16, 76, 2, 1, 32], function (msg) {
+ console.debug(`XG chorus type: ${xgEffType[msg[0]]}${msg[1] > 0 ? " " + (msg[1] + 1) : ""}`);
+ }).add([67, 16, 76, 2, 1, 34], function (msg) {
+ console.debug(`XG chorus LFO: ${xgLfoFreq[msg[0]]}Hz`);
+ }).add([67, 16, 76, 2, 1, 35], function (msg) {
+ //console.debug(`XG chorus LFO phase: ${msg}`);
+ }).add([67, 16, 76, 2, 1, 36], function (msg) {
+ console.debug(`XG chorus feedback: ${msg}`);
+ }).add([67, 16, 76, 2, 1, 37], function (msg) {
+ console.debug(`XG chorus delay offset: ${getXgDelayOffset(msg[0])}ms`);
+ }).add([67, 16, 76, 2, 1, 39], function (msg) {
+ console.debug(`XG chorus low: ${xgNormFreq[msg[0]]}Hz`);
+ }).add([67, 16, 76, 2, 1, 40], function (msg) {
+ console.debug(`XG chorus low: ${msg[0] - 64}dB`);
+ }).add([67, 16, 76, 2, 1, 41], function (msg) {
+ console.debug(`XG chorus high: ${xgNormFreq[msg[0]]}Hz`);
+ }).add([67, 16, 76, 2, 1, 42], function (msg) {
+ console.debug(`XG chorus high: ${msg[0] - 64}dB`);
+ }).add([67, 16, 76, 2, 1, 43], function (msg) {
+ console.debug(`XG chorus dry/wet: ${msg}`);
+ }).add([67, 16, 76, 2, 1, 44], function (msg) {
+ console.debug(`XG chorus return: ${msg}`);
+ }).add([67, 16, 76, 2, 1, 45], function (msg) {
+ console.debug(`XG chorus pan: ${msg[0] - 64}`);
+ }).add([67, 16, 76, 2, 1, 46], function (msg) {
+ console.debug(`XG chorus to reverb: ${msg}`);
+ }).add([67, 16, 76, 2, 1, 64], function (msg) {
+ console.debug(`XG variation type: ${xgEffType[msg[0]]}${msg[1] > 0 ? " " + (msg[1] + 1) : ""}`);
+ }).add([67, 16, 76, 2, 1, 66], function (msg) {
+ console.debug(`XG variation 1: ${msg}`);
+ }).add([67, 16, 76, 2, 1, 68], function (msg) {
+ console.debug(`XG variation 2: ${msg}`);
+ }).add([67, 16, 76, 2, 1, 70], function (msg) {
+ console.debug(`XG variation 3: ${msg}`);
+ }).add([67, 16, 76, 2, 1, 72], function (msg) {
+ console.debug(`XG variation 4: ${msg}`);
+ }).add([67, 16, 76, 2, 1, 74], function (msg) {
+ console.debug(`XG variation 5: ${msg}`);
+ }).add([67, 16, 76, 2, 1, 76], function (msg) {
+ console.debug(`XG variation 6: ${msg}`);
+ }).add([67, 16, 76, 2, 1, 78], function (msg) {
+ console.debug(`XG variation 7: ${msg}`);
+ }).add([67, 16, 76, 2, 1, 80], function (msg) {
+ console.debug(`XG variation 8: ${msg}`);
+ }).add([67, 16, 76, 2, 1, 82], function (msg) {
+ console.debug(`XG variation 9: ${msg}`);
+ }).add([67, 16, 76, 2, 1, 84], function (msg) {
+ console.debug(`XG variation 10: ${msg}`);
+ }).add([67, 16, 76, 2, 1, 86], function (msg) {
+ console.debug(`XG variation return: ${toDecibel(msg[0])}dB`);
+ }).add([67, 16, 76, 2, 1, 87], function (msg) {
+ console.debug(`XG variation pan: ${msg[0] - 64}`);
+ }).add([67, 16, 76, 2, 1, 88], function (msg) {
+ console.debug(`XG variation to reverb: ${toDecibel(msg[0])}dB`);
+ }).add([67, 16, 76, 2, 1, 89], function (msg) {
+ console.debug(`XG variation to chorus: ${toDecibel(msg[0])}dB`);
+ }).add([67, 16, 76, 2, 1, 90], function (msg) {
+ console.debug(`XG variation connection: ${msg[0] ? "system" : "insertion"}`);
+ }).add([67, 16, 76, 2, 1, 91], function (msg) {
+ console.debug(`XG variation part: ${msg}`);
+ }).add([67, 16, 76, 2, 1, 92], function (msg) {
+ console.debug(`XG variation mod wheel: ${msg[0] - 64}`);
+ }).add([67, 16, 76, 2, 1, 93], function (msg) {
+ console.debug(`XG variation bend wheel: ${msg[0] - 64}`);
+ }).add([67, 16, 76, 2, 1, 94], function (msg) {
+ console.debug(`XG variation channel after touch: ${msg[0] - 64}`);
+ }).add([67, 16, 76, 2, 1, 95], function (msg) {
+ console.debug(`XG variation AC1: ${msg[0] - 64}`);
+ }).add([67, 16, 76, 2, 1, 96], function (msg) {
+ console.debug(`XG variation AC2: ${msg[0] - 64}`);
+ }).add([67, 16, 76, 8], function (msg, track) {
+ // XG part setup
+ //console.info(`XG Part Setup trk ${track} ch ${msg[0]} real ${upThis.chRedir(msg[0], track)}.`);
+ // THIS CAN CONTAIN BUGS
+ upThis.#seXgPart.run(msg.slice(1), upThis.chRedir(msg[0], track));
+ }).add([67, 16, 76, 48], function (msg) {
+ // XG drum 1 setup
+ upThis.#seXgDrumInst.run(msg.slice(1), 0, msg[0]);
+ }).add([67, 16, 76, 49], function (msg) {
+ // XG drum 2 setup
+ upThis.#seXgDrumInst.run(msg.slice(1), 1, msg[0]);
+ }).add([67, 16, 76, 50], function (msg) {
+ // XG drum 3 setup
+ upThis.#seXgDrumInst.run(msg.slice(1), 2, msg[0]);
+ }).add([67, 16, 76, 51], function (msg) {
+ // XG drum 4 setup
+ upThis.#seXgDrumInst.run(msg.slice(1), 3, msg[0]);
+ });
+ // Roland MT-32 SysEx
+ // Refactor this!
+ this.#seMain.add([65, 1], function (msg) {
+ upThis.switchMode("mt32");
+ upThis.#seMtSysEx.run(msg, 1);
+ }).add([65, 2], function (msg) {
+ upThis.switchMode("mt32");
+ upThis.#seMtSysEx.run(msg, 2);
+ }).add([65, 3], function (msg) {
+ upThis.switchMode("mt32");
+ upThis.#seMtSysEx.run(msg, 3);
+ }).add([65, 4], function (msg) {
+ upThis.switchMode("mt32");
+ upThis.#seMtSysEx.run(msg, 4);
+ }).add([65, 5], function (msg) {
+ upThis.switchMode("mt32");
+ upThis.#seMtSysEx.run(msg, 5);
+ }).add([65, 6], function (msg) {
+ upThis.switchMode("mt32");
+ upThis.#seMtSysEx.run(msg, 6);
+ }).add([65, 7], function (msg) {
+ upThis.switchMode("mt32");
+ upThis.#seMtSysEx.run(msg, 7);
+ }).add([65, 8], function (msg) {
+ upThis.switchMode("mt32");
+ upThis.#seMtSysEx.run(msg, 8);
+ }).add([65, 9], function (msg) {
+ upThis.switchMode("mt32");
+ upThis.#chActive[9] = 1;
+ upThis.#seMtSysEx.run(msg, 9);
+ }).add([65, 16, 22, 18, 8], function (msg, track) {
+ upThis.switchMode("mt32");
+ let section = msg[0]/*upThis.chRedir(msg[0], track, true)*/,
+ funcId = msg[1],
+ theText = "";
+ if (funcId == 0) {
+ msg.slice(2, 12).forEach((e) => {
+ if (e > 31) {
+ theText += String.fromCharCode(e);
+ };
+ });
+ console.debug(`MT-32 voice setup on section ${section}: ${theText}.`);
+ } else {
+ //console.debug(`Mysterious sequence on channel ${part + 1}: ${msg}`);
+ };
+ }).add([65, 16, 22, 18, 16, 0, 13], function (msg, track) {
+ upThis.switchMode("mt32");
+ console.info(`MT-32 receive channel: ${msg}`);
+ }).add([65, 16, 22, 18, 16, 0, 22], function (msg, track) {
+ upThis.switchMode("mt32");
+ console.info(`MT-32 all notes off? ${msg}`);
+ }).add([65, 16, 22, 18, 32, 0], function (msg) {
+ upThis.switchMode("mt32");
+ let offset = msg[0];
+ upThis.#letterDisp = " ".repeat(offset);
+ msg.unshift();
+ msg.pop();
+ upThis.#letterDisp = " ".repeat(offset);
+ upThis.#letterExpire = Date.now() + 3200;
+ msg.forEach(function (e) {
+ if (e > 31) {
+ upThis.#letterDisp += String.fromCharCode(e);
+ };
+ });
+ upThis.#letterDisp += " ".repeat(32 - upThis.#letterDisp.length);
+ });
+ this.#seMtSysEx.add([22, 18, 2, 0, 0], function (msg, channel) {
+ // MT-32 tone properties
+ // Refactor this!
+ let setName = "";
+ msg.slice(0, 10).forEach(function (e) {
+ if (e > 31) {
+ setName += String.fromCharCode(e);
+ };
+ });
+ upThis.#customName[channel] = setName;
+ console.debug(`MT-32 tone properties on channel ${channel + 1} (${setName}).`);
+ let matchedPart = [];
+ msg.slice(10).forEach((e, i) => {
+ if (e < 10) {
+ matchedPart[e] = matchedPart[e] || [];
+ matchedPart[e].push(i);
+ };
+ });
+ console.info(matchedPart[channel]);
+ });
+ // Roland GS SysEx
+ // Refactor this!
+ this.#seMain.add([65, 16, 66, 18, 0, 0, 127], function (msg) {
+ // GS module mode (single port 16 channel, or double port 32 channel)
+ upThis.switchMode("gs", true);
+ upThis.#cc[1152] = 120;
+ upThis.#cc[3200] = 120;
+ upThis.#cc[5248] = 120;
+ upThis.#cc[7296] = 120;
+ upThis.#trkRedir.forEach(toZero);
+ upThis.#modeKaraoke = false;
+ upThis.#subLsb = 3;
+ console.info(`GS system set to ${msg[0] ? "dual" : "single"} mode.`);
+ }).add([65, 16, 66, 18, 64, 0, 0], function (msg) {
+ // GS Master Tune, 4 bytes but I don't know how to process
+ }).add([65, 16, 66, 18, 64, 0, 4], function (msg) {
+ // GS Master Volume, same as universal master volume but with MSB only.
+ upThis.#masterVol = msg[0] * 129 / 163.83;
+ }).add([65, 16, 66, 18, 64, 0, 5], function (msg) {
+ // GS Master Key Shift
+ console.debug(`GS master key shift: ${msg[0] - 64} semitones.`);
+ }).add([65, 16, 66, 18, 64, 0, 6], function (msg) {
+ // GS Master Pan
+ console.debug(`GS master pan:${msg[0] - 64}.`);
+ }).add([65, 16, 66, 18, 64, 1, 48], function (msg) {
+ // GS reverb macro
+ console.debug(`GS reverb type: ${gsRevType[msg[0]]}`);
+ }).add([65, 16, 66, 18, 64, 1, 49], function (msg) {
+ // GS reverb Character
+ }).add([65, 16, 66, 18, 64, 1, 50], function (msg) {
+ // GS reverb pre-LPF
+ console.debug(`GS reverb pre-LPF: ${msg[0]}`);
+ }).add([65, 16, 66, 18, 64, 1, 51], function (msg) {
+ // GS reverb level
+ console.debug(`GS reverb level: ${msg[0]}`);
+ }).add([65, 16, 66, 18, 64, 1, 52], function (msg) {
+ // GS reverb time (NEED A LOOKUP TABLE FOR REAL VALUES)
+ console.debug(`GS reverb time: ${msg[0]}`);
+ }).add([65, 16, 66, 18, 64, 1, 53], function (msg) {
+ // GS reverb delay feedback
+ console.debug(`GS reverb delay feedback: ${msg[0]}`);
+ }).add([65, 16, 66, 18, 64, 1, 55], function (msg) {
+ // GS reverb pre-delay time
+ console.debug(`GS reverb pre-delay time: ${msg[0]}`);
+ }).add([65, 16, 66, 18, 64, 1, 56], function (msg) {
+ // GS reverb chorus macro
+ console.debug(`GS chorus type: ${gsChoType[msg[0]]}`);
+ }).add([65, 16, 66, 18, 64, 1, 57], function (msg) {
+ // GS reverb chorus pre-LPF (SC-88 Pro manual page 195)
+ console.debug(`GS chorus pre-LPF: ${msg[0]}`);
+ }).add([65, 16, 66, 18, 64, 2, 0], function (msg) {
+ // GS EQ low freq
+ console.debug(`GS EQ low: ${msg[0] ? 400 : 200}Hz`);
+ }).add([65, 16, 66, 18, 64, 2, 1], function (msg) {
+ // GS EQ low gain
+ console.debug(`GS EQ low: ${msg[0] - 64}dB`);
+ }).add([65, 16, 66, 18, 64, 2, 2], function (msg) {
+ // GS EQ high freq
+ console.debug(`GS EQ high: ${msg[0] ? 6000 : 3000}Hz`);
+ }).add([65, 16, 66, 18, 64, 2, 3], function (msg) {
+ // GS EQ high gain
+ console.debug(`GS EQ high: ${msg[0] - 64}dB`);
+ }).add([65, 16, 66, 18, 64, 3], function (msg) {
+ // GS EFX params, have to ignore for now (SC-88 Pro manual page 196)
+ }).add([65, 16, 69, 18, 16, 0], function (msg) {
+ // GS Text Insert (same as XG Letter Display)
+ let offset = msg[0];
+ upThis.#letterDisp = " ".repeat(offset);
+ upThis.#letterExpire = Date.now() + 3200;
+ msg.pop();
+ msg.slice(1).forEach(function (e) {
+ upThis.#letterDisp += String.fromCharCode(e);
+ });
+ }).add([65, 16, 69, 18, 16, 1, 0], function (msg) {
+ // GS Frame Draw (same as XG Bitmap Display)
+ upThis.#bitmapExpire = Date.now() + 3200;
+ msg.forEach(function (e, i) {
+ if (i < 64) {
+ let ln = Math.floor(i / 16), co = i % 16;
+ let pt = (co * 4 + ln) * 5, threshold = 5, bi = 0;
+ pt -= co * 4;
+ if (ln == 3) {
+ threshold = 1;
+ };
+ while (bi < threshold) {
+ upThis.#bitmap[pt + bi] = (e >> (4 - bi)) & 1;
+ bi ++;
+ };
+ };
+ });
+ }).add([65, 16, 66, 18, 64, 16], function (msg, track) {
+ // GS Part channel 10
+ upThis.#seGsPart.run(msg, upThis.chRedir(9, track, true), track);
+ }).add([65, 16, 66, 18, 64, 17], function (msg, track) {
+ // GS Part channel 01
+ upThis.#seGsPart.run(msg, upThis.chRedir(0, track, true), track);
+ }).add([65, 16, 66, 18, 64, 18], function (msg, track) {
+ // GS Part channel 02
+ upThis.#seGsPart.run(msg, upThis.chRedir(1, track, true), track);
+ }).add([65, 16, 66, 18, 64, 19], function (msg, track) {
+ // GS Part channel 03
+ upThis.#seGsPart.run(msg, upThis.chRedir(2, track, true), track);
+ }).add([65, 16, 66, 18, 64, 20], function (msg, track) {
+ // GS Part channel 04
+ upThis.#seGsPart.run(msg, upThis.chRedir(3, track, true), track);
+ }).add([65, 16, 66, 18, 64, 21], function (msg, track) {
+ // GS Part channel 05
+ upThis.#seGsPart.run(msg, upThis.chRedir(4, track, true), track);
+ }).add([65, 16, 66, 18, 64, 22], function (msg, track) {
+ // GS Part channel 06
+ upThis.#seGsPart.run(msg, upThis.chRedir(5, track, true), track);
+ }).add([65, 16, 66, 18, 64, 23], function (msg, track) {
+ // GS Part channel 07
+ upThis.#seGsPart.run(msg, upThis.chRedir(6, track, true), track);
+ }).add([65, 16, 66, 18, 64, 24], function (msg, track) {
+ // GS Part channel 08
+ upThis.#seGsPart.run(msg, upThis.chRedir(7, track, true), track);
+ }).add([65, 16, 66, 18, 64, 25], function (msg, track) {
+ // GS Part channel 09
+ upThis.#seGsPart.run(msg, upThis.chRedir(8, track, true), track);
+ }).add([65, 16, 66, 18, 64, 26], function (msg, track) {
+ // GS Part channel 11
+ upThis.#seGsPart.run(msg, upThis.chRedir(10, track, true), track);
+ }).add([65, 16, 66, 18, 64, 27], function (msg, track) {
+ // GS Part channel 12
+ upThis.#seGsPart.run(msg, upThis.chRedir(11, track, true), track);
+ }).add([65, 16, 66, 18, 64, 28], function (msg, track) {
+ // GS Part channel 13
+ upThis.#seGsPart.run(msg, upThis.chRedir(12, track, true), track);
+ }).add([65, 16, 66, 18, 64, 29], function (msg, track) {
+ // GS Part channel 14
+ upThis.#seGsPart.run(msg, upThis.chRedir(13, track, true), track);
+ }).add([65, 16, 66, 18, 64, 30], function (msg, track) {
+ // GS Part channel 15
+ upThis.#seGsPart.run(msg, upThis.chRedir(14, track, true), track);
+ }).add([65, 16, 66, 18, 64, 31], function (msg, track) {
+ // GS Part channel 16
+ upThis.#seGsPart.run(msg, upThis.chRedir(15, track, true), track);
+ }).add([65, 16, 66, 18, 64, 64], function (msg, track) {
+ // GS Part channel 10
+ upThis.#seGsPartProp.run(msg, upThis.chRedir(9, track, true));
+ }).add([65, 16, 66, 18, 64, 65], function (msg, track) {
+ // GS Part channel 01
+ upThis.#seGsPartProp.run(msg, upThis.chRedir(0, track, true));
+ }).add([65, 16, 66, 18, 64, 66], function (msg, track) {
+ // GS Part channel 02
+ upThis.#seGsPartProp.run(msg, upThis.chRedir(1, track, true));
+ }).add([65, 16, 66, 18, 64, 67], function (msg, track) {
+ // GS Part channel 03
+ upThis.#seGsPartProp.run(msg, upThis.chRedir(2, track, true));
+ }).add([65, 16, 66, 18, 64, 68], function (msg, track) {
+ // GS Part channel 04
+ upThis.#seGsPartProp.run(msg, upThis.chRedir(3, track, true));
+ }).add([65, 16, 66, 18, 64, 69], function (msg, track) {
+ // GS Part channel 05
+ upThis.#seGsPartProp.run(msg, upThis.chRedir(4, track, true));
+ }).add([65, 16, 66, 18, 64, 70], function (msg, track) {
+ // GS Part channel 06
+ upThis.#seGsPartProp.run(msg, upThis.chRedir(5, track, true));
+ }).add([65, 16, 66, 18, 64, 71], function (msg, track) {
+ // GS Part channel 07
+ upThis.#seGsPartProp.run(msg, upThis.chRedir(6, track, true));
+ }).add([65, 16, 66, 18, 64, 72], function (msg, track) {
+ // GS Part channel 08
+ upThis.#seGsPartProp.run(msg, upThis.chRedir(7, track, true));
+ }).add([65, 16, 66, 18, 64, 73], function (msg, track) {
+ // GS Part channel 09
+ upThis.#seGsPartProp.run(msg, upThis.chRedir(8, track, true));
+ }).add([65, 16, 66, 18, 64, 74], function (msg, track) {
+ // GS Part channel 11
+ upThis.#seGsPartProp.run(msg, upThis.chRedir(10, track, true));
+ }).add([65, 16, 66, 18, 64, 75], function (msg, track) {
+ // GS Part channel 12
+ upThis.#seGsPartProp.run(msg, upThis.chRedir(11, track, true));
+ }).add([65, 16, 66, 18, 64, 76], function (msg, track) {
+ // GS Part channel 13
+ upThis.#seGsPartProp.run(msg, upThis.chRedir(12, track, true));
+ }).add([65, 16, 66, 18, 64, 77], function (msg, track) {
+ // GS Part channel 14
+ upThis.#seGsPartProp.run(msg, upThis.chRedir(13, track, true));
+ }).add([65, 16, 66, 18, 64, 78], function (msg, track) {
+ // GS Part channel 15
+ upThis.#seGsPartProp.run(msg, upThis.chRedir(14, track, true));
+ }).add([65, 16, 66, 18, 64, 79], function (msg, track) {
+ // GS Part channel 16
+ upThis.#seGsPartProp.run(msg, upThis.chRedir(15, track, true));
+ });
+ // KORG X5D SysEx
+ upThis.#seMain.add([66, 48, 54, 104], function (msg, track) {
+ // X5D extended multi setup
+ upThis.switchMode("x5d", true);
+ korgFilter(msg, function (e, i) {
+ if (i < 192) {
+ let part = upThis.chRedir(Math.floor(i / 12), track, true),
+ chOff = part * 128;
+ switch (i % 12) {
+ case 0: {
+ // Program change
+ upThis.#prg[part] = e;
+ if (e > 0) {
+ upThis.#chActive[part] = 1;
+ };
+ break;
+ };
+ case 1: {
+ // Volume
+ upThis.#cc[chOff + 7] = e;
+ break;
+ };
+ case 2: {
+ // Coarse tune
+ upThis.#rpn[part * allocated.rpn + 3] = (e > 127 ? 256 - e : 64 + e);
+ break;
+ };
+ case 3: {
+ // Fine tune
+ upThis.#rpn[part * allocated.rpn + 1] = (e > 127 ? 256 - e : 64 + e);
+ break;
+ };
+ case 4: {
+ // Pan
+ if (e < 31) {
+ upThis.#cc[chOff + 10] = Math.round((e - 15) * 4.2 + 64);
+ };
+ break;
+ };
+ case 5: {
+ // Reverb + Chorus
+ let choSend = e >> 4,
+ revSend = e & 15;
+ upThis.#cc[chOff + 91] = x5dSendLevel(revSend);
+ upThis.#cc[chOff + 93] = x5dSendLevel(choSend);
+ break;
+ };
+ case 10: {
+ // Control filter
+ upThis.#cc[chOff] = (e & 3) ? 82 : 56;
+ break;
+ };
+ case 11: {
+ // MIDI Rc Ch + Track Switch
+ let midiCh = e & 15,
+ trkSw = e >> 4;
+ upThis.#chReceive[part] = e;
+ if (midiCh != part || trkSw) {
+ console.info(`X5D Part CH${part + 1} receives from CH${midiCh + 1}. Track is ${trkSw ? "inactive" : "active"}.`);
+ upThis.buildRchTree();
+ };
+ };
+ };
+ } else {
+ let part = upThis.chRedir(i - 192, track, true);
+ // What the heck is pitch bend range 0xF4(-12) to 0x0C(12)?
+ };
+ });
+ }).add([66, 48, 54, 76, 0], function (msg, track) {
+ // X5D program dump
+ upThis.switchMode("x5d", true);
+ let name = "", msb = 82, prg = 0, lsb = 0;
+ let voiceMap = "MSB\tPRG\tLSB\tNME";
+ korgFilter(msg, function (e, i) {
+ if (i < 16400) {
+ let p = i % 164;
+ switch (true) {
+ case (p < 10): {
+ if (e > 31) {
+ name += String.fromCharCode(e);
+ };
+ break;
+ };
+ case (p == 11): {
+ voiceMap += `\n${msb}\t${prg}\t${lsb}\t${name.trim().replace("Init Voice", "")}`;
+ prg ++;
+ name = "";
+ break;
+ };
+ };
+ if (prg > 99) {
+ msb = 90;
+ prg = 0;
+ };
+ };
+ });
+ upThis.dispatchEvent("mapupdate", {
+ clearRange: {
+ msb: 82,
+ prg: [0, 99],
+ lsb: 0
+ },
+ voiceMap
+ });
+ }).add([66, 48, 54, 77, 0], function (msg, track) {
+ // X5D combi dump
+ upThis.switchMode("x5d", true);
+ let name = "", msb = 90, prg = 0, lsb = 0;// CmbB then CmbA
+ let voiceMap = "MSB\tPRG\tLSB\tNME";
+ korgFilter(msg, function (e, i) {
+ if (i < 13600) {
+ let p = i % 136;
+ switch (true) {
+ case (p < 10): {
+ if (e > 31) {
+ name += String.fromCharCode(e);
+ };
+ break;
+ };
+ case (p == 11): {
+ voiceMap += `\n${msb}\t${prg}\t${lsb}\t${name.trim().replace("Init Combi", "")}`;
+ prg ++;
+ name = "";
+ break;
+ };
+ };
+ };
+ });
+ upThis.dispatchEvent("mapupdate", {
+ clearRange: {
+ msb: 90,
+ prg: [0, 99],
+ lsb: 0
+ },
+ voiceMap
+ });
+ }).add([66, 48, 66, 54], function (msg, track) {
+ // NS5R program dump
+ upThis.switchMode("ns5r", true);
+ let name = "", msb = 80, prg = 0, lsb = 0;
+ let voiceMap = "MSB\tPRG\tLSB\tNME";
+ korgFilter(msg, function (e, i) {
+ let p = i % 158;
+ switch (true) {
+ case (p < 10): {
+ if (e > 31) {
+ name += String.fromCharCode(e);
+ };
+ break;
+ };
+ case (p == 11): {
+ msb = e;
+ break;
+ };
+ case (p == 12): {
+ lsb = e;
+ break;
+ };
+ case (p == 13): {
+ voiceMap += `\n${msb}\t${prg}\t${lsb}\t${name.trim()}`;
+ prg ++;
+ name = "";
+ break;
+ };
+ };
+ });
+ upThis.dispatchEvent("mapupdate", {
+ clearRange: {
+ msb: 80,
+ lsb: 0
+ },
+ voiceMap
+ });
+ }).add([66, 48, 66, 52], function (msg) {
+ // KORG NS5R/NX5R System Exclusive
+ // Current effect dump, but cannot find parsing docs.
+ upThis.switchMode("ns5r", true);
+ upThis.#modeKaraoke = false;
+ //console.debug(`NS5R effect dump: `, msg);
+ }).add([66, 48, 66, 53], function (msg) {
+ // NS5R Current multi dump
+ upThis.switchMode("ns5r", true);
+ korgFilter(msg, function (e, i) {
+ switch (true) {
+ case i < 2944: {
+ // 32 part setup params, 2944 bytes
+ let part = Math.floor(i / 92),
+ chOff = part * 128;
+ switch (i % 92) {
+ case 0: {
+ // MSB Bank
+ upThis.#cc[chOff] = e;
+ break;
+ };
+ case 1: {
+ // LSB Bank
+ upThis.#cc[chOff + 32] = e;
+ break;
+ };
+ case 2: {
+ // Program
+ upThis.#prg[part] = e;
+ if (e > 0) {
+ upThis.#chActive[part] = 1;
+ };
+ break;
+ };
+ case 3: {
+ // Receive MIDI channel
+ upThis.#chReceive[part] = e;
+ if (part != e) {
+ console.info(`NS5R CH${part + 1} receives from CH${e + 1}.`);
+ upThis.buildRchTree();
+ };
+ };
+ case 7: {
+ // 0 for melodic, 1 for drum, 2~5 for mod drums 1~4
+ break;
+ };
+ case 8: {
+ // Coarse Tune
+ upThis.#rpn[part * allocated.rpn + 3] = (e < 40 || e > 88) ? e + (e > 63 ? -192 : 64) : e;
+ break;
+ };
+ case 9: {
+ // Fine Tune
+ // This is trying to use absolute values.
+ };
+ case 10: {
+ // Volume
+ upThis.#cc[chOff + 7] = e;
+ break;
+ };
+ case 11: {
+ // Expression
+ upThis.#cc[chOff + 11] = e;
+ break;
+ };
+ case 14: {
+ // Pan
+ upThis.#cc[chOff + 10] = e || 128;
+ break;
+ };
+ case 19: {
+ // Chorus
+ upThis.#cc[chOff + 93] = e;
+ break;
+ };
+ case 20: {
+ // Reverb
+ upThis.#cc[chOff + 91] = e;
+ break;
+ };
+ case 84: {
+ // Portamento Switch
+ upThis.#cc[chOff + 65] = e;
+ break;
+ };
+ case 85: {
+ // Portamento Time
+ upThis.#cc[chOff + 5] = e;
+ break;
+ };
+ };
+ break;
+ };
+ case i < 3096: {
+ // part common params, 152 bytes
+ break;
+ };
+ case i < 3134: {
+ // currnet effect params, 38 bytes
+ break;
+ };
+ case i < 8566: {
+ // 4 mod drum params, 5432 bytes
+ break;
+ };
+ };
+ });
+ });
+ // Yamaha XG Drum Setup SysEx
+ // Refactor this!
+ upThis.#seXgDrumInst.add([0], function (msg, setupNum, noteNum) {
+ console.debug(`XG Drum ${setupNum} note ${noteNum} coarse pitch bend ${msg[0] - 64}.`);
+ }).add([1], function (msg, setupNum, noteNum) {
+ console.debug(`XG Drum ${setupNum} note ${noteNum} fine pitch bend ${msg[0] - 64}.`);
+ }).add([2], function (msg, setupNum, noteNum) {
+ console.debug(`XG Drum ${setupNum} note ${noteNum} level ${msg[0]}.`);
+ }).add([3], function (msg, setupNum, noteNum) {
+ console.debug(`XG Drum ${setupNum} note ${noteNum} alt group ${msg[0]}.`);
+ }).add([4], function (msg, setupNum, noteNum) {
+ console.debug(`XG Drum ${setupNum} note ${noteNum} pan ${msg[0] - 64}.`);
+ }).add([5], function (msg, setupNum, noteNum) {
+ console.debug(`XG Drum ${setupNum} note ${noteNum} reverb send ${toDecibel(msg[0])}dB.`);
+ }).add([6], function (msg, setupNum, noteNum) {
+ console.debug(`XG Drum ${setupNum} note ${noteNum} chorus send ${toDecibel(msg[0])}dB.`);
+ }).add([7], function (msg, setupNum, noteNum) {
+ console.debug(`XG Drum ${setupNum} note ${noteNum} variation send ${toDecibel(msg[0])}dB.`);
+ }).add([8], function (msg, setupNum, noteNum) {
+ console.debug(`XG Drum ${setupNum} note ${noteNum} key assign as ${msg[0] > 0 ? "multi" : "single"}.`);
+ }).add([9], function (msg, setupNum, noteNum) {
+ // Note off send
+ }).add([10], function (msg, setupNum, noteNum) {
+ // Note on send
+ }).add([11], function (msg, setupNum, noteNum) {
+ // Filter cutoff (brightness)
+ }).add([12], function (msg, setupNum, noteNum) {
+ // Filter resonance
+ }).add([13], function (msg, setupNum, noteNum) {
+ // EG attack rate
+ }).add([14], function (msg, setupNum, noteNum) {
+ // EG decay 1 rate
+ }).add([15], function (msg, setupNum, noteNum) {
+ // EG decay 2 rate
+ });
+ // Yamaha XG Part Setup SysEx
+ // Refactor this!
+ upThis.#seXgPart.add([0], function (msg, channel) {
+ console.debug(`XG Part reserve ${msg[0]} elements for channel ${channel}.`);
+ }).add([1], function (msg, channel) {
+ // Same as cc0
+ upThis.#cc[channel * 128] = msg[0];
+ }).add([2], function (msg, channel) {
+ // Same as cc32
+ upThis.#cc[channel * 128 + 32] = msg[0];
+ }).add([3], function (msg, channel) {
+ // Same as program change
+ upThis.#prg[channel] = msg[0];
+ }).add([4], function (msg, channel) {
+ // Change receive channel. May require channel redirect feature to be implemented!
+ upThis.#chReceive[channel] = msg[0];
+ if (channel != msg[0]) {
+ console.info(`XG Part CH${channel + 1} receives from CH${msg[0] + 1}.`);
+ upThis.buildRchTree();
+ };
+ }).add([5], function (msg, channel) {
+ // Mono/poly switching
+ console.debug(`XG Part mono/poly set to ${msg[0] ? "mono" : "poly"} for channel ${channel}.`);
+ }).add([6], function (msg, channel) {
+ // Same note number key on assign (what does this mean???)
+ console.debug(`XG Part repeat pressing set to ${["single", "multi", "inst"][msg[0]]} mode for channel ${channel}.`);
+ }).add([7], function (msg, channel) {
+ let data = msg[0];
+ upThis.#cc[128 * channel] = data > 1 ? 127 : 0;
+ console.debug(`XG Part use mode "${xgPartMode[data]}" for channel ${channel}.`);
+ }).add([14], function (msg, channel) {
+ //console.debug(`XG Part panning for channel ${channel}: ${msg[0]}.`);
+ upThis.#cc[128 * channel + 10] = msg[0] || 128;
+ }).add([17], function (msg, channel) {
+ console.debug(`XG Part dry level ${msg[0]} for channel ${channel}.`);
+ }).add([18], function (msg, channel) {
+ console.debug(`XG Part chorus send ${toDecibel(msg[0])}dB for channel ${channel}.`);
+ }).add([19], function (msg, channel) {
+ console.debug(`XG Part reverb send ${toDecibel(msg[0])}dB for channel ${channel}.`);
+ }).add([20], function (msg, channel) {
+ console.debug(`XG Part variation send ${toDecibel(msg[0])}dB for channel ${channel}.`);
+ }).add([21], function (msg, channel) {
+ console.debug(`XG Part LFO speed ${msg[0]} for channel ${channel}.`);
+ }).add([29], function (msg, channel) {
+ console.debug(`XG Part MW bend ${msg[0] - 64} semitones for channel ${channel}.`);
+ }).add([32], function (msg, channel) {
+ console.debug(`XG Part MW LFO pitch depth ${msg[0]} for channel ${channel}.`);
+ }).add([33], function (msg, channel) {
+ console.debug(`XG Part MW LFO filter depth ${msg[0]} for channel ${channel}.`);
+ }).add([35], function (msg, channel) {
+ upThis.#rpn[channel * allocated.rpn + 3] = msg[0];
+ //console.debug(`XG Part bend pitch ${msg[0] - 64} semitones for channel ${channel}.`);
+ }).add([83], function (msg, channel) {
+ // Polyphonic aftertouch (PAT) pitch control
+ //console.debug(`XG Part PAT pitch ${msg[0] - 64} semitones for channel ${channel}.`);
+ }).add([103], function (msg, channel) {
+ // Same as cc65
+ upThis.#cc[channel * 128 + 65] = msg[0];
+ }).add([104], function (msg, channel) {
+ // Same as cc5
+ upThis.#cc[channel * 128 + 5] = msg[0];
+ }).add([105], function (msg, channel) {
+ console.debug(`XG Part EG initial ${msg[0] - 64} for channel ${channel}.`);
+ }).add([106], function (msg, channel) {
+ console.debug(`XG Part EG attack time ${msg[0] - 64} for channel ${channel}.`);
+ });
+ // Roland GS Part Setup SysEx
+ // Refactor this!
+ upThis.#seGsPart.add([0], function (msg, channel) {
+ // Same as cc00 and program change
+ if (upThis.#cc[channel * 128] == 120) {
+ msg[0] = 120;
+ };
+ upThis.#cc[channel * 128] = msg[0] || 0;
+ upThis.#prg[channel] = msg[1] || 0;
+ }).add([2], function (msg, channel, track) {
+ // Channel redirect might be required
+ // 3 to 18 controls whether to receive messages. Not implemented for now.
+ let targetCh = upThis.chRedir(msg[0], track, true);
+ upThis.#chReceive[channel] = targetCh;
+ if (channel != targetCh) {
+ console.info(`GS Part CH${channel + 1} receives from CH${targetCh + 1.}.`);
+ upThis.buildRchTree();
+ };
+ }).add([19], function (msg, channel) {
+ // Switch to mono (0) or poly (1)
+ }).add([20], function (msg, channel) {
+ // Switch assign mode
+ }).add([21], function (msg, channel) {
+ // Channel use rhythm or not
+ // Only two drum kits can even be used at the same time
+ console.debug(`GS Part ${channel + 1} type: ${["melodic", "drum 1", "drum 2"][msg[0]]}.`);
+ if (msg[0] > 0) {
+ upThis.#cc[channel * 128] = 120;
+ };
+ }).add([25], function (msg, channel) {
+ // Set volume
+ upThis.#cc[channel * 128 + 7] = msg[0];
+ }).add([28], function (msg, channel) {
+ // Set pan
+ upThis.#cc[channel * 128 + 10] = msg[0] || 128;
+ }).add([33], function (msg, channel) {
+ // Set chorus
+ upThis.#cc[channel * 128 + 93] = msg[0];
+ }).add([34], function (msg, channel) {
+ // Set reverb
+ upThis.#cc[channel * 128 + 91] = msg[0];
+ });
+ // Roland GS Part Properties
+ // Refactor this!
+ upThis.#seGsPartProp.add([0], function(msg, channel) {
+ upThis.#cc[channel * 128 + 32] = msg[0];
+ }).add([1], function(msg, channel) {
+ // This should be per-channel subLsb, but currently not implemented, sooooo...
+ upThis.#cc[channel * 128 + 32] = msg[0];
+ }).add([32], function(msg, channel) {
+ console.debug(`GS Part ${channel + 1} turned EQ ${msg[0] ? "on" : "off"}.`);
+ }).add([33], function(msg, channel) {
+ // GS output assign
+ }).add([34], function(msg, channel) {
+ console.debug(`GS Part ${channel + 1} turned EFX ${msg[0] ? "on" : "off"}.`);
+ });
+ };
+};
+
+export {
+ OctaviaDevice,
+ ccToPos
+};
diff --git a/src/state/utils.js b/src/state/utils.js
new file mode 100644
index 00000000..c7cfa8ca
--- /dev/null
+++ b/src/state/utils.js
@@ -0,0 +1,77 @@
+"use strict";
+
+let toDecibel = function (data = 64) {
+ return Math.round(2000 * Math.log10(data / 64)) / 100;
+};
+
+let customInterpreter = function (type, file, rawMtLen) {
+ let u8Data = [];
+ let metaLength = rawMtLen == false ? file.readIntVLV() : rawMtLen;
+ if (type == 0 || type == 127) {
+ //metaLength = 1;
+ };
+ for (let c = 0; c < metaLength; c ++) {
+ let byte = file.readInt(1);
+ u8Data.push(byte);
+ if (byte == 247) {
+ // End of SysEx
+ } else if (byte == 240) {
+ // Start of a new SysEx
+ } else if (byte > 127) {
+ // Start of a new event
+ console.debug(`Early termination: ${u8Data}`);
+ u8Data.pop();
+ file.backOne();
+ file.backOne();
+ return new Uint8Array(u8Data);
+ };
+ };
+ //console.debug(`Constructed data: `, u8Data);
+ return new Uint8Array(u8Data);
+};
+
+let gsChecksum = function (sequence) {
+ // Only pass along the three-byte address and their data.
+ let checksum = 0;
+ sequence.forEach((e) => {
+ checksum += e;
+ checksum = checksum & 127; // Prevent going out of range
+ });
+ return (~checksum + 1) & 127;
+};
+
+// Why KORG adds a byte every seven bytes is a mistery to me.
+let korgFilter = function (korgArr, iterator) {
+ let realData = 0, dataMask = 0;
+ for (let pointer = 0; pointer < korgArr.length; pointer ++) {
+ let shifts = pointer % 8 - 1,
+ unmasked = (((dataMask >> shifts) & 1) << 7),
+ e = korgArr[pointer];
+ e += unmasked;
+ if (pointer % 8 != 0) {
+ iterator(e, realData, korgArr);
+ //console.debug(`Unmasked: ${dataMask} >> ${shifts} = ${e}`);
+ realData ++;
+ } else {
+ dataMask = korgArr[pointer];
+ //console.debug(`Overlay mask: ${dataMask}`);
+ };
+ };
+};
+
+let x5dSendLevel = function (sendParam) {
+ let res = Math.floor(sendParam * 14.2);
+ if (res < 128) {
+ return res;
+ } else {
+ return 0;
+ };
+};
+
+export {
+ toDecibel,
+ gsChecksum,
+ korgFilter,
+ x5dSendLevel,
+ customInterpreter
+};
diff --git a/src/state/xgValues.js b/src/state/xgValues.js
new file mode 100644
index 00000000..59e0c8fe
--- /dev/null
+++ b/src/state/xgValues.js
@@ -0,0 +1,315 @@
+"use strict";
+
+const xgEffType = [
+ "off",
+ "hall",
+ "room",
+ "stage",
+ "plate",
+ "delay LCR",
+ "delay LR",
+ "echo",
+ "cross delay",
+ "early reflections",
+ "gate reverb",
+ "reverse gate"
+].concat((new Array(4)), [
+ "white room",
+ "tunnel",
+ "canyon",
+ "basement",
+ "karaoke"
+], new Array(43), [
+ "pass through",
+ "chorus",
+ "celeste",
+ "flanger",
+ "symphonic",
+ "rotary speaker",
+ "tremelo",
+ "auto pan",
+ "phaser",
+ "distortion",
+ "overdrive",
+ "amplifier",
+ "3-band EQ",
+ "2-band EQ",
+ "auto wah"
+], new Array(1), [
+ "pitch change",
+ "harmonic",
+ "touch wah",
+ "compressor",
+ "noise gate",
+ "voice channel",
+ "2-way rotary speaker",
+ "ensemble detune",
+ "ambience"
+], new Array(4), [
+ "talking mod",
+ "Lo-Fi",
+ "dist + delay",
+ "comp + dist + delay",
+ "wah + dist + delay",
+ "V dist",
+ "dual rotor speaker"
+]);
+let xgPartMode = [
+ "melodic",
+ "drums",
+ "drum set 1",
+ "drum set 2",
+ "drum set 3",
+ "drum set 4",
+ "drum set 5",
+ "drum set 6",
+ "drum set 7",
+ "drum set 8"
+];
+let xgDelOffset = [
+ 17.1, 18.6, 20.2, 21.8, 23.3,
+ 24.9, 26.5, 28, 29.6, 31.2,
+ 32.8, 34.3, 35.9, 37.5, 39,
+ 40.6, 42.2, 43.7, 45.3, 46.9,
+ 48.4, 50
+];
+let xgNormFreq = [
+ 20, 22, 25, 28, 32, 36, 40, 45,
+ 50, 56, 63, 70, 80, 90, 100, 110,
+ 125, 140, 160, 180, 200, 225, 250, 280,
+ 315, 355, 400, 450, 500, 560, 630, 700,
+ 800, 900, 1E3, 1100, 1200, 1400, 1600, 1800,
+ 2E3, 2200, 2500, 2800, 3200, 3600, 4E3, 4500,
+ 5E3, 5600, 6300, 7E3, 8E3, 9E3, 1E4, 11E3,
+ 12E3, 14E3, 16E3, 18E3, 2E4
+];
+let xgLfoFreq = [
+ 0, 0.04, 0.08, 0.13, 0.17, 0.21, 0.25, 0.29,
+ 0.34, 0.38, 0.42, 0.46, 0.51, 0.55, 0.59, 0.63,
+ 0.67, 0.72, 0.76, 0.8, 0.84, 0.88, 0.93, 0.97,
+ 1.01, 1.05, 1.09, 1.14, 1.18, 1.22, 1.26, 1.3,
+ 1.35, 1.39, 1.43, 1.47, 1.51, 1.56, 1.6, 1.64,
+ 1.68, 1.72, 1.77, 1.81, 1.85, 1.89, 1.94, 1.98,
+ 2.02, 2.06, 2.10, 2.15, 2.19, 2.23, 2.27, 2.31,
+ 2.36, 2.4, 2.44, 2.48, 2.52, 2.57, 2.61, 2.65,
+ 2.69, 2.78, 2.86, 2.94, 3.03, 3.11, 3.2, 3.28,
+ 3.37, 3.45, 3.53, 3.62, 3.7, 3.87, 4.04, 4.21,
+ 4,37, 4.54, 4.71, 4.88, 5.05, 5.22, 5.38, 5.55,
+ 5.72, 6.06, 6.39, 6.73, 7.07, 7.4, 7.74, 8.08,
+ 8.41, 8.75, 9.08, 9.42, 9.76, 10.1, 10.8, 11.4,
+ 12.1, 12.8, 13.5, 14.1, 14.8, 15.5, 16.2, 16.8,
+ 17.5, 18.2, 19.5, 20.9, 22.2, 23.6, 24.9, 26.2,
+ 27.6, 28.9, 30.3, 31.6, 33.0, 34.3, 37.0, 39.7
+];
+let getXgRevTime = function (data) {
+ let a = 0.1, b = -0.3;
+ if (data > 66) {
+ a = 5, b = 315;
+ } else if (data > 56) {
+ a = 1, b = 47;
+ } else if (data > 46) {
+ a = 0.5, b = 18.5;
+ };
+ return a * data - b;
+};
+let getXgDelayOffset = function (data) {
+ if (data > 105) {
+ return xgDelOffset[data - 106];
+ } else if (data > 100) {
+ return data * 1.1 - 100;
+ } else {
+ return data / 10;
+ };
+};
+
+let xgSgVocals = `,a,i,u,e,o,ka,ki,ku,ke,ko,ky,kw,sa,si,su,se,so,sh,ta,ti,tu,te,to,t,ch,t,s,na,ni,nu,ne,no,ny,nn,ha,hi,hu,he,ho,hy,fa,fi,fu,fe,fo,ma,mi,mu,me,mo,my,mm,ya,yu,ye,yo,ra,ri,ru,re,ro,ry,wa,wi,we,wo,ga,gi,gu,ge,go,gy,gw,za,zi,zu,ze,zo,ja,ji,ju,je,jo,jy,da,di,du,de,do,dy,ba,bi,bu,be,bo,by,va,vi,vu,ve,vo,pa,pi,pu,pe,po,py,nga,ngi,ngu,nge,ngo,ngy,ng,hha,hhi,hhu,hhe,hho,hhy,hhw,*,_,,,~,.`.split(",");
+let xgSgMap = {};
+`hi*,
+ka,か
+ki,き
+ku,く
+ke,け
+ko,こ
+ky,き!
+kw,くl
+tsu,つ
+ts,つl
+sa,さ
+si,すぃ
+su,す
+se,せ
+so,そ
+shi,し
+sh,し!
+ta,た
+ti,てぃ
+tu,とぅ
+te,て
+to,と
+tchy,ち!
+tchi,ち
+na,な
+ni,に
+nu,ぬ
+ne,ね
+no,の
+ny,に!
+nn,ん
+ha,は
+hi,ひ
+hu,ほぅ
+he,へ
+ho,ほ
+hy,ひ!
+fa,ふぁ
+fi,ふぃ
+fu,ふ
+fe,ふぇ
+fo,ふぉ
+ma,ま
+mi,み
+mu,む
+me,め
+mo,も
+my,み!
+mm,
+ra,ら
+ri,り
+ru,る
+re,れ
+ro,ろ
+ry,り!
+wa,わ
+wi,うぃ
+we,うぇ
+wo,を
+nga,ガ
+ngi,ギ
+ngu,グ
+nge,ゲ
+ngo,ゴ
+ngy,ギ!
+ng,
+ga,が
+gi,ぎ
+gu,ぐ
+ge,げ
+go,ご
+gy,ぎ!
+gw,ぐl
+za,ざ
+zi,ずぃ
+zu,ず
+ze,ぜ
+zo,ぞ
+ja,じゃ
+ji,じ
+ju,じゅ
+je,じぇ
+jo,じょ
+jy,じ!
+da,だ
+di,でぃ
+du,どぅ
+de,で
+do,ど
+dy,で!
+ba,ば
+bi,び
+bu,ぶ
+be,べ
+bo,ぼ
+by,び!
+va,ゔぁ
+vi,ゔぃ
+vu,ゔ
+ve,ゔぇ
+vo,ゔぉ
+pa,ぱ
+pi,ぴ
+pu,ぷ
+pe,ペ
+po,ぽ
+py,ぴ!
+!ya,ゃ
+!yu,ゅ
+!ye,ぇ
+!yo,ょ
+ya,や
+yu,ゆ
+ye,いぇ
+yo,よ
+!a,ゃ
+!u,ゅ
+!e,ぇ
+!o,ょ
+!a,ゃ
+!u,ゅ
+!e,ぇ
+!o,ょ
+la,ぁ
+li,ぃ
+lu,ぅ
+le,ぇ
+lo,ぉ
+a,あ
+i,い
+u,う
+e,え
+o,お
+*,っ
+~,
+^,
+_,`.split("\n").forEach((e) => {
+ let param = e.split(",");
+ xgSgMap[param[0]] = param[1];
+});
+let getSgKana = function (seq) {
+ let target = seq;
+ if (seq[0] == "*") {
+ target = target.slice(1);
+ };
+ // Lengthened vowel remover
+ ["aa", "ii", "uu", "ee", "oo"].forEach((e) => {
+ while (target.indexOf(e) > -1) {
+ target = target.replace(e, e[0]);
+ };
+ });
+ // Replacement based on the conversion table
+ for (let mark in xgSgMap) {
+ target = target.replaceAll(mark, xgSgMap[mark]);
+ };
+ // Removing the unnecessary ん prefix
+ if (target.indexOf("ん") == 0 && target.length > 1) {
+ target = target.slice(1);
+ };
+ // Removing the trailing special charecters
+ let youOn = target.indexOf("!");
+ if (youOn > -1 && target.length > 1) {
+ target = target.slice(youOn + 1);
+ };
+ return target;
+};
+
+let getVlCtrlSrc = function (ctrlNo) {
+ if (!ctrlNo) {
+ return "off";
+ } else if (ctrlNo < 96) {
+ return `cc${ctrlNo}`;
+ } else {
+ return ["aftertouch", "velocity", "pitch bend"][ctrlNo - 96];
+ };
+};
+
+export {
+ xgEffType,
+ xgPartMode,
+ xgSgVocals,
+ xgDelOffset,
+ xgNormFreq,
+ xgLfoFreq,
+ getSgKana,
+ getXgRevTime,
+ getXgDelayOffset,
+ getVlCtrlSrc
+};
diff --git a/src/state_skim/index.mjs b/src/state_skim/index.mjs
new file mode 100644
index 00000000..f5c4887f
--- /dev/null
+++ b/src/state_skim/index.mjs
@@ -0,0 +1,1411 @@
+"use strict";
+
+import {BinaryMatch} from "../../libs/lightfelt@ltgcgo/ext/binMatch.js";
+import {CustomEventSource} from "../../libs/lightfelt@ltgcgo/ext/customEvents.js";
+import {VoiceBank} from "../state/bankReader.js";
+
+const modeIdx = [
+ "?",
+ "gm", "gs", "xg", "g2",
+ "mt32", "ns5r",
+ "ag10", "x5d", "05rw", "krs",
+ "k11", "sg"
+];
+const substList = [
+ [0, 0, 0, 0, 121, 0, 0, 56, 82, 81, 63, 0, 0],
+ [0, 0, 4, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0]
+];
+const drumMsb = [120, 127, 120, 127, 120, 127, 61, 62, 62, 62, 120, 122, 122];
+const passedMeta = [0, 3, 81, 84, 88]; // What is meta event 32?
+const eventTypes = {
+ 8: "Off",
+ 9: "On",
+ 10: "Note aftertouch",
+ 11: "cc",
+ 12: "pc",
+ 13: "Channel aftertouch",
+ 14: "Pitch"
+};
+
+const useRpnMap = {
+ 0: 0,
+ 1: 1,
+ 2: 3,
+ 5: 4
+},
+rpnCap = [
+ [0, 24],
+ [0, 127],
+ [0, 127],
+ [40, 88],
+ [0, 127],
+ [0, 127]
+],
+useNormNrpn = [36, 37],
+useDrumNrpn = [20, 21, 22, 23, 24, 25, 26, 28, 29, 30, 31, 36, 37, 64, 65],
+ccAccepted = [
+ 0, 1, 2, 4, 5, 6, 7, 8, 10, 11, 32,
+ 38, 64, 65, 66, 67, 68, 69, 70, 71,
+ 72, 73, 74, 75, 76, 77, 78, 84, 91,
+ 92, 93, 94, 95, 98, 99, 100, 101,
+ 12, 13, // General-purpose effect controllers
+ 16, 17, 18, 19 // General-purpose sound controllers
+], // 96, 97, 120 to 127 all have special functions
+nrpnCcMap = [33, 99, 100, 32, 102, 8, 9, 10]; // cc71 to cc78
+
+const korgDrums = [0, 16, 25, 40, 32, 64, 26, 48];
+
+let modeMap = {};
+modeIdx.forEach((e, i) => {
+ modeMap[e] = i;
+});
+let ccToPos = {
+ length: ccAccepted.length
+};
+ccAccepted.forEach((e, i) => {
+ ccToPos[e] = i;
+});
+
+let getDebugState = function () {
+ return !!self.Bun || self.debugMode || false; // If run on Bun.js, output all possible logs
+};
+let sysExSplitter = function (seq) {
+ let seqArr = [];
+ let seqStart = 0;
+ seq?.forEach(function (e, i) {
+ if (e == 247) {
+ // End of SysEx
+ seqArr.push(seq.subarray(seqStart, i));
+ } else if (e == 240) {
+ seqStart = i + 1;
+ } else {
+ //seqArr[seqArr.length - 1].push(e);
+ };
+ });
+ if (!seqArr.length) {
+ seqArr.push(seq.subarray(0));
+ };
+ if (getDebugState()) {
+ //console.info(seqArr);
+ };
+ return seqArr;
+};
+let showTrue = function (data, prefix = "", suffix = "", length = 2) {
+ return data ? `${prefix}${data.toString().padStart(length, "0")}${suffix}` : "";
+};
+
+const allocated = {
+ ch: 128, // channels
+ cc: ccAccepted.length, // control changes
+ nn: 128, // notes per channel
+ pl: 512, // polyphony
+ tr: 256, // tracks
+ cmt: 14, // C/M timbre storage size
+ rpn: 6,
+};
+
+let OctaviaDevice = class extends CustomEventSource {
+ // Values
+ #mode = 0;
+ #bitmapPage = 0;
+ #bitmapExpire = 0;
+ #bitmapStore = new Array(11); // 10 pages of bitmaps, 1 KORG bitmap
+ get #bitmap() {
+ return this.#bitmapStore[this.#bitmapPage];
+ };
+ set #bitmap(value) {
+ this.#bitmapStore[this.#bitmapPage] = value;
+ };
+ #chActive = new Uint8Array(allocated.ch); // Whether the channel is in use
+ #chReceive = new Uint8Array(allocated.ch); // Determine the receiving channel
+ #cc = new Uint8ClampedArray(allocated.ch * allocated.cc); // 64 channels, 128 controllers
+ #prg = new Uint8ClampedArray(allocated.ch);
+ #velo = new Uint8ClampedArray(allocated.ch * allocated.nn); // 64 channels. 128 velocity registers
+ #mono = new Uint8Array(allocated.ch); // Mono/poly mode
+ #poly = new Uint16Array(allocated.pl); // 512 polyphony allowed
+ #polyState = new Uint8Array(allocated.pl); // State of each active voice.
+ #pitch = new Int16Array(allocated.ch); // Pitch for channels, from -8192 to 8191
+ #rawStrength = new Uint8Array(allocated.ch);
+ #dataCommit = 0; // 0 for RPN, 1 for NRPN
+ #rpn = new Uint8Array(allocated.ch * allocated.rpn); // RPN registers (0 pitch MSB, 1 fine tune MSB, 2 fine tune LSB, 3 coarse tune MSB, 4 mod sensitivity MSB, 5 mod sensitivity LSB)
+ #nrpn = new Int8Array(allocated.ch * useNormNrpn.length); // Normal section of NRPN registers
+ #bnCustom = new Uint8Array(allocated.ch); // Custom name activation
+ #cmTPatch = new Uint8Array(128); // C/M part patch storage
+ #cmTTimbre = new Uint8Array(allocated.cmt * 8); // C/M part timbre storage
+ #cmPatch = new Uint8Array(1024); // C/M device patch storage
+ #cmTimbre = new Uint8Array(allocated.cmt * 64); // C/M device timbre storage (64)
+ #subMsb = 0; // Allowing global bank switching
+ #subLsb = 0;
+ #masterVol = 100;
+ #metaChannel = 0;
+ #noteLength = 500;
+ #convertLastSyllable = 0;
+ #letterDisp = "";
+ #letterExpire = 0;
+ #selectPort = 0;
+ #receiveRS = true; // Receive remote switch
+ #modeKaraoke = false;
+ #receiveTree;
+ // Temporary EFX storage
+ #gsEfxSto = new Uint8Array(2);
+ // Metadata text events
+ #metaTexts = [];
+ // GS Track Occupation
+ #trkRedir = new Uint8Array(allocated.ch);
+ #trkAsReq = new Uint8Array(allocated.tr); // Track Assignment request
+ baseBank = new VoiceBank("gm", "gm2", "xg", "gs", "ns5r", "gmega", "plg-150vl", "plg-150pf", "plg-150dx", "plg-150an", "plg-150dr", "plg-100sg", "kross"); // Load all possible voice banks
+ userBank = new VoiceBank("gm"); // User-defined bank for MT-32, X5DR and NS5R
+ initOnReset = false; // If this is true, Octavia will re-init upon mode switches
+ chRedir(part, track, noConquer) {
+ if (this.#trkAsReq[track]) {
+ // Allow part assigning via meta
+ let metaChosen = (this.#trkAsReq[track] - 1) * 16 + part;
+ return metaChosen;
+ } else if ([modeMap.gs, modeMap.ns5r].indexOf(this.#mode) > -1) {
+ // Do not conquer channels if requested.
+ if (noConquer == 1) {
+ return part;
+ };
+ let shift = 0, unmet = true;
+ while (unmet) {
+ if (this.#trkRedir[part + shift] == 0) {
+ this.#trkRedir[part + shift] = track;
+ console.debug(`Assign track ${track} to channel ${part + shift + 1}.`);
+ unmet = false;
+ } else if (this.#trkRedir[part + shift] == track) {
+ unmet = false;
+ } else {
+ shift += 16;
+ if (shift >= 128) {
+ shift = 0;
+ unmet = false;
+ };
+ };
+ };
+ return part + shift;
+ } else {
+ return part;
+ };
+ };
+ // Exec Pools
+ // Meta event pool
+ #metaRun = [];
+ // Sequencer specific meta pool
+ #metaSeq;
+ // Universal actions
+ #ua = {
+ nOff: (part, note) => {
+ // Note off
+ let rawNote = part * 128 + note;
+ let polyIdx = this.#poly.lastIndexOf(rawNote);
+ if (polyIdx > -1) {
+ if (this.#cc[allocated.cc * part + ccToPos[64]] > 63 && !this.config?.disableCc64) {
+ // Held by cc64
+ this.#polyState[polyIdx] = 4;
+ } else {
+ this.#poly[polyIdx] = 0;
+ this.#velo[rawNote] = 0;
+ this.#polyState[polyIdx] = 0;
+ };
+ };
+ },
+ nOn: (part, note, velo) => {
+ // Note on
+ let rawNote = part * 128 + note;
+ let place = 0;
+ if (this.#mono[part]) {
+ // Shut all previous notes off in mono mode
+ this.#ua.ano(part);
+ };
+ while (this.#polyState[place] > 0 && this.#poly[place] != rawNote) {
+ // If just by judging whether a polyphonic voice is occupied,
+ // "multi" mode is considered active.
+ // If "rawNote" is also taken into consideration,
+ // this will be "single" mode instead.
+ // 0: idle
+ // 1: attack
+ // 2: decay
+ // 3: sustain (active)
+ // 4: hold
+ // 5: sostenuto sustain
+ // 6: sostenuto hold
+ // 7: release
+ place ++;
+ };
+ if (place < allocated.pl) {
+ this.#poly[place] = rawNote;
+ this.#velo[rawNote] = velo;
+ this.#polyState[place] = 3;
+ if (this.#rawStrength[part] < velo) {
+ this.#rawStrength[part] = velo;
+ };
+ //console.debug(place);
+ } else {
+ console.error("Polyphony exceeded.");
+ };
+ },
+ nAt: (part, note, velo) => {
+ // Note/polyphonic aftertouch
+ },
+ cAt: (part, velo) => {
+ // Channel aftertouch
+ },
+ hoOf: (part) => {
+ // Scan and turn off all notes held by cc64
+ this.#polyState.forEach((e, i) => {
+ if (e == 4) {
+ // Held by cc64
+ let rawNote = this.#poly[i];
+ let channel = rawNote >> 7;
+ if (part == channel) {
+ this.#polyState[i] = 0;
+ this.#poly[i] = 0;
+ this.#velo[rawNote] = 0;
+ };
+ };
+ });
+ },
+ soOf: (part) => {
+ // Scan and turn off all notes held by cc66
+ },
+ ano: (part) => {
+ // All notes off
+ // Current implementation uses the static velocity register
+ this.#poly.forEach((e, i, a) => {
+ let ch = e >> 7, no = e & 127;
+ if (e == 0 && this.#velo[0] == 0) {
+ } else if (ch == part) {
+ this.#ua.nOff(ch, no);
+ };
+ });
+ }
+ };
+ // Channel event pool
+ #runChEvent = {
+ 8: function (det) {
+ let part = det.channel;
+ // Note off, velocity should be ignored.
+ let rawNote = det.data[0];
+ this.#ua.nOff(part, rawNote);
+ },
+ 9: function (det) {
+ let part = det.channel;
+ // Note on, but should be off if velocity is 0.
+ // Set channel active
+ this.#chActive[part] = 1;
+ let rawNote = det.data[0];
+ let velocity = det.data[1];
+ if (velocity > 0) {
+ this.#ua.nOn(part, rawNote, velocity);
+ } else {
+ this.#ua.nOff(part, rawNote);
+ };
+ },
+ 10: function (det) {
+ let part = det.channel;
+ // Note aftertouch.
+ // Currently it directly changes velocity to set value.
+ let rawNote = part * 128 + det.data[0];
+ let polyIdx = this.#poly.indexOf(rawNote);
+ if (polyIdx > -1) {
+ this.#velo[rawNote] = data[1];
+ };
+ },
+ 11: function (det) {
+ let part = det.channel;
+ // CC event, directly assign values to the register.
+ this.#chActive[part] = 1;
+ let chOffset = part * allocated.cc;
+ // Non-store CC messages
+ switch (det.data[0]) {
+ case 96: {
+ // RPN Data increment
+ return;
+ break;
+ };
+ case 97: {
+ // RPN Data decrement
+ return;
+ break;
+ };
+ case 120: {
+ // All sound off, but keys stay on
+ return;
+ break;
+ };
+ case 121: {
+ // Reset controllers
+ this.#ua.ano(part);
+ this.#pitch[part] = 0;
+ let chOff = part * allocated.cc;
+ // Reset to zero
+ this.#cc[chOff + ccToPos[1]] = 0; // Modulation
+ this.#cc[chOff + ccToPos[5]] = 0; // Portamento Time
+ this.#cc[chOff + ccToPos[64]] = 0; // Sustain
+ this.#cc[chOff + ccToPos[65]] = 0; // Portamento
+ this.#cc[chOff + ccToPos[66]] = 0; // Sostenuto
+ this.#cc[chOff + ccToPos[67]] = 0; // Soft Pedal
+ // Reset to full
+ this.#cc[chOff + ccToPos[11]] = 127; // Expression
+ // RPN/NRPN to null
+ this.#cc[chOff + ccToPos[101]] = 127;
+ this.#cc[chOff + ccToPos[100]] = 127;
+ this.#cc[chOff + ccToPos[99]] = 127;
+ this.#cc[chOff + ccToPos[98]] = 127;
+ return;
+ break;
+ };
+ case 123: {
+ // All notes off
+ this.#ua.ano(part);
+ return;
+ break;
+ };
+ case 124: {
+ // Omni off
+ this.#ua.ano(part);
+ return;
+ break;
+ };
+ case 125: {
+ // Omni on
+ this.#ua.ano(part);
+ return;
+ break;
+ };
+ case 126: {
+ // Mono mode
+ this.#mono[part] = 1;
+ this.#ua.ano(part);
+ return;
+ break;
+ };
+ case 127: {
+ // Poly mode
+ this.#mono[part] = 0;
+ this.#ua.ano(part);
+ return;
+ break;
+ };
+ };
+ // Check if control change is accepted
+ if (ccToPos[det.data[0]] == undefined) {
+ console.warn(`cc${det.data[0]} is not accepted.`);
+ } else {
+ // Stored CC messages
+ switch (det.data[0]) {
+ case 0: {
+ // Detect mode via bank MSB
+ if (getDebugState()) {
+ console.debug(`${modeIdx[this.#mode]}, CH${part + 1}: ${det.data[1]}`);
+ };
+ if (this.#mode == 0) {
+ if (det.data[1] < 48) {
+ // Do not change drum channel to a melodic
+ if (this.#cc[chOffset] > 119) {
+ det.data[1] = this.#cc[chOffset];
+ det.data[1] = 120;
+ console.debug(`Forced channel ${part + 1} to stay drums.`);
+ };
+ if (det.data[1] > 0) {
+ console.debug(`Roland GS detected with MSB: ${det.data[1]}`);
+ this.switchMode("gs");
+ };
+ } else if (det.data[1] == 62) {
+ this.switchMode("x5d");
+ } else if (det.data[1] == 63) {
+ this.switchMode("krs");
+ } else if (det.data[1] == 64 || det.data[1] == 127) {
+ this.switchMode("xg");
+ };
+ } else if (this.#mode == modeMap.gs) {
+ if (det.data[1] < 56) {
+ // Do not change drum channel to a melodic
+ if (this.#cc[chOffset] > 119) {
+ det.data[1] = this.#cc[chOffset];
+ det.data[1] = 120;
+ console.debug(`Forced channel ${part + 1} to stay drums.`);
+ };
+ };
+ } else if (this.#mode == modeMap.gm) {
+ if (det.data[1] < 48) {
+ // Do not change drum channel to a melodic
+ if (this.#cc[chOffset] > 119) {
+ det.data[1] = 120;
+ this.switchMode("gs", true);
+ console.debug(`Forced channel ${part + 1} to stay drums.`);
+ };
+ } else if (det.data[1] == 64 || det.data[1] == 127) {
+ this.switchMode("xg", true);
+ };
+ } else if (this.#mode == modeMap.x5d) {
+ if (det.data[1] > 0 && det.data[1] < 8) {
+ this.switchMode("05rw", true);
+ } else if (det.data[1] == 56) {
+ let agCount = 0;
+ for (let c = 0; c < 16; c ++) {
+ let d = this.#cc[allocated.cc * c];
+ if (d == 56 || d == 62) {
+ agCount ++;
+ };
+ };
+ if (agCount > 14) {
+ this.switchMode("ag10", true);
+ };
+ };
+ };
+ break;
+ };
+ case 6: {
+ // Show RPN and NRPN
+ if (this.#dataCommit) {
+ let msb = this.#cc[chOffset + ccToPos[99]],
+ lsb = this.#cc[chOffset + ccToPos[98]];
+ if (msb == 1) {
+ let toCc = nrpnCcMap.indexOf(lsb);
+ if (toCc > -1) {
+ this.#cc[chOffset + ccToPos[71 + toCc]] = det.data[1];
+ getDebugState() && console.debug(`Redirected NRPN 1 ${lsb} to cc${71 + toCc}.`);
+ } else {
+ let nrpnIdx = useNormNrpn.indexOf(lsb);
+ if (nrpnIdx > -1) {
+ this.#nrpn[part * 10 + nrpnIdx] = det.data[1] - 64;
+ };
+ getDebugState() && console.debug(`CH${part + 1} voice NRPN ${lsb} commit`);
+ };
+ } else {
+ //console.debug(`CH${part + 1} drum NRPN ${msb} commit`);
+ };
+ } else {
+ // Commit supported RPN values
+ let rpnIndex = useRpnMap[this.#cc[chOffset + ccToPos[100]]];
+ if (this.#cc[chOffset + ccToPos[101]] == 0 && rpnIndex != undefined) {
+ getDebugState() && console.debug(`CH${part + 1} RPN 0 ${this.#cc[chOffset + ccToPos[100]]} commit: ${det.data[1]}`);
+ det.data[1] = Math.min(Math.max(det.data[1], rpnCap[rpnIndex][0]), rpnCap[rpnIndex][1]);
+ this.#rpn[part * allocated.rpn + rpnIndex] = det.data[1];
+ };
+ };
+ break;
+ };
+ case 38: {
+ // Show RPN and NRPN
+ if (!this.#dataCommit) {
+ // Commit supported RPN values
+ if (this.#cc[chOffset + 101] == 0 && useRpnMap[this.#cc[chOffset + 100]] != undefined) {
+ this.#rpn[part * allocated.rpn + useRpnMap[this.#cc[chOffset + 100]] + 1] = det.data[1];
+ };
+ } else {
+ //console.debug(`${part + 1} LSB ${det.data[1]} ${this.#dataCommit ? "NRPN" : "RPN"} ${this.#dataCommit ? this.#cc[chOffset + 99] : this.#cc[chOffset + 101]} ${this.#dataCommit ? this.#cc[chOffset + 98] : this.#cc[chOffset + 100]}`);
+ };
+ break;
+ };
+ case 64: {
+ // cc64: hold
+ if (det.data[1] < 64) {
+ this.#ua.hoOf(part);
+ };
+ break;
+ };
+ case 66: {
+ // cc66: sostenuto
+ console.debug(`Sostenuto pedal: ${det.data[1]}`);
+ break;
+ };
+ case 98:
+ case 99: {
+ this.#dataCommit = 1;
+ break;
+ };
+ case 100:
+ case 101: {
+ this.#dataCommit = 0;
+ break;
+ };
+ };
+ this.#cc[chOffset + ccToPos[det.data[0]]] = det.data[1];
+ };
+ },
+ 12: function (det) {
+ let part = det.channel;
+ // Program change
+ this.#chActive[part] = 1;
+ this.#prg[part] = det.data;
+ this.#bnCustom[part] = 0;
+ if (getDebugState()) {
+ console.debug(`T:${det.track} C:${part} P:${det.data}`);
+ };
+ },
+ 13: function (det) {
+ // Channel aftertouch
+ let upThis = this;
+ let part = det.channel;
+ this.#poly.forEach(function (e) {
+ let realCh = e >> 7;
+ if (part == realCh) {
+ upThis.#velo[e] = det.data;
+ };
+ });
+ },
+ 14: function (det) {
+ let part = det.channel;
+ // Pitch bending
+ this.#pitch[part] = det.data[1] * 128 + det.data[0] - 8192;
+ },
+ 15: function (det) {
+ // SysEx
+ sysExSplitter(det.data).forEach((seq) => {
+ let manId = seq[0],
+ deviceId = seq[1];
+ (this.#seMan[manId] || function () {
+ console.debug(`Unknown manufacturer ${manId}.`);
+ })(deviceId, seq.subarray(2), det.track);
+ //upThis.#seMain.run(seq, det.track);
+ });
+ },
+ 248: function (det) {
+ // MIDI clock
+ },
+ 250: function (det) {
+ // MIDI start
+ },
+ 251: function (det) {
+ // MIDI continue
+ },
+ 252: function (det) {
+ // MIDI stop
+ },
+ 254: function (det) {
+ // Active sense
+ },
+ 255: function (det) {
+ // Meta
+ (this.#metaRun[det.meta] || function (data, track, meta) {}).call(this, det.data, det.track, det.meta);
+ if (det.meta != 32) {
+ this.#metaChannel = 0;
+ };
+ let useReply = passedMeta.indexOf(det.meta) > -1;
+ if (useReply) {
+ det.reply = "meta";
+ return det;
+ } else if (getDebugState()) {
+ console.debug(det);
+ };
+ }
+ };
+ // SysEx manufacturer table
+ #seMan = {
+ 64: (id, msg, track) => {
+ // Kawai
+ this.#seKg.run(msg, track, id);
+ },
+ 65: (id, msg, track) => {
+ // Roland
+ // CmdId is usually 18 (DT1)
+ // D-50: [20, CmdId]
+ // C/M: [22, CmdId]
+ // GS: [66, CmdId, HH, MM, LL, ...DD, Checksum]
+ if (msg[0] < 16) {
+ this.#seGs.run(msg, track, id);
+ console.warn(`Unknown device SysEx!`);
+ } else {
+ let sentCs = msg[msg.length - 1];
+ let calcCs = gsChecksum(msg.subarray(2, msg.length - 1));
+ if (sentCs == calcCs) {
+ this.#seGs.run(msg.subarray(0, msg.length - 1), track, id);
+ } else {
+ console.warn(`Bad GS checksum ${sentCs}. Should be ${calcCs}.`);
+ };
+ };
+ },
+ 66: (id, msg, track) => {
+ // Korg
+ this.#seAi.run(msg, track, id);
+ },
+ 67: (id, msg, track) => {
+ // Yamaha
+ // XG: [76, HH, MM, LL, ...DD]
+ this.#seXg.run(msg, track, id);
+ },
+ 68: (id, msg, track) => {
+ // Casio
+ this.#seCs.run(msg, track, id);
+ },
+ 71: (id, msg, track) => {
+ // Akai
+ this.#seSg.run(msg, track, id);
+ },
+ 126: (id, msg, track) => {
+ // Universal non-realtime
+ this.#seUnr.run(msg, track, id);
+ },
+ 127: (id, msg, track) => {
+ // Universal realtime
+ this.switchMode("gm");
+ this.#seUr.run(msg, track, id);
+ }
+ };
+ #seUnr; // Universal non-realtime
+ #seUr; // Universal realtime
+ #seXg; // YAMAHA
+ #seGs; // Roland
+ #seAi; // KORG
+ #seKg; // Kawai
+ #seSg; // Akai
+ #seCs; // Casio
+ buildRchTree() {
+ // Build a receiving tree from currently set receive channels
+ // Now builds from the ground up each time
+ // Can be optimized to move elements instead
+ let tree = [];
+ this.#chReceive.forEach((e, i) => {
+ if (!tree[e]?.constructor) {
+ tree[e] = [];
+ };
+ tree[e].push(i);
+ });
+ this.#receiveTree = tree;
+ //console.debug(tree);
+ };
+ getActive() {
+ let result = this.#chActive.slice();
+ if (this.#mode == modeMap.mt32) {
+ //result[0] = 0;
+ };
+ return result;
+ };
+ getCc(channel) {
+ // Return channel CC registers
+ let start = channel * allocated.cc;
+ let arr = this.#cc.slice(start, start + allocated.cc);
+ arr[ccToPos[0]] = arr[ccToPos[0]] || this.#subMsb;
+ arr[ccToPos[32]] = arr[ccToPos[32]] || this.#subLsb;
+ return arr;
+ };
+ getCcAll() {
+ // Return all CC registers
+ let arr = this.#cc.slice();
+ for (let c = 0; c < allocated.ch; c ++) {
+ let chOff = c * allocated.cc;
+ arr[chOff + ccToPos[0]] = arr[chOff + ccToPos[0]] || this.#subMsb;
+ arr[chOff + ccToPos[32]] = arr[chOff + ccToPos[32]] || this.#subLsb;
+ };
+ return arr;
+ };
+ getPitch() {
+ return this.#pitch;
+ };
+ getProgram() {
+ return this.#prg;
+ };
+ getTexts() {
+ return this.#metaTexts.slice();
+ };
+ getVel(channel) {
+ // Return all pressed keys with velocity in a channel
+ let notes = new Map();
+ let upThis = this;
+ upThis.#poly.forEach(function (e, i) {
+ let realCh = Math.floor(e / 128),
+ realNote = e % 128;
+ if (channel == realCh && upThis.#velo[e] > 0) {
+ notes.set(realNote, {
+ v: upThis.#velo[e], // Short for velocity
+ s: upThis.#polyState[i] // Short for state
+ });
+ };
+ });
+ return notes;
+ };
+ getBitmap() {
+ return {
+ bitmap: this.#bitmap,
+ expire: this.#bitmapExpire
+ };
+ };
+ getLetter() {
+ return {
+ text: this.#letterDisp,
+ expire: this.#letterExpire
+ };
+ };
+ getMode() {
+ return modeIdx[this.#mode];
+ };
+ getMaster() {
+ return {
+ volume: this.#masterVol
+ };
+ };
+ getRawStrength() {
+ // 0 to 127
+ let upThis = this;
+ this.#poly.forEach(function (e) {
+ let channel = Math.floor(e / 128);
+ if (upThis.#velo[e] > upThis.#rawStrength[channel]) {
+ upThis.#rawStrength[channel] = upThis.#velo[e];
+ };
+ });
+ return this.#rawStrength;
+ };
+ getStrength() {
+ // 0 to 255
+ let str = [], upThis = this;
+ this.getRawStrength().forEach(function (e, i) {
+ str[i] = Math.floor(e * upThis.#cc[i * allocated.cc + ccToPos[7]] * upThis.#cc[i * allocated.cc + ccToPos[11]] * upThis.#masterVol / 803288);
+ });
+ return str;
+ };
+ getRpn() {
+ return this.#rpn;
+ };
+ getNrpn() {
+ return this.#nrpn;
+ };
+ getVoice(msbO, prgO, lsbO, mode) {
+ let msb = msbO || this.#subMsb,
+ prg = prgO,
+ lsb = lsbO || this.#subLsb;
+ if (modeIdx[this.#mode] == "ns5r") {
+ if (msb > 0 && msb < 56) {
+ lsb = 3; // Use SC-88 Pro map
+ };
+ };
+ let bank = this.userBank.get(msb, prg, lsb, mode);
+ if (modeIdx[this.#mode] == "mt32") {
+ // Reload MT-32 user bank transparently
+ if (bank.name.indexOf("MT-m:") == 0) {
+ // Device patch
+ let patch = parseInt(bank.name.slice(5)),
+ timbreOff = patch * allocated.cmt,
+ userBank = "";
+ this.#cmTimbre.subarray(timbreOff, timbreOff + 10).forEach((e) => {
+ if (e > 31) {
+ userBank += String.fromCharCode(e);
+ };
+ });
+ this.userBank.load(`MSB\tLSB\tPRG\n0\t127\t${prg}\t${userBank}`, true);
+ bank.name = userBank;
+ bank.ending = " ";
+ };
+ };
+ if (bank.ending != " " || !bank.name.length) {
+ bank = this.baseBank.get(msb, prg, lsb, mode);
+ };
+ return bank;
+ };
+ getChVoice(part) {
+ let voice = this.getVoice(this.#cc[part * allocated.cc + ccToPos[0]], this.#prg[part], this.#cc[part * allocated.cc + ccToPos[32]], modeIdx[this.#mode]);
+ if (this.#bnCustom[part]) {
+ switch (this.#mode) {
+ case modeMap.mt32: {
+ voice.ending = "~";
+ voice.name = "";
+ this.#cmTTimbre.subarray(14 * (part - 1), 14 * (part - 1) + 10).forEach((e) => {
+ if (e > 31) {
+ voice.name += String.fromCharCode(e);
+ };
+ });
+ };
+ };
+ };
+ return voice;
+ };
+ init(type = 0) {
+ // Type 0 is full reset
+ // Type 1 is almost-full reset
+ // Full reset, except the loaded banks
+ this.dispatchEvent("mode", "?");
+ this.#mode = 0;
+ this.#subMsb = 0;
+ this.#subLsb = 0;
+ this.#metaChannel = 0;
+ this.#chActive.fill(0);
+ this.#cc.fill(0);
+ this.#prg.fill(0);
+ this.#velo.fill(0);
+ this.#poly.fill(0);
+ this.#rawStrength.fill(0);
+ this.#pitch.fill(0);
+ this.#nrpn.fill(0);
+ this.#masterVol = 100;
+ this.#metaTexts = [];
+ this.#noteLength = 500;
+ this.#convertLastSyllable = 0;
+ this.#letterExpire = 0;
+ this.#letterDisp = "";
+ this.#bitmapExpire = 0;
+ this.#bitmapPage = 0;
+ this.#bitmap.fill(0);
+ this.#modeKaraoke = false;
+ this.#selectPort = 0;
+ this.#receiveRS = true;
+ // Reset MIDI receive channel
+ this.#chReceive.forEach(function (e, i, a) {
+ a[i] = i;
+ });
+ this.buildRchTree();
+ // Reset channel redirection
+ if (type == 0) {
+ this.#trkRedir.fill(0);
+ this.#trkAsReq.fill(0);
+ };
+ // Channel 10 to drum set
+ this.#cc[allocated.cc * 9] = drumMsb[0];
+ this.#cc[allocated.cc * 25] = drumMsb[0];
+ this.#cc[allocated.cc * 41] = drumMsb[0];
+ this.#cc[allocated.cc * 57] = drumMsb[0];
+ // Reset effect storage
+ this.#gsEfxSto.fill(0);
+ // Reset MT-32 user patch and timbre storage
+ this.#cmPatch.fill(0);
+ this.#cmTimbre.fill(0);
+ this.#cmTPatch.fill(0);
+ this.#cmTTimbre.fill(0);
+ this.#bnCustom.fill(0);
+ // Reset MT-32 user bank
+ this.userBank.clearRange({msb: 0, lsb: 127, prg: [0, 127]});
+ for (let ch = 0; ch < allocated.ch; ch ++) {
+ let chOff = ch * allocated.cc;
+ // Reset to full
+ this.#cc[chOff + ccToPos[7]] = 100; // Volume
+ this.#cc[chOff + ccToPos[11]] = 127; // Expression
+ // Reset to centre
+ this.#cc[chOff + ccToPos[10]] = 64; // Pan
+ this.#cc[chOff + ccToPos[71]] = 64; // Resonance
+ this.#cc[chOff + ccToPos[72]] = 64; // Release Time
+ this.#cc[chOff + ccToPos[73]] = 64; // Attack Time
+ this.#cc[chOff + ccToPos[74]] = 64; // Brightness
+ this.#cc[chOff + ccToPos[75]] = 64; // Decay Time
+ this.#cc[chOff + ccToPos[76]] = 64; // Vibrato Rate
+ this.#cc[chOff + ccToPos[77]] = 64; // Vibrato Depth
+ this.#cc[chOff + ccToPos[78]] = 64; // Vibrato Delay
+ // Extra default values
+ this.#cc[chOff + ccToPos[91]] = 40; // Reverb
+ // RPN/NRPN to null
+ this.#cc[chOff + ccToPos[101]] = 127;
+ this.#cc[chOff + ccToPos[100]] = 127;
+ this.#cc[chOff + ccToPos[99]] = 127;
+ this.#cc[chOff + ccToPos[98]] = 127;
+ // RPN reset
+ let rpnOff = ch * allocated.rpn;
+ this.#rpn[rpnOff] = 2; // Pitch bend sensitivity
+ this.#rpn[rpnOff + 1] = 64; // Fine tune MSB
+ this.#rpn[rpnOff + 2] = 0; // Fine tune LSB
+ this.#rpn[rpnOff + 3] = 64; // Coarse tune MSB
+ this.#rpn[rpnOff + 4] = 0; // Mod sensitivity MSB
+ this.#rpn[rpnOff + 5] = 0; // Mod sensitivity LSB
+ // NRPN drum section reset
+ };
+ return;
+ };
+ switchMode(mode, forced = false) {
+ let idx = modeIdx.indexOf(mode);
+ if (idx > -1) {
+ if (this.#mode == 0 || forced) {
+ this.#mode = idx;
+ this.#bitmapPage = 0; // Restore page
+ this.#subMsb = substList[0][idx];
+ this.#subLsb = substList[1][idx];
+ for (let ch = 0; ch < allocated.ch; ch ++) {
+ if (drumMsb.indexOf(this.#cc[ch * allocated.cc]) > -1) {
+ this.#cc[ch * allocated.cc] = drumMsb[idx];
+ };
+ //this.initOnReset && forced && this.#ua.ano(ch);
+ };
+ if (this.initOnReset && forced) {
+ //this.init(1);
+ };
+ switch (idx) {
+ case modeMap.mt32: {
+ mt32DefProg.forEach((e, i) => {
+ let ch = i + 1;
+ if (!this.#chActive[ch]) {
+ this.#prg[ch] = e;
+ this.#cc[ch * allocated.cc + ccToPos[91]] = 127;
+ };
+ });
+ break;
+ };
+ };
+ this.dispatchEvent("mode", mode);
+ };
+ } else {
+ throw(new Error(`Unknown mode ${mode}`));
+ };
+ };
+ newStrength() {
+ this.#rawStrength.fill(0);
+ };
+ runJson(json) {
+ // Execute transformed JSON event
+ if (json.type > 14) {
+ if (json.type == 15 && json.data.constructor != Uint8Array) {
+ json.data = Uint8Array.from(json.data);
+ };
+ return this.#runChEvent[json.type].call(this, json);
+ } else {
+ // Universal MIDI channel receive support.
+ let rcvPart = this.chRedir(json.part, json.track),
+ executed = false;
+ this.#receiveTree[rcvPart]?.forEach((e) => {
+ json.channel = e;
+ executed = true;
+ this.#runChEvent[json.type].call(this, json);
+ });
+ /* this.#chReceive.forEach((e, i) => {
+ if (e == rcvPart) {
+ //json.channel = this.chRedir(i, json.track);
+ json.channel = i;
+ executed = true;
+ this.#runChEvent[json.type].call(this, json);
+ };
+ }); */
+ if (!executed) {
+ console.warn(`${eventTypes[json.type] ? eventTypes[json.type] : json.type}${[11, 12].includes(json.type) ? (json.data[0] != undefined ? json.data[0] : json.data).toString() : ""} event sent to CH${rcvPart + 1} without any recipient.`);
+ };
+ };
+ if (this.#metaTexts.length > 100) {
+ this.#metaTexts.splice(100, this.#metaTexts.length - 99);
+ };
+ };
+ runRaw(midiArr) {
+ // Translate raw byte stream into JSON MIDI event
+ };
+ constructor() {
+ super();
+ let upThis = this;
+ this.#bitmap = new Uint8Array(256);
+ this.#bitmapStore[10] = new Uint8Array(512);
+ this.#metaSeq = new BinaryMatch();
+ this.userBank.strictMode = true;
+ // Prevent bank readers from getting stalled
+ this.userBank.load(`MSB\tPRG\tLSB\tNME\n062\t000\t000\t\n122\t000\t000\t\n122\t001\t000\t\n122\t002\t000\t\n122\t003\t000\t\n122\t004\t000\t\n122\t005\t000\t\n122\t006\t000\t`);
+ // Metadata events
+ // Should be moved to somewhere else
+ this.#metaRun[1] = function (data) {
+ // Normal text
+ switch (data.slice(0, 2)) {
+ case "@I": {
+ this.#modeKaraoke = true;
+ this.#metaTexts.unshift(`Kar.Info: ${data.slice(2)}`);
+ break;
+ };
+ case "@K": {
+ this.#modeKaraoke = true;
+ this.#metaTexts.unshift(`Karaoke mode active.`);
+ console.debug(`Karaoke mode active: ${data.slice(2)}`);
+ break;
+ };
+ case "@L": {
+ this.#modeKaraoke = true;
+ this.#metaTexts.unshift(`Language: ${data.slice(2)}`);
+ break;
+ };
+ case "@T": {
+ this.#modeKaraoke = true;
+ this.#metaTexts.unshift(`Ka.Title: ${data.slice(2)}`);
+ break;
+ };
+ case "@V": {
+ this.#modeKaraoke = true;
+ this.#metaTexts.unshift(`Kara.Ver: ${data.slice(2)}`);
+ break;
+ };
+ case "XF": {
+ // XG File Data section
+ let dataArr = data.slice(2).split(":");
+ switch (dataArr[0]) {
+ case "hd": {
+ dataArr.slice(1).forEach((e, i) => {
+ e.length && this.#metaTexts.unshift(`${[
+ "SongDate", "SnRegion", "SongCat.", "SongBeat",
+ "SongInst", "Sn.Vocal", "SongCmp.", "SongLrc.",
+ "SongArr.", "SongPerf", "SongPrg.", "SongTags"
+ ][i]}: ${e}`);
+ });
+ break;
+ };
+ case "ln": {
+ dataArr.slice(1).forEach((e, i) => {
+ e.length && this.#metaTexts.unshift(`${[
+ "Kar.Lang", "Kar.Name", "Kar.Cmp.", "Kar.Lrc.",
+ "kar.Arr.", "Kar.Perf", "Kar.Prg."
+ ][i]}: ${e}`);
+ });
+ break;
+ };
+ default: {
+ this.#metaTexts.unshift(`XGF_Data: ${data}`);
+ };
+ };
+ break;
+ };
+ default: {
+ if (this.#modeKaraoke) {
+ if (data[0] == "\\") {
+ // New section
+ this.#metaTexts.unshift(`@ ${data.slice(1)}`);
+ } else if (data[0] == "/") {
+ // New line
+ this.#metaTexts.unshift(data.slice(1));
+ } else {
+ // Normal append
+ this.#metaTexts[0] += data;
+ };
+ } else {
+ this.#metaTexts[0] = data;
+ this.#metaTexts.unshift("");
+ };
+ };
+ };
+ };
+ this.#metaRun[2] = function (data) {
+ this.#metaTexts.unshift(`Copyrite: ${data}`);
+ };
+ this.#metaRun[3] = function (data, track) {
+ // Filter overly annoying meta events
+ if (track < 1 && this.#metaChannel < 1) {
+ this.#metaTexts.unshift(`TrkTitle: ${data}`);
+ };
+ };
+ this.#metaRun[4] = function (data, track) {
+ //if (track < 1 && this.#metaChannel < 1) {
+ this.#metaTexts.unshift(`${showTrue(this.#metaChannel, "", " ")}Instrmnt: ${data}`);
+ //};
+ };
+ this.#metaRun[5] = function (data) {
+ if (data.trim() == "") {
+ this.#metaTexts.unshift("");
+ } else {
+ this.#metaTexts[0] += `${data}`;
+ };
+ };
+ this.#metaRun[6] = function (data) {
+ this.#metaTexts.unshift(`${showTrue(this.#metaChannel, "", " ")}C.Marker: ${data}`);
+ };
+ this.#metaRun[7] = function (data) {
+ this.#metaTexts.unshift(`CuePoint: ${data}`);
+ };
+ this.#metaRun[32] = function (data) {
+ this.#metaChannel = data[0] + 1;
+ };
+ this.#metaRun[33] = function (data, track) {
+ console.debug(`Track ${track} requests to get assigned to output ${data}.`);
+ upThis.#trkAsReq[track] = data + 1;
+ };
+ this.#metaRun[81] = function (data, track) {
+ upThis.#noteLength = data / 1000;
+ };
+ this.#metaRun[127] = function (data, track) {
+ //console.debug(`Sequencer specific on track ${track}: `, data);
+ upThis.#metaSeq.run(data, track);
+ };
+ // Sequencer specific meta event
+ // No refactoring needed.
+ this.#metaSeq.default = function (seq) {
+ console.warn(`Unrecognized sequencer-specific byte sequence: ${seq}`);
+ };
+ this.#metaSeq.add([67, 0, 1], function (msg, track) {
+ //console.debug(`XGworks requests assigning track ${track} to output ${msg[0]}.`);
+ upThis.#trkAsReq[track] = msg[0] + 1;
+ });
+ // Binary match should be avoided in favour of a circular structure
+ this.#seUnr = new BinaryMatch();
+ this.#seUr = new BinaryMatch();
+ this.#seXg = new BinaryMatch();
+ this.#seGs = new BinaryMatch();
+ this.#seAi = new BinaryMatch();
+ this.#seKg = new BinaryMatch();
+ this.#seSg = new BinaryMatch();
+ // The new SysEx engine only defines actions when absolutely needed.
+ // Mode reset section
+ this.#seUnr.add([9], (msg) => {
+ // General MIDI reset.
+ upThis.switchMode(["gm", "?", "g2"][msg[0] - 1], true);
+ upThis.#modeKaraoke = upThis.#modeKaraoke || false;
+ console.info(`MIDI reset: ${["GM", "Init", "GM2"][msg[0] - 1]}`);
+ if (msg[0] == 2) {
+ upThis.init();
+ };
+ });
+ // GM SysEx section
+ this.#seUr.add([4, 1], (msg) => {
+ // Master volume
+ upThis.#masterVol = ((msg[1] << 7) + msg[0]) / 16383 * 100;
+ }).add([4, 3], (msg) => {
+ // Master fine tune
+ return (((msg[1] << 7) + msg[0] - 8192) / 8192);
+ }).add([4, 4], (msg) => {
+ // Master coarse tune
+ return (msg[1] - 64);
+ });
+ // XG SysEx section
+ this.#seXg.add([76, 0, 0], (msg) => {
+ switch (msg[0]) {
+ case 126: {
+ // Yamaha XG reset
+ upThis.switchMode("xg", true);
+ upThis.#modeKaraoke = false;
+ console.info("MIDI reset: XG");
+ break;
+ };
+ };
+ }).add([76, 6, 0], (msg) => {
+ // XG Letter Display
+ let offset = msg[0];
+ if (offset < 64) {
+ upThis.#letterDisp = " ".repeat(offset);
+ upThis.#letterExpire = Date.now() + 3200;
+ msg.subarray(1).forEach(function (e) {
+ upThis.#letterDisp += String.fromCharCode(e);
+ });
+ upThis.#letterDisp = upThis.#letterDisp.padEnd(32, " ");
+ } else {
+ // Expire all existing letter display
+ upThis.#letterExpire = Date.now();
+ };
+ }).add([76, 7, 0], (msg) => {
+ // XG Bitmap Display
+ let offset = msg[0];
+ upThis.#bitmapExpire = Date.now() + 3200;
+ upThis.#bitmap.fill(0); // Init
+ let workArr = msg.subarray(1);
+ for (let index = 0; index < offset; index ++) {
+ workArr.unshift(0);
+ };
+ workArr.forEach(function (e, i) {
+ let ln = Math.floor(i / 16), co = i % 16;
+ let pt = (co * 3 + ln) * 7, threshold = 7, bi = 0;
+ pt -= co * 5;
+ if (ln == 2) {
+ threshold = 2;
+ };
+ while (bi < threshold) {
+ upThis.#bitmap[pt + bi] = (e >> (6 - bi)) & 1;
+ bi ++;
+ };
+ });
+ });
+ // XG drum setup would be blank for now
+ // TG300 SysEx section, the parent of XG
+ this.#seXg.add([43, 7, 0], (msg, track, id) => {
+ // TG300 display letter
+ // Same as XG letter display
+ upThis.#letterDisp = " ".repeat(offset);
+ upThis.#letterExpire = Date.now() + 3200;
+ msg.subarray(1).forEach(function (e) {
+ upThis.#letterDisp += String.fromCharCode(e);
+ });
+ upThis.#letterDisp = upThis.#letterDisp.padEnd(32, " ");
+ }).add([43, 7, 1], (msg, track, id) => {
+ // TG300 display bitmap
+ // Same as XG bitmap display
+ upThis.#bitmapExpire = Date.now() + 3200;
+ upThis.#bitmap.fill(0); // Init
+ msg.forEach(function (e, i) {
+ let ln = Math.floor(i / 16), co = i % 16;
+ let pt = (co * 3 + ln) * 7, threshold = 7, bi = 0;
+ pt -= co * 5;
+ if (ln == 2) {
+ threshold = 2;
+ };
+ while (bi < threshold) {
+ upThis.#bitmap[pt + bi] = (e >> (6 - bi)) & 1;
+ bi ++;
+ };
+ });
+ });
+ // TG drum setup would also be blank
+ // GS SysEx section
+ this.#seGs.add([66, 18, 0, 0, 127], (msg, track, id) => {
+ // GS mode set
+ upThis.switchMode("gs", true);
+ upThis.#cc[allocated.cc * 9] = 120;
+ upThis.#cc[allocated.cc * 25] = 120;
+ upThis.#cc[allocated.cc * 41] = 120;
+ upThis.#cc[allocated.cc * 57] = 120;
+ upThis.#subLsb = 3; // Use SC-88 Pro map by default
+ upThis.#modeKaraoke = false;
+ upThis.#trkRedir.fill(0);
+ console.info(`GS system to ${["single", "dual"][msg[0]]} mode.`);
+ }).add([66, 18, 64, 0], (msg, track, id) => {
+ switch (msg[0]) {
+ case 127: {
+ // Roland GS reset
+ upThis.switchMode("gs", true);
+ upThis.#cc[allocated.cc * 9] = 120;
+ upThis.#cc[allocated.cc * 25] = 120;
+ upThis.#cc[allocated.cc * 41] = 120;
+ upThis.#cc[allocated.cc * 57] = 120;
+ upThis.#modeKaraoke = false;
+ upThis.#trkRedir.fill(0);
+ console.info("MIDI reset: GS");
+ break;
+ };
+ };
+ }).add([69, 18, 16], (msg) => {
+ // GS display section
+ switch (msg[0]) {
+ case 0: {
+ // GS display letter
+ upThis.#letterExpire = Date.now() + 3200;
+ let offset = msg[1];
+ upThis.#letterDisp = " ".repeat(offset);
+ msg.subarray(2).forEach(function (e) {
+ if (e < 128) {
+ upThis.#letterDisp += String.fromCharCode(e);
+ };
+ });
+ break;
+ };
+ case 32: {
+ upThis.#bitmapExpire = Date.now() + 3200;
+ if (msg[1] == 0) {
+ // GS display page
+ upThis.#bitmapPage = Math.max(Math.min(msg[2] - 1, 9), 0);
+ };
+ break;
+ };
+ default: {
+ if (msg[0] < 11) {
+ // GS display bitmap
+ upThis.#bitmapExpire = Date.now() + 3200;
+ if (!upThis.#bitmapStore[msg[0] - 1]?.length) {
+ upThis.#bitmapStore[msg[0] - 1] = new Uint8Array(256);
+ };
+ let target = upThis.#bitmapStore[msg[0] - 1];
+ let offset = msg[1];
+ target.fill(0); // Init
+ let workArr = msg.subarray(2);
+ for (let index = 0; index < offset; index ++) {
+ workArr.unshift(0);
+ };
+ workArr.forEach(function (e, i) {
+ let ln = Math.floor(i / 16), co = i % 16;
+ let pt = (co * 4 + ln) * 5, threshold = 5, bi = 0;
+ pt -= co * 4;
+ if (ln == 3) {
+ threshold = 1;
+ };
+ while (bi < threshold) {
+ target[pt + bi] = (e >> (4 - bi)) & 1;
+ bi ++;
+ };
+ });
+ } else {
+ console.warn(`Unknown GS display section: ${msg[0]}`);
+ };
+ };
+ };
+ });
+ // Roland MT-32 or C/M SysEx section
+ this.#seGs.add([22, 18, 127], (msg) => {
+ // MT-32 reset all params
+ upThis.switchMode("mt32", true);
+ upThis.#modeKaraoke = false;
+ upThis.userBank.clearRange({msb: 0, lsb: 127, prg: [0, 127]});
+ console.info("MIDI reset: MT-32");
+ }).add([22, 18, 32], (msg) => {
+ // MT-32 Text Display
+ upThis.switchMode("mt32");
+ let offset = msg[1];
+ let text = " ".repeat(offset);
+ msg.subarray(2).forEach((e) => {
+ if (e > 31) {
+ text += String.fromCharCode(e);
+ };
+ });
+ upThis.#letterDisp = text.padStart(20, " ");
+ upThis.#letterExpire = Date.now() + 3200;
+ }).add([22, 18, 82], (msg, track) => {
+ // MT-32 alt reset?
+ let partBase = upThis.chRedir(0, track, true);
+ for (let part = 0; part < 16; part ++) {
+ upThis.#ua.ano(partBase + part);
+ if (part && part < 10) {
+ upThis.#prg[partBase + part] = mt32DefProg[part - 1];
+ };
+ };
+ console.info(`MT-32 alt reset complete.`);
+ });
+ // KORG NS5R SysEx section
+ this.#seAi.add([66, 0], (msg, track) => {
+ // Mode switch
+ upThis.switchMode("ns5r", true);
+ upThis.#modeKaraoke = false;
+ console.debug(`NS5R mode switch requested: ${["global", "multi", "prog edit", "comb edit", "drum edit", "effect edit"][msg[0]]} mode.`);
+ }).add([66, 1], (msg, track) => {
+ // Map switch
+ upThis.switchMode(["ns5r", "05rw"][msg[0]], true);
+ upThis.#modeKaraoke = false;
+ }).add([66, 18, 0, 0], (msg, track) => {
+ // Master setup
+ let offset = msg[0];
+ switch (offset) {
+ case 124: // all param reset
+ case 126: // XG reset for NS5R
+ case 127: { // GS reset for NS5R
+ upThis.switchMode("ns5r", true);
+ upThis.#modeKaraoke = false;
+ break;
+ };
+ };
+ }).add([66, 18, 8, 0], (msg, track) => {
+ // Display (letter and bitmap)
+ // Mehh I'll fill this up when I have time
+ }).add([66, 125], (msg) => {
+ // Backlight
+ upThis.dispatchEvent("backlight", ["green", "orange", "red", false, "yellow", "blue", "purple"][msg[0]] || "white");
+ }).add([66, 127], (msg) => {
+ // NS5R screen dump
+ let screenBuffer = new Uint8Array(5760);
+ korgFilter(msg, (e, i, a) => {
+ if (i < 720) {
+ for (let bi = 0; bi < 8; bi ++) {
+ screenBuffer[i * 8 + bi] = (e >> (7 - bi)) & 1;
+ };
+ };
+ });
+ upThis.dispatchEvent("screen", {type: "ns5r", data: screenBuffer});
+ }).add([76], (msg, track, id) => {
+ // N1R to NS5R redirector
+ upThis.#seAi.run([66, ...msg], track, id);
+ });
+ // Kawai GMega
+ this.#seKg.add([16, 0, 8, 0], (msg, track, id) => {
+ // GMega system section
+ let e = (msg[2] << 4) + msg[3];
+ let dPref = "K11 ";
+ ([() => {
+ // GMega bank set
+ upThis.switchMode("k11", true);
+ upThis.#modeKaraoke = false;
+ upThis.#subLsb = e ? 4 : 0;
+ console.info("MIDI reset: GMega/K11");
+ }][msg[0]] || (() => {}))();
+ });
+ // AKAI SG
+ this.#seSg.add([66, 93, 64], (msg, track, id) => {
+ let e = msg[2];
+ switch (msg[0]) {
+ case 0: {
+ // SG system section at 0x00
+ switch (msg[1]) {
+ case 127: {
+ // SG reset
+ upThis.switchMode("sg", true);
+ break;
+ };
+ };
+ break;
+ };
+ };
+ });
+ };
+};
+
+export {
+ OctaviaDevice,
+ allocated,
+ ccToPos
+};
diff --git a/src/xp_basic/buildOpt.txt b/src/xp_basic/buildOpt.txt
new file mode 120000
index 00000000..46463af1
--- /dev/null
+++ b/src/xp_basic/buildOpt.txt
@@ -0,0 +1 @@
+../compat/buildOpt.txt
\ No newline at end of file
diff --git a/src/xp_basic/index.mjs b/src/xp_basic/index.mjs
new file mode 120000
index 00000000..490f8d89
--- /dev/null
+++ b/src/xp_basic/index.mjs
@@ -0,0 +1 @@
+../basic/index.mjs
\ No newline at end of file
diff --git a/src/xp_basic/inject.js b/src/xp_basic/inject.js
new file mode 120000
index 00000000..f71227a5
--- /dev/null
+++ b/src/xp_basic/inject.js
@@ -0,0 +1 @@
+../compat/inject.js
\ No newline at end of file
diff --git a/src/xp_demoMw/buildOpt.txt b/src/xp_demoMw/buildOpt.txt
new file mode 120000
index 00000000..46463af1
--- /dev/null
+++ b/src/xp_demoMw/buildOpt.txt
@@ -0,0 +1 @@
+../compat/buildOpt.txt
\ No newline at end of file
diff --git a/src/xp_demoMw/index.js b/src/xp_demoMw/index.js
new file mode 120000
index 00000000..742b5add
--- /dev/null
+++ b/src/xp_demoMw/index.js
@@ -0,0 +1 @@
+../demoMw/index.js
\ No newline at end of file
diff --git a/src/xp_demoMw/inject.js b/src/xp_demoMw/inject.js
new file mode 120000
index 00000000..f71227a5
--- /dev/null
+++ b/src/xp_demoMw/inject.js
@@ -0,0 +1 @@
+../compat/inject.js
\ No newline at end of file
diff --git a/src/xp_demoTui/buildOpt.txt b/src/xp_demoTui/buildOpt.txt
new file mode 120000
index 00000000..46463af1
--- /dev/null
+++ b/src/xp_demoTui/buildOpt.txt
@@ -0,0 +1 @@
+../compat/buildOpt.txt
\ No newline at end of file
diff --git a/src/xp_demoTui/index.js b/src/xp_demoTui/index.js
new file mode 120000
index 00000000..2828b73c
--- /dev/null
+++ b/src/xp_demoTui/index.js
@@ -0,0 +1 @@
+../demoTui/index.js
\ No newline at end of file
diff --git a/src/xp_demoTui/inject.js b/src/xp_demoTui/inject.js
new file mode 120000
index 00000000..f71227a5
--- /dev/null
+++ b/src/xp_demoTui/inject.js
@@ -0,0 +1 @@
+../compat/inject.js
\ No newline at end of file
diff --git a/src/xp_fakeMu/buildOpt.txt b/src/xp_fakeMu/buildOpt.txt
new file mode 120000
index 00000000..46463af1
--- /dev/null
+++ b/src/xp_fakeMu/buildOpt.txt
@@ -0,0 +1 @@
+../compat/buildOpt.txt
\ No newline at end of file
diff --git a/src/xp_fakeMu/index.js b/src/xp_fakeMu/index.js
new file mode 120000
index 00000000..7f59fc6e
--- /dev/null
+++ b/src/xp_fakeMu/index.js
@@ -0,0 +1 @@
+../fakeMu/index.js
\ No newline at end of file
diff --git a/src/xp_fakeMu/inject.js b/src/xp_fakeMu/inject.js
new file mode 120000
index 00000000..f71227a5
--- /dev/null
+++ b/src/xp_fakeMu/inject.js
@@ -0,0 +1 @@
+../compat/inject.js
\ No newline at end of file
diff --git a/src/xp_fakeNs5r/buildOpt.txt b/src/xp_fakeNs5r/buildOpt.txt
new file mode 120000
index 00000000..46463af1
--- /dev/null
+++ b/src/xp_fakeNs5r/buildOpt.txt
@@ -0,0 +1 @@
+../compat/buildOpt.txt
\ No newline at end of file
diff --git a/src/xp_fakeNs5r/index.js b/src/xp_fakeNs5r/index.js
new file mode 120000
index 00000000..c1cc3e01
--- /dev/null
+++ b/src/xp_fakeNs5r/index.js
@@ -0,0 +1 @@
+../fakeNs5r/index.js
\ No newline at end of file
diff --git a/src/xp_fakeNs5r/inject.js b/src/xp_fakeNs5r/inject.js
new file mode 120000
index 00000000..f71227a5
--- /dev/null
+++ b/src/xp_fakeNs5r/inject.js
@@ -0,0 +1 @@
+../compat/inject.js
\ No newline at end of file
diff --git a/src/xp_fakePsr/buildOpt.txt b/src/xp_fakePsr/buildOpt.txt
new file mode 120000
index 00000000..46463af1
--- /dev/null
+++ b/src/xp_fakePsr/buildOpt.txt
@@ -0,0 +1 @@
+../compat/buildOpt.txt
\ No newline at end of file
diff --git a/src/xp_fakePsr/index.js b/src/xp_fakePsr/index.js
new file mode 120000
index 00000000..2d1f4a7d
--- /dev/null
+++ b/src/xp_fakePsr/index.js
@@ -0,0 +1 @@
+../fakePsr/index.js
\ No newline at end of file
diff --git a/src/xp_fakePsr/inject.js b/src/xp_fakePsr/inject.js
new file mode 120000
index 00000000..f71227a5
--- /dev/null
+++ b/src/xp_fakePsr/inject.js
@@ -0,0 +1 @@
+../compat/inject.js
\ No newline at end of file
diff --git a/src/xp_fakeQy/buildOpt.txt b/src/xp_fakeQy/buildOpt.txt
new file mode 120000
index 00000000..46463af1
--- /dev/null
+++ b/src/xp_fakeQy/buildOpt.txt
@@ -0,0 +1 @@
+../compat/buildOpt.txt
\ No newline at end of file
diff --git a/src/xp_fakeQy/index.js b/src/xp_fakeQy/index.js
new file mode 120000
index 00000000..725d2353
--- /dev/null
+++ b/src/xp_fakeQy/index.js
@@ -0,0 +1 @@
+../fakeQy/index.js
\ No newline at end of file
diff --git a/src/xp_fakeQy/inject.js b/src/xp_fakeQy/inject.js
new file mode 120000
index 00000000..f71227a5
--- /dev/null
+++ b/src/xp_fakeQy/inject.js
@@ -0,0 +1 @@
+../compat/inject.js
\ No newline at end of file
diff --git a/src/xp_fakeSc/buildOpt.txt b/src/xp_fakeSc/buildOpt.txt
new file mode 120000
index 00000000..46463af1
--- /dev/null
+++ b/src/xp_fakeSc/buildOpt.txt
@@ -0,0 +1 @@
+../compat/buildOpt.txt
\ No newline at end of file
diff --git a/src/xp_fakeSc/index.js b/src/xp_fakeSc/index.js
new file mode 120000
index 00000000..067f6eab
--- /dev/null
+++ b/src/xp_fakeSc/index.js
@@ -0,0 +1 @@
+../fakeSc/index.js
\ No newline at end of file
diff --git a/src/xp_fakeSc/inject.js b/src/xp_fakeSc/inject.js
new file mode 120000
index 00000000..f71227a5
--- /dev/null
+++ b/src/xp_fakeSc/inject.js
@@ -0,0 +1 @@
+../compat/inject.js
\ No newline at end of file
diff --git a/src/xp_state/buildOpt.txt b/src/xp_state/buildOpt.txt
new file mode 120000
index 00000000..46463af1
--- /dev/null
+++ b/src/xp_state/buildOpt.txt
@@ -0,0 +1 @@
+../compat/buildOpt.txt
\ No newline at end of file
diff --git a/src/xp_state/index.mjs b/src/xp_state/index.mjs
new file mode 120000
index 00000000..34c150b7
--- /dev/null
+++ b/src/xp_state/index.mjs
@@ -0,0 +1 @@
+../state/index.mjs
\ No newline at end of file
diff --git a/src/xp_state/inject.js b/src/xp_state/inject.js
new file mode 120000
index 00000000..f71227a5
--- /dev/null
+++ b/src/xp_state/inject.js
@@ -0,0 +1 @@
+../compat/inject.js
\ No newline at end of file
diff --git a/test/cambiare.htm b/test/cambiare.htm
new file mode 100644
index 00000000..0288ff58
--- /dev/null
+++ b/test/cambiare.htm
@@ -0,0 +1,43 @@
+
+
+
+ Octavia Cambiare (alpha)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Open MIDI ,
+ audio ,
+ line .
+ GM ,
+ GS ,
+ XG ,
+ GM2 ,
+ MT-32 ,
+ NS5R ,
+ AG-10 ,
+ 05R/W ,
+ X5D ,
+ GMega ,
+ SG ;
+ KROSS ,
+ S90 ES ,
+ Motif ES .
+
+
+ Demo
+ collection loading...
+
+ Start port: A B C D E F G H, show 16 32 64 channels.
+
+
+
diff --git a/test/css/fonts.css b/test/css/fonts.css
new file mode 100644
index 00000000..4f4e5127
--- /dev/null
+++ b/test/css/fonts.css
@@ -0,0 +1,18 @@
+@font-face {
+ font-family: "Noto Sans Mono Web";
+ src: url("../font/NotoSansMono-VF.woff2") format("woff2");
+}
+@font-face {
+ font-family: "Arial Web";
+ font-weight: 400;
+ src: url("../font/arial.woff2") format("woff2");
+}
+@font-face {
+ font-family: "Arial Web";
+ font-weight: 700;
+ src: url("../font/arialbd.woff2") format("woff2");
+}
+
+body {
+ font-family: "Noto Sans Mono", "Noto Sans Mono Web", mono;
+}
diff --git a/test/css/tui.css b/test/css/tui.css
new file mode 100644
index 00000000..942d2919
--- /dev/null
+++ b/test/css/tui.css
@@ -0,0 +1,62 @@
+body {
+ min-width: 768px;
+}
+
+p {
+ margin: 0.2em;
+}
+
+b[class], b[id^=open] {
+ cursor: pointer;
+}
+b.active {
+ outline: 2px solid;
+ padding: 0 2px;
+}
+
+li[id^=mw-in-], li[id^=mw-out-] {
+ cursor: pointer;
+}
+li.active {
+ text-decoration: underline;
+}
+
+div.section {
+ margin: 0.8em;
+ cursor: default;
+}
+
+div#display {
+ font-size: 16px;
+ cursor: default;
+ white-space: pre-wrap;
+}
+canvas#ymhMu {
+ background: #af2;
+}
+canvas#rlndSc {
+ background: #fa0;
+}
+
+@media (prefers-color-scheme: dark){
+ span.letter {
+ background: #dbdbdb !important;
+ color: #202b38 !important;
+ }
+ canvas#bmDisp {
+ filter: invert(100%);
+ }
+}
+span.letter {
+ background: #363636;
+ color: #fff;
+ white-space: pre-wrap;
+ display: inline-block;
+}
+
+.state-hold {
+ text-decoration: line-through;
+}
+.state-active {
+ color: green;
+}
diff --git a/test/css/water.min.css b/test/css/water.min.css
new file mode 120000
index 00000000..14ad36bc
--- /dev/null
+++ b/test/css/water.min.css
@@ -0,0 +1 @@
+../../libs/water.css@kognise/water.min.css
\ No newline at end of file
diff --git a/test/data b/test/data
new file mode 120000
index 00000000..4909e06e
--- /dev/null
+++ b/test/data
@@ -0,0 +1 @@
+../data
\ No newline at end of file
diff --git a/test/fakeMu.htm b/test/fakeMu.htm
new file mode 100644
index 00000000..a5837e98
--- /dev/null
+++ b/test/fakeMu.htm
@@ -0,0 +1,51 @@
+
+
+
+ Octavia MU Screen
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Open MIDI ,
+ audio ,
+ line .
+ GM ,
+ GS ,
+ XG ,
+ GM2 ,
+ MT-32 ,
+ NS5R ,
+ AG-10 ,
+ 05R/W ,
+ X5D ,
+ GMega ,
+ SG ;
+ KROSS ,
+ S90 ES ,
+ Motif ES .
+
+
+ Demo
+ collection loading...
+
+
+ Switch active channels by scrolling the mouse wheel, or clicking the horizontal edges of the fake screen. Choose and click on the demos to enjoy.
+ Octavia will handle MIDI standard detection most of the time, but if it cannot detect one of the supported standards, you can select the correct standard manually too.
+ While handling state tracking and automatic channel assignment, Octavia does neither handle MIDI synthesizing nor embed a synthesizer currently. If you want to play a certain MIDI track, you must provide both the MIDI file and the synced pre-rendered audio file.
+
+
diff --git a/test/fakeNs5r.htm b/test/fakeNs5r.htm
new file mode 100644
index 00000000..947be7a8
--- /dev/null
+++ b/test/fakeNs5r.htm
@@ -0,0 +1,51 @@
+
+
+
+ Octavia NS5R Screen
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Open MIDI ,
+ audio ,
+ line .
+ GM ,
+ GS ,
+ XG ,
+ GM2 ,
+ MT-32 ,
+ NS5R ,
+ AG-10 ,
+ 05R/W ,
+ X5D ,
+ GMega ,
+ SG ;
+ KROSS ,
+ S90 ES ,
+ Motif ES .
+
+
+ Demo
+ collection loading...
+
+
+ Switch active channels by scrolling the mouse wheel, or clicking the horizontal edges of the fake screen. Choose and click on the demos to enjoy.
+ Octavia will handle MIDI standard detection most of the time, but if it cannot detect one of the supported standards, you can select the correct standard manually too.
+ While handling state tracking and automatic channel assignment, Octavia does neither handle MIDI synthesizing nor embed a synthesizer currently. If you want to play a certain MIDI track, you must provide both the MIDI file and the synced pre-rendered audio file.
+
+
diff --git a/test/fakePsr.htm b/test/fakePsr.htm
new file mode 100644
index 00000000..7ace1bb6
--- /dev/null
+++ b/test/fakePsr.htm
@@ -0,0 +1,64 @@
+
+
+
+ Octavia PSR Screen
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Open MIDI ,
+ audio ,
+ line .
+ GM ,
+ GS ,
+ XG ,
+ GM2 ,
+ MT-32 ,
+ NS5R ,
+ AG-10 ,
+ 05R/W ,
+ X5D ,
+ GMega ,
+ SG ;
+ KROSS ,
+ S90 ES ,
+ Motif ES .
+
+
+ Backlight color
+ White ,
+ Green ,
+ Orange ,
+ Red ,
+ Light blue ,
+ Blue .
+
+
+ Automatic channel switching
+ ON
+
+
+ Demo
+ collection loading...
+
+
+ Switch active channels by scrolling the mouse wheel, or clicking the horizontal edges of the fake screen. Choose and click on the demos to enjoy. Click on the top of the fake screen will get you switched between song information view, voice view and rhythm view of the top section.
+ Octavia will handle MIDI standard detection most of the time, but if it cannot detect one of the supported standards, you can select the correct standard manually too.
+ While handling state tracking and automatic channel assignment, Octavia does neither handle MIDI synthesizing nor embed a synthesizer currently. If you want to play a certain MIDI track, you must provide both the MIDI file and the synced pre-rendered audio file.
+
+
diff --git a/test/fakeQy.htm b/test/fakeQy.htm
new file mode 100644
index 00000000..8751d0e6
--- /dev/null
+++ b/test/fakeQy.htm
@@ -0,0 +1,51 @@
+
+
+
+ Octavia QY Screen
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Open MIDI ,
+ audio ,
+ line .
+ GM ,
+ GS ,
+ XG ,
+ GM2 ,
+ MT-32 ,
+ NS5R ,
+ AG-10 ,
+ 05R/W ,
+ X5D ,
+ GMega ,
+ SG ;
+ KROSS ,
+ S90 ES ,
+ Motif ES .
+
+
+ Demo
+ collection loading...
+
+
+ Switch active channels by scrolling the mouse wheel, or clicking the horizontal edges of the fake screen. Choose and click on the demos to enjoy. Click on the top of the fake screen will get you switched between default view and mixer view.
+ Octavia will handle MIDI standard detection most of the time, but if it cannot detect one of the supported standards, you can select the correct standard manually too.
+ While handling state tracking and automatic channel assignment, Octavia does neither handle MIDI synthesizing nor embed a synthesizer currently. If you want to play a certain MIDI track, you must provide both the MIDI file and the synced pre-rendered audio file.
+
+
diff --git a/test/fakeSc.htm b/test/fakeSc.htm
new file mode 100644
index 00000000..8f84f8bd
--- /dev/null
+++ b/test/fakeSc.htm
@@ -0,0 +1,51 @@
+
+
+
+ Octavia SC Screen
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Open MIDI ,
+ audio ,
+ line .
+ GM ,
+ GS ,
+ XG ,
+ GM2 ,
+ MT-32 ,
+ NS5R ,
+ AG-10 ,
+ 05R/W ,
+ X5D ,
+ GMega ,
+ SG ;
+ KROSS ,
+ S90 ES ,
+ Motif ES .
+
+
+ Demo
+ collection loading...
+
+
+ Switch active channels by scrolling the mouse wheel, or clicking the horizontal edges of the fake screen. Choose and click on the demos to enjoy.
+ Octavia will handle MIDI standard detection most of the time, but if it cannot detect one of the supported standards, you can select the correct standard manually too.
+ While handling state tracking and automatic channel assignment, Octavia does neither handle MIDI synthesizing nor embed a synthesizer currently. If you want to play a certain MIDI track, you must provide both the MIDI file and the synced pre-rendered audio file.
+
+
diff --git a/test/font/NotoSansMono-VF.woff2 b/test/font/NotoSansMono-VF.woff2
new file mode 100644
index 0000000000000000000000000000000000000000..11cc7b2ca41915683c682669e7d65141be69f44a
GIT binary patch
literal 572476
zcmZU3LtrHeuxy+Y+qSKVZ6_1kwrxyoXJSum+qP}nIRE~)e6KcD-HYCIt*YBYQGyi&
z6a)kW(8ULW_8(*DyMh2ZhySPdU-`d*yHAN1k|KxSrYR_;F07J=DJcIR1))M23ab7V
z{!LCL2J$Vy6k-V*7o!xNBmnoq48q)zDNiC=u%+0Ln5lsvphVrp7
zIB~Y%LC$*9Q!{q(PgXpkuV_3O0X-l*o%{YQUvNF?goB%vY4dE|-9f3!|N*bV%YbKwUU8PvZt
zZesqjePY!z)wXCzPepXS{gkrHaE^1>|J$Uz2COWw6b?+(tR#}nlm$unRw+H$E}11P
zvSUh!g`!jrz)~TfRL2?qi7WJ`bPdOjhe7H83bl`9IBU4Kc*z|#QMsPuy>;-szwTHT
z(ZWDI9?yY+Bb~~m4&9-PIUo$rV1d^{<4!fQJ=>W<-kBWu{!o4|lvp|1cY-5W`01N)
z@t0nYb6B4Ay(YWR($Oa$HZj3x6)}ENWF3rcN*tPFa29PS_VO1~m~9SJ{JrgI1{KvE
zr_kTAPRD0Bx}lMGNiy^L4EK>H*Pz^IKANiYhP#m_pw2YUuyu=NC*CS|;bd_-lg_qV
zCg~&Jjpj=x?`M8zPe`XQE^S82UA;GmS}#K9IaH7YsS=*RdvM?*YH-a8t-~uzV4mmE
z|BmWBpU10nJAxNEc&ByyeQYDftsaVDB(CW-)17beWaCUdtY$sta}o<3@fnJ%qGnL@
z?w1){pN-Jghw#8gqU_MvrORB9XQPn_cyF@ENES7LhX7Lx>+7d(Et^=YbV}2-x800%xD9V=o@z?}84$Qs-Y63k?du!LGrNViH^Fen?#-;m|7q
zQ2WPVkBrQQb$oiCEgebj0RuQ5@H^jG8py$XP;EDc@0U-IM>!Ms8L=yjn;O0c!+E96
z)+3NdSqAeb;5n7vc*+E}igKnlVbg&k$3DrqM8W^S?N7C623|;TeVD2w{KkGN#V!7o
zjqKCafS574JYLdT0V@p2y!>@nmk*ui)=!+K_t2IJ|38L77(Gl@sS!hZ^w<@f(*!C}
ztC5G}{q&aXQmH#QOmCKl??m#yQJD-wYvD8z2{ITS;z@2W<4Tej1d;i%RY1|HqJCE-
zg0iE*19VKt^}J-;c1kc3yy5~GOnage)_BEz$lRmZGisS$9Jkd048L?F&<*1elF_
zEa-i;@(F#Rzg?P>{E&=sPAGRGAl0YOQ$zzKE^r>Zbk2gALm|Y@OUR>uYXmQ=YX-P+
z6Suu#;nRmw{F%dJHQ@QyZL;+5?Ndj=u9_S&!doAn0al)0nj{XWcJ7aj#?oA}rQia*
z!#BXkof)~)dTc~zrXQFE^v%3+<}zVh%gfNXu$6@*2Y#dB)3Bu4k>1&VUyLl6oSyP4
z+>%rxZF@g0OWNq*+k(cvETA7M^gNO`KY*6?*!(R{Vv&*Ui&i_E=0aMOK#&ytd8p{Y
z{dovj(ySzGI#dp`M&oL0Z7>3UaQ7|ddJ3-2n0B)O$3sUx4t@SZCoE|Vupi2??RvxF
zyhZdF3Bm!kLyFdQw52pQpUC@0Ir3=_wz!0P`O#B^r!q2U1e(_I+A+6Dlb4
z;4mD^!_sK%*bD^hZlk&=dRCy#E3o%<#xI}k)f7zLxoaj1soj~z&6R3pw_4XvBhVon
zSX28GP_1O_fVH&rbT^08H+%beH8z%&N%uzJxu>pH)s%UDm!xba>tRF@zW;vwf(;Hu
z|KZ*m9cS?0=s2?mWfQ#h;Lt(ujAMZMNyscnKBM-RuGVr6UqEvYdm=2~_)Gv+gG4iMOF4(x3KVUTSwOAsCbLp1cj
zT@Xrt|BU;DynWoZWm+CLas;Q+l}?3=L3PjvVaD2r!vEM^5k#Z1>{QZlSN=Dk7ZazW
z7r^BC{VCv(X8)T8tjq%H=hHx<^VQ?^clQTBUAiGX?y)j`(xEcxL^(W<54l7!&OpVo
zrI=w51&-->+8;FNtY1zba2d`rU0d$$2E6WVU7eCcv$8@O#0cLlXYCg!q_M^rTEmvE
z<3@nQEE3L(!Vfn6qg}IM#If&1dzTgF=4JVF(4%yWrWIiE;t$haoNR2aXU+)?!=nsc
zr@_WL@ObxoSw|eR)?@l<=>&cBk6jjZ5(sD^Oelnu2qd{shVdQHplruu7iiFsd%&y^
z96D;xPdj&Fs-7tq><$Mq;fM;xhZIw_LuBc(DLvy@gqNI^8RmOln0>jVin{0Zvm`ja
zqJ7^}-}nz|(<&J2eRCE5co_(cXiw76W+HN9KXaubD5sU~56WKTXM;{hIs#JW5_*Tx
zz^RFlhO{`>nk_4*UL2npRqY#m(WbEBb&c~MU-
zf;gw}Bi)qOL=H2{6;W4T69i5(9D#ZU;a_7iCEHLFD&d|GBG6vD?J+%*cqJ)moQ>
zBO;2?t5(un$ZREdef4%rh6_4R37}3memicY`k9v)%EcQp@YzhLbDjj1U>8$Q@`r1E
zV~nHS-ly5E+_qud{PCb?V5I^U;TLMKkm1y?5MpqUUxrgbvIURO(ya?=TCfbwQbs!N
zvM3Yiv?*Y#DhZgTf`cmRD70W;wDGpeiDgRb@ohqm7>;sBYWQv>lYfW{^WT02xy*%w
zvZe};R0%H2_(VlwrAVcQ%`Gp}Yc=HjJ)SgTg6Y6`Jf?Yy6H!h^k{LAb?
z%y6F;%tQP9Ln2HsmOws)z^9pz7PppV1?{#Rz+l*PFCHoE>C}}$;1tjYYD-THK90HG
zU}l&J*I5R=b2_N4W|ou#&ek44bhxDh9TFZP#o)hpy
z0SS`J*H;S?d`)p@ZbCc`X0yb$t>-pt#8^f8hoSYFJ*Z???T!xDuJIuKp3
zLCtTPjm-l|sR0
zBHEIiYm10aeCOBK3-Px~ofjIkfrZzQQdxGpI(!%{I-oq7VgEF=r8;w>;VE$!Hk8ns
z4H^jSed(BOC&3^ibCr37p$yo8r~s%ZR?f{ss#H#%iU7aYUL9(8EY6@Z=m*A-^FR9-
z@5=+FOAmrD5+<`7{r?)&c+aGkQQ#^|%@J?NZ#KnF+;AoT)X-@?<2ayMT9Qi@euWCnTN6aX8A5p#`7gZu8MRNz~=#yAa{X}sGG-ya1op^memvp
z9q-@U-mU(5!<6^qwtSl_J^{Y1>N!z`48nZq)PWWa&
zsM|cWY=8gEN2x9>w6q}eE>n5r#%K7CY-A6K9R|3m!wuF$ehsHlOvX`7Dy6?Jyslyl
z0jsKnkm$Frl>_VLDmlfIOYdmbD8*Bswn|Am{Jh{ILMZ1~v9yz}?_>U`!ihHLh@FzG
zPh_}#q9Ol)%n4>!dRk2y!fe^1;p=A|vpm-LW?IC4XFf7)BONdFc+~$+!d-SZJRtCt
zJ1u#}BynVP!(1#)-SmH;d!tb;|i=*@{b%`kN1Ev)nt3RbS`y#uD%x8xPINNe6mZAzjaZ(wM|r-~aa<0>l(72tDbL&;J$mDXH_)5Wf$}$gT1--KO(6xd|Wuwbv
z!QzI-O?&%L0)=MN7r7wMRr3*f1Ks6BWQ%Z6GKt?2F#?yJHcAHl96n#fq-b1ZtXyv!
zG`2fH%|WKO)`JSCRuF4DR)R)_y$k2*~g!L);dJv%;nJP}i4RT17XZNmM52q-NB^17h
z&`w>hsM78H2HI7tv%s4K$9PJCK}d^)f)sW7?C5FiBK&(79MbN?gAw`9yQ=qg4whe2
zwXx{|JzpMJSl&9RhTwF4q@2=vYfHzhQ%KOX26Xd77p$H@XWzH`8@Ry2aUABnA{}5M
zxS_w#roPBEZqfLa%7&tUcxl4fA$uilikJ~Q5*4z)Ngu+qr`R)PhDU$?jC_P8@UGx5}eirKnZ_5s@JoC@3JYU*|
zMzk~a?A_Ov_kctU3+IY3Ja$awvjIAuiHT`s3M2rQ(g=-KA}9zY=#RJhFb*F-BImC@
zliOJ0pItZxhwf@|KVI${*f4!0|yLiXk{nBr1b!%W;{;m#Q`%TXTyU
zcCyjT?-d#io2-!L`u&Ij5BkJhmpLQ}V8J>jj?pfe*;
zwSjJw{Tp+M1ba$?ReOEdoS}za?&?~-7A~&wq!QDHy`ci5U%D^qnPe{>G8$D7W)e=`c<1tbjRE0
zBF>wO4BR<~>U4J$P~2rgfWSqoTkARJ7kzmtaOkpnD~!X1iuLO!4RQnt0I0Kw_UY(H
z?mK~%1TOuWCW16}oUl}&Y{=3}aK6T;mcRa_8pNAH_DQew>qhC
z0~&}8W#TeHA_%t%W)y$6+A@DO$XXUXx=Rcg@ATTh57MAiiIq?J)G%x&(&X@A~qP
zZJrLDRXeMr?N%xW1W6KE64@4f)o{1%G?6qu#W;%9wzq%}ymNjwVI)E9aHBxDNLe6L
zw8u*qWkUPJH*L_Z!fx!3|;EHwyiU+9;#%zUA9EE+2W+<^&~jM
zEB{vp2?b(7AZP{hz3LF25*>0LU*2ZX~VPni=ce9
zO4rQ~Srhq9)Zsr@^;6v$x6+5nSU6I4A&^*mBPr>lm^1cP?a53x{L5k|zC+utb+ZLr
z8#=*sa%jJ%T3{*JEd3Hgs$N{86#33nSIzpzmT47Xi)rgFUZ^A~N%`)j?}y!os+9`)
zLMkjZVu#32|F4c0KouBpw|1%!==#o`(v4h)_Rq1xBE<6HTfKWCrN(=E-!{;LhvIWN
z{Wl|1fA*|MA4m*-2-JQM8!)xf?K_WDKEW9^VFpyjJBW9iZSLRI;B|5^!ArySO`=01
z25|HPjyxJt1`1Y1mv(Lzc@GkbCL%loqB#koa!yysvp{T=v?5I^coyBr45b7**jaG+
zKPz?Qp74!&&HgE;@2>g#-9%XP$Uf=)%Wc;==MW!pR5#A$*UVSCTInhgLLgJssyM=1
zu|c2A?drd&TBvEJ4I55M++=tr+EHK0XS-QmC6v1H+KM^veP?&
zv)9P~g_Rnuon=eTV?o|uj|WJ|ylD0>3DYVfFkw=)GFi>+k2$2A52BBm+#GD|?CgC+
zIK<%Ae}NWS@*c09c$bNi*H%V+7T%SS0WOKq7=?%b$aqqQjnJQlb^%X{pXyO0LUM}O
z@pX1ye9-QqbPt;8NWVY^zS1lFd%LlSi>(uUYf7KYVV|a;#QoFPA3bp_4AP$VLH@7N;82AR;xI5yLc)TtIx)$uaM^wy5DHAI4A0xIezB%D>|~MT5Mu-4
zBX+^v{;2ka#X{+!Xwoqdzq*6#bDmI0H6>^Qbp~(t5NWCn%bFytxo=p?4hiEbzT2+b
z(jN(5+geTHN}9TFP|HJPF4mbMi%6YSK#12#B?a~_PItYRdzuJ^07yx`PeShj26K}%
zFWPf?C1=Fm#YTAiX~2%>r02}HJk{GBFwNT?=!TtY$x6pdW!f$86xe5>cBSXFZzafe
zO^RS&(`58z`FU$DX$Nih$%ZAHdcq?p(Dn$hBYVz@pJ@77^Vut^R;zC_orO$CEwbqb
z3ACBa@iHuVN_mR|=_D8`II1y9nbCl(w1wPMNvifSzfnE+QK+kSVAz#?OH8ds
z`%7_=+J!9eTo$PgoVghdy-x%j=?55avpAE&-_rrhUE{8)76mF7^#@l-%}`6>W?l5X
zHAR}HfwgJ?T*h!8UqmsWpo0l*4WmWqvwQu0;&C3oQkHXJm9dd8-
zi*7+NIkgmgiXDW97dZJcEw@3t9Z@Wu4O~<=E})P17zoL~(FcGFlQRe0XlxXl?N78&
z-G)y7Y?I>O^gMKs$sqz!FcOwUl2kY&Xzq7We-J;86+4Ja&
zx-p#AhXIV)KRzW@MX<4=<&&-UyRr>z9E}|8VW!Bi&8SLTWef^%^gPKnYG3+vGn(~=
zSUQ9LITkhOm%)1U(I|nO0G!|R3WT0D;~xBYH}3+G^n)V4mK}QAP~wB(v9U-gnavf0ik$-6{jeqKsTcA*payAoZ2+
z_G>45Me6$UzJ1q2
zu=IJBUf*H8TXueEt?&=^7(6rj_wt57?hbEv8A
z8+#s)rZh75ZX@AOZfIw~WRC%s8X0Y6C9OnE`A&SZnlMVHOHQqDxCAT;iZnS&qOOJ*
z>^XmY-E;tFVCvtm2m8y~or-qe%1xlSy{y)-gW(w$<~<=EM3%>5hr*ve{bVFySf9tUnQ76y`saVPhfg5
z9x=8ndq`G**z**Si;Dx(>a`_Q`*AtpFA&5HBGF2?62Sn3J`=^ux>K@&klH
z4qvh9=<)c6xVdppD~5`aDvN@Ff&ogB@Wptbo?cM)Gk6rQpfi-kJc4Z>+qMoss<#4S
zgq|#_-kQDY@!znMXWLschk}8c;OVru#jqFEy9)|uGd~nG_gSfm=U7kLB(p}AH&lQm
z|F#Y0*h(iGvib?Cn|@;x!<}u7EuVu!TA|0+UuraGNA!2Mm_J%Afe2&ekEw`-tvwQHJFXg{Uzx$SHX&nb9b
znmi?Xt0Lx?i*l!_X25ZcUvv0Iht!8fZXFeT1vVKF1o`6aAF0}#
zB-4b%4l<_ePUAGtGPBU%2=ph#G0twcsHzzfPuP$-?tfNIc1j8;GUmzdBI5ew$21!-QybX*H`*k4MSq#MNm6laIa^kZZu>q#^Rz5@7i+dAT1XV6
z0vTHZ)HncO5lCCWKYvF--9X@FQwKmIKRQU@Spi0oB!GHjl!GCXsXAPv>Ola_I=C{L
zA2J6Uh%z1;vYRHz5G)hySTGiWDM>T}>n&;!y>Erl)o7T=RoQWf<|7BVvB?TxXe5S;
z4l$Anu`dL?(h4k$PL5h%T8YzQ&);P5K7Jrd#Cnqsx?;P=Tz(YMxa=s9aH4u
zDH^nbji@`}g~rX_5f~Rpc$WP{~P1xszDxO9?=Jfra=-;y6gG5muzoER1Bn
zqtJ1_ej#D)H#xccZ$ffLbv#rJ+3=yq2a9LUF!Z?Ez+y^BDcl9fB>QtH
z>AV^Uvw|8(GbI-xtp>0Brxu753~j`TIz-_HH%XH9`p1N;`RatL#q9+AE${^V9X4X_
zN(&KZ-Py3Cx4+Qi72ViLY*{elTGK&CTbQD(1x8XeQ?^P>D4^x((dbKqg%Hn?mcrfM
zQ~CP5j7mTO=3*{ssD;i_oQ2O~@CE1+tc3_O~h9}?C%Lnv^ZN)q94i;VpH
z%OfGin*(Bv+ij@!6I(*lnl7^huMdInDL4-T*4iCv)14lgv8gt*v8fKVF<-CEx#*6j
zH29c*o~J`sg+F}u9z){p2F6>20I?S(^DRO<{Pn}B(QB>1vA^fM$^yAq`3`(sbPU3$Bt
zP7Zm#ow
zq%b|kSnFatWD|l!#xB%c=P57!Tt
z>Wj%WYThW5+5NB4h4eEb`+hnb&9}ra*r)I{t@iV&@gw^uW|{!Pg|s=(*1#6a7mv2T
z!Z8FL*>N-s69E2*8e2@
zbeHN3cK23z-y4N<9uI%@Vcoi`cg^*AZNz6=npbk9U1B}$=IZnuN?SuAUl9{gb(tRE
ztknP#6l^q&s~ci7Pqo`iy1H294rl6R&X$LumD1c0P4~5q0dXe_<>t@^YTqvBM#Gv>
z0KQ*g(d45%`a(a~BN{2k6l8yg?;7)p$pW-%S<$UyK?x&La4((V5oCa(6>aAfq Io
z$b)@HA&~B=gb<)k;bg5ui4Pf@!?+}PM)D8DvMI>@K^?LV)&fP)Un=nD6>X38b{;>(
zFVecyHPtnjvs2+Hw#WOZ+N&+xWzFlifLQ6ul+5e`$}P&(%R%A5H}d$|bS2p_G5$+$
zI?Q&iO?3+7$LCR>Y8>xiG~Eg_L{_mv0|Ox#yTQ6%1)hTJJl8S=%0C)&s3;Z}H1Q72LC^oWpUw`*E
zW5d><*bk+H!1t-RPz~@$oIEo8HLp@+vuSkD!xp*EDC_gt-X#;1{o-TztG`IDd6-kn
zbUc(uS+B467SjP2ck807Bq(=zbD}7
zKjFo_z;b!%nif)`unFszlQI3G_5OSXR%Na*3-LVoB_Pxrxmpr`Rt2XP&SqOzKVbuqS;xKTXb8=^)8usg*+$g
zx)qD>N}w_5Yl(l62!}EIok^dfk9`Gv&(vCnuDj<`uxNQH@csp(!k+OJi&O_uZgxga
z(m0@#$_;zw^n);c!F&ZgpjN8vilF}%@3ha)lBw_dWq3B^4RG`?B+QTnUJ@A{Pe|d4
z1T%8JrJlG~B<68#g0?hl83rS}beOhiLzH9y^eNNV-X@qwPMhMludw2JJKgR4!O_GW
zb=S-0e3!m&yEfOe#v>Y!K5MF
z|CGJj7v3Cj2d?A)fZ>WehQvoZ=Z-AmE7*g5?F%+mVR$sLwAj;dS$*&MgzN
zI7O1QnCbCZD;AXHqD1E>?5SoMKJ{qQmEs^gn7HdS@&%<
zq59g!;YdwM=(QH9VFz8^D~amfBM{nW7lSm9H)jV=%-&2He(D1{r%ck9XH5Ix#@JKR
zlVFaNo>du@5QSw?`{yRr^w8{FEpS(8&fn!<1h)L&omeI^DmLhHH5NzEKSTxMD#@L;3s(A`iXDqM5N#gr
zuwGSML0{GyGkGA9=?bp84TGo21~#e3RX6mk(T&H^i}kqAlKOc!M@+Lj6U`_0n_)en
zh&D>%{E8a9`!@zHALaF>%?FcVApjn@YOtL`aOJ?K%Ligheb%khXE32BH7A}a8*qNM
z9fgwf*5Wh~0=FeiSKvMflJz~)z2+g8H+*hUAm?YA^4LDZ5zHMT`_WqgGeTj6i1by<
z&T#iR?}}G&K))T5#rKZxj(mXA5$qZSLbeT<75JUL_jL1Mp
z-aYPQ@`C3+xvjROo%
zF^h$2UWTtet6qhS_!lP&g9GWXLDqf6q>8hAR#Yi$aG^H56zfqg5r?6!h^epctx4Qo
z7+V&2;rv?n5#2ZMhMSZWQXm3>!=mve@f|EH0t=vljnp&}IHJn*}
z1m-aPz38!q{bbd2BPjKpXUEy6yhg#XEIAg|YpsdNdq0hJ@w}S){H-Fm?GKSBVUHPA
z%E8So%GpzeMaLS;?@kNtr?ak;`Vnw^edPr~7DMpyMlMC&q`sTAmjwG3gA7n=|Gju>
zocYE}H@5Fx&1%|E4kNsrY?bYIj~lDiob=}P?Nd)JIU^m`I=;B{aV7HcGL_0?bECSFQfch7&^OI?l$M$(Snab(S)hH>jgMQPr4jKX|rK(F63JuC9s_wl0C>J37Qk5prz
z+3t`7|1V|W$am~AboW#5cKJ4&`@RDw<{|XsVZhC9T$YCiDZwstRmE2@@2k64P{66R
z%hQ>6S4y>B305>$yayqJ*y=6*2pvw*p3x_ry3djqUlmhpHA`(kj5PZPez-VW<}
z^meJ%HvN#Or;aRG`~}Ws%<4S75YD@()YgFxNRw*pw=Q_Ai;(t7#=#^Dcf}06--Z4;
zt5ofM4rdDT023SgDvini?wpbnTvI8^a}z#O)~MAGR?7jet2}mRhu?Ns
zYmOEl=`WJHe7(4gr5VSj8GSOjay{Z5S<*+d?L1jlJ${}%5-HZO?r36K!B1QifEH$o
z&N+YeQ@v(*0_NOlPjCG6`+SGHe|=>;{0W-eyw%0>{_8Pfe~p~;I_eM$IWCC?Qz(jScQ;oiQnSxd%jlH(=mE+%~s55_;p=d
zGcr0$b-IW*$T>3NTSt_he6Y?Rw~1CoL>X89_Y2e~!LqK`Bz*J*gL>0`0r3ZyP?3_~
zVyz2v@qyliFDEPYRGB9O@yTh98iAsfDa#)B1*ye|=hv6UHDk8E0L;IvgdCO1^!9)CInNdS&-e*UlR=IlhMtd&;>XMM|3Gphzfr*`O_;au6fCYcLOs;v-
z9_$$ePk~6Xm8+mE+z=7`c&h2O(5VU`XfZZ}iBR
zowYMK#&BtU^sZiSZ99|z2I|66%jbZS6o!qeUTnqSfY>fSD)37DfG=sP*URZQ<07>D
zh0xxZddA%DcxHN%%|Dk~IAV(Eh7=A!)w9y0^Ul!0B!jOKV)4wUT?bQT{dRCzwcn2#
zZgdwKC0`{s^_7(Y!<*8_m!h22bVNN^JR0w3H?TV{;ZGJ~9BL`rSGwe5u1?+^oI2mZ
zV~>}@9kj5GkMW`a=j8o#ku0FSC-GC2BIB{K(Hw)!KgWZkYKTM#F0i%?xU)}I1_&{C
z_yVCL3K$&v`N2o5;Yqfj{cA343xe}+}U1T$iDoXDcN_bTZ50LjgN14)7-7s~wo
zylz+37=~SF*T?IVPGlQcwbRkXyHD&XCW{y9l10L%3bVd8QR$@J_}`EBC14C}@Cx$fF9W#^LPl*#&Jx2yQkE?g
zOKRx{c|opJi8k_Pz7A;p!XG!N_RzBoX3|^BmgU
zUc?47rszQNG1B$>&j#JDFrWLLzlvr7L)H{WGR}XEYxQrw$-B4I7Bz025SN?YY@&>t
zf3@F?+?K2SEIenR4iprZUEI4%{+5}*<1v)sz$Gc~+LWk~I1q$Qz#~N(b*=#sv5Lp3
zhr?Dv){RZk0DL8Impe9*TcC$Y{${|26@YB`ZKQG(FaGRN5+vvMD4D)w`!D)SVy?S5
z+n7y^zd9da^$*V$Pvn&ZvAI+iiFsjXheF5c!+p@aypME{-&3@S1=Rgyp(iqfC4T()qOyEX%FG3(?~`s%RmFcCR+VOM@g36K
z2J6IG4dZIr$knHCc}2)}2Zk#VwA@4-YdVkBW!Ncv#53w6nq#2J?~4B0=f@
z_#kpx%KKHzBlT319q;yjzQ7h+YmnuSgf3tGFvnhgU%x8iesHU*xZ%|;ZDM^{2?JB7
z0)RqUu-z0|<(x1~?E7BWT%@wL!;9
z`y%|JlMcpxN9T3zfaxxQ9{d~=Wo85Xrs`wYJl?DS)(f5DH~6UGFF=c_D|tBOY&X_&
z#G|tVN7Um_N{w*#R}3E_;+z>dBjH{HI(9WzlJ__{R+JxPZ7>2doc3a!j3#+N^mh4{+O7kh1&w$8
zJ+5v8?p-<--pcG6OW_33DB}Maj1f`huB|@!EuQw=cZ%86_N7TK*mOg}+-L3l34B%G
zCE4+U>yq5z{X7Mu$cd(ya{~D(7k%6UtnVTxmGR(9htt<>;^P>mb)&WL3h_hYJT9?8
z(Z>5BlU@EpdLL)I;R9+z4kS8=zb?hRDR_8Xi}VJ&kIUXL`5HAvdJ7g*YkqHDygF0X
z2$r43`=tVDc`yv0Tqh-ap(L2>liHwZeK!p{z;NC0NWe_DnMHyy@uEVzChaZ3AhRx7
zK&%3tUWvi_(jsDSV|4I^1chV(AnE3+FbS_d+}5D~oqB;Ao28X^t8YfB2j$VYEaU}>PKV|CDBt60P{jC5iZmYPUN+b6{^%1rx#d7Clh&~>w6#!
zS=msz&((5STz6Z?%90S*4U#yg&5
zgJs4T;$<>F8f8PT2_Ml2J_AB445##|kJ^lE7NS2RkxWNtN+(aivx^~#nRziO2Z`;3
z0jHkfTU^fkR5IiXQiYvJR6FTGmn>e2A94pprD}SCj&w4sK4a{HvUuVG0fn>>tDX`i
zuBQmuc(UqpWb$HL&8~aWryd$YvzC6rq4OD}KjSruoD%tF2@y3?!1n!7FEj|!u1T*2
zOyn*EGKPFy4WBBBkh+49iYQzz8FLpUnj3?ucKCZ%h2-Xpv*h{xhpboT@}n(-q%z9x
zjDzF3%QX&HaIh#qP5V6c8GVfxqZGZvh=qpwoR0>JyJWv8temEZcR~c$Jr3z9hO+v5
z0ed6NBbf?LJynf?Zl&u-I-_ei>w_nrlyW(|I8y8TQC5}hbd^SIYH-kM!DwyBxdyvL
zQ)b+9j$tAS@+l5F60-j;6D7^T+s}-lMK9K#aYns>ps&23VovK+@guk~60nzP|(8$ShNIljI
za74vIOalLU3J9$_ry=UuBm3%U^X-3B?dLxA`jK9Xd%qfXTWX)eIwjIC9iD77fW%TK
z%{Z@Whe19#c+yVrmzBRSl~etCr?_#s9AP(_IvyWYzE9I`K$87o8INT?cQgqAv!L*>
zwz(pBjebV4a#`Edh~_Rc&Mglz{OKZ6MB5FRYMmbq>g;X(QrhR?BHhSlE{)mU
zPT6%ers;Au!1vu?E$x^=)>!sCzu(a*0LZamwA#FPy#7^eNhST?ro1|rtNscG
zFnA6=IF-F?D&f0P#uI=zS#&rflU{S{3SPVOV%17;uT{h)re_?|d5pF#v#{>HCnK&=
zokn{_i20)%MYtgv{Do1*ICEy_>eDi<76{
zFLzFSlQexyR1&huk)(Zv}Af;u>ULrGN08Ui<6W&w^ayvBfe=
zs7?)#e}@2h^Zg72BD_M}_C39_tRGt&^##RuCoII%vW(Iud7cH=Ob#69>>cDkOhOdU
zW6h8AXWXAL^>0=SNs`Tuwgn*_=+WHYSnDQP--pqoQ->|Rq1L0s!9(w1Z=p=cG?vD`
zpLJdw{p3*v;yaz5OSdwloo&j10gJN&U24OMNs|xS@?DS;UnEO)w`*0776I>98n00=
z&|k@?wMfl)dA_}QcpGs^^S>7KFOgjSc*uVBsPlDb!2lHrb`}EffbXl--j~wAS)luA
zvQF(V5pW}EZIgm%>~Xt#G_Q_*hogr(JEGl|Z*^njV~o!-%n@JX^8MWSXMWq_V?a#~
z$yDKICiccpV%N*3$k*?dUCkZ7i7L4rdUF}hOrN;{T7p=xTwlK%jp=52nabVy{;uot
zt!TVI^v!)>fAd8NAHKH7?q_^32ojOkVdt0qZ0dJPdPrIA$_`XV*~5y4Vz0}+bE^MG
z<_Gpvb->3ntF6Jm75nCu-5&Cq>JcWv*)R0mIqh3no)nLOr%ly#(QhmR-=&XS#xKI;
zTK`t)ZTqlwjiG~GK|Kp#w%5IbH4mYiK=)|zTZh2cX^H1pMxKdnn@d`+W@q!)$r*P{
z&qK7(X)m=5?9E|3)vW`OK=;>!o5G_q1PMr~!E+SWy6=aq_J{OB_FZd^TJq^p_g$+2
z>#+xf?aWVqYs?L~jyl%)DzKNS{lTqY?q__y^emU*4`!6SXtUrujP&zt14zNND
z#Or%6bNqQ5ppl8WyPev@MSMR3nlrnif;##Kz=w+M9r(L}q@BSMkGz2euNhPYq_^CS
zl-z>1MR6(B(|MqtUIIW!P&7pt8Z5y21F*kszl3>7k8-`Xo%@O~{{Lvi@|zD6KQ2C1(O@|Em~e
zz_F!tM!=2N9hjnQW?4pnpI0jQO@Hc`&N)r1{pl?QDz7>O1u9Zes;X+Lt`-`m{BUeG
z1c3NLQEHl|Yev?1&!IiqtC#epcDf$do7Z>A;Xb*q?iZt5!DMCcf>m0L9Wsq+@wExs
zcxJE!m*7$S(DB48dEaorB#{4el2EQrtZ$JWPKEa5M}hVnEgFr9#)boz7{q``sN)>x
z!<8!8^*_qo;3l`Z!(Hy-riyB6Y3BCaQ|w|N`#BJLc@`&@_IH+9
z39Do5yfQBbOrICL;*cYbIpLHue#RRgJjOftFGtVutDTMniqvTTZ2~cPUdWFC
z+4cB5XGEU?6VLm6vFk-dDp8^+Yp*r$e@KNlAHsrNT;UiUx-IbuGd6$LLMK(vC}LQF
zyXS3Lohs53@P(_*Kn%F@%OYIv_QHx!k-s*1K7kOS(#+1Hkgt|pdR$`YIR#Zng-c;J
zZe;f%3NO2GbGt@VevL-9Du|E$nCT)hD!{?IfcSgy;lKWM+&z>O6~qgY1vz_LMIR{$
z2S1`Bmf&(cG$t#?`Y`PlLNgxdVIHMeEPbPPO~~g^yEXI;%O{VQNS?fIH+)Vpc^C5d
z9u*3roz^?Q$3GyrE2Isd3K+XV6?k-ZlzMXPPZ1I1CAd6-X_x
zNb*sa#0t`sYffD^bDx}IG`YFt-67CgH2Jp;@Cg`Z?19@!Efi255N(i}N3`*thP<(U
z1}ylJXB*&*(REY7x^VNDb;m05W`VuB?jxiMj5pxpcno~g?!3U0i}ygDYP(2#!+ijV
z0YC|E2m>nP4G=&w*U#HyVVYntR-2FDBK$ExNJw^`&;uPG1u%igk0xOU`hN+0FC;D;
zVPwmtLfshB8C;hR@Y*f`bD_C{5-9;M*^i@06rJL<`qwoYjqZ!li+NBA$q6cpkCkeh
z=!r#lOqL!hxKc(h@bi(B%tNmP2a7ufvsuvTX7BBg8CY1k;ijoF&}v$
zp@`T=_CqAr*GEhZoP|GJBozoKlxB0^+R&&d3@t*_`f=kLT*)J#g%#5&a#p@xhH}e7TW*LUgpa__`)1!&
zxT|uKVw7%EfvU0jq0)p})Hh2LTBhjuX#=yX#2Wc_bn7TRfX?*6h~95mFb_vZEXERW
z=(yF2RHpYXN8=~NHGtEqFH#B1bm~Toh7{H1
z5nzCf_DMQAasUsrdni-ph#%B=(}}Q){yMl2x``>g}Olc3Yvvs*c|HlxdN+`6rpA
z>L{EUFqGT|o~JC%sx_$ipy;Z0#pI|`xuZ2;F|_fcZI_S?ZVGSkF(xr|8sRX)-a2|@
zqf*Ms+Nxzt6CMNjKGAm=XqBR8{=sBPltvaQa
z1fjF}|IxUjRS)lRQ&6~MFO@$wn8IJwkpIzMthYJkNe#NM*h1P>8v!}HeYnDPyndb<
zPy=5{#CCLpml|yGYQt=JB@Jy9_YfOxlynQ21R5h4Sn(7IwDT&_k+oQc0g)Ac3jnJx
zkUGm%+-+m?A(F<`%*?&RO`K?^DaN&?4LWG1=T^-=l=axAKl(4}C~>7nn@a-eoDoL|{Zf86@ZF~;kSWI1oL~W49O7mh_zswbrP|ccS$a27hn)ltcL&ye
zGiP5jOXcF-07&2(9&GW7fUT+)&@&WwYTPkXW+&CxL{Rkh&LiBvT1>6=?y8!ybB2h-
zbBLavdlvnVW|j)k+x2Q6wtN-o(FRvnd!#N3s~cwlBpVkAa-d^NgD6TNqcBa
z7ie2LAvc9V7*5d`Pbrv5dH6Y1U`dU*r!G9BVH~F!TrAaaJLq!&xKHmq$z>o}1|hyB
zG{PnVBF(5ErPv)ZIqtLY;BN5LkQLdJi~mSvO-NiKP)j%H`ygPHT?wF=o=|H!!M$z)
z^8|r_V3BGS-snUr-HGG!r@^SAGytLC0EY>Pg@#Q)y1W`)1+4`D0Lsn;Z)YkgxfxK(
z3TgmKsSH>P8)datVaV%;casQ)auj-<9#B#%*n%W;k=~7!{qE~ZH+%-4a0w?Ha@>&v
za+6GVQXqvr*-T2sw+ZdH+zIc*cQQM9ilWb@1(ci`B|(f0sc4q-RK7|zbiuqz8FK~h
zpjNs~hnNo0*!6-;yW#?^g0^V?H70bq>gVasl}1|8XByy2KnVl0C)y{x(VhB@xdLVK8#I9(0#IIdX8-%?Y}Jq(9$0dn6Hb3yoc@Vp!s
z86ItB%U>;ZWyJHm(z1k~_}^f>$H!Ms8!-$1v^rIvBUJ+V0MKC{rBjrG`OGOkUaM3i
zL{vEOkTnTf0{-p4NU|^Fl~`1o`bJnAw6R0PY_1YA3$jp007t#
z<{|h(?w}UloA8f!TWX2$m?#!&q771-9OTfZIGQVBCHACBdd^fl<(gpRyLmwd2xJx^
z)hCExC9wxcf_z#}3X(0|&;xBLkgs7$6~;;(5i@zk)PN2dkx3wmIayAZXe~LaO0CQ+skGj4BW((a?Rww({@5M*T_;v7(*GSz{*3+dbr+x0tF3}S*Hqdh!q`+_}Fm!v$2s5k%
z4kI!{L)%7gHYD)CIBdfAn4l|;niQ&e&zlNy)AY>r*euL;>15nYty++UpYRmP!{v!Z
zTfC(d%dGOMoE1}rmDFha*kxyk!glwaX(L+%t=YCeXnkU*cE#hpy-?}lvMGmf*zZm}
z6aDEO$94ku+Tqo>w{#LX9Zfm2E8E;I;0s+OW`|3<+}n}3vTM+E*NwdO^4xoUD2{L3
z(cKac^e_@{WNOZx{@IiHS%&BKaNdh3$vqGE*u8IggCBC_y^|RqQA$Jq!Pl(%bSjB;
zk>9e#<-by1X|gM${UpEiyI&Wc{Mm<)Gy=w4CIo6=G0hJz1Dt*dDVg=(DM?4u>CnU4RYw21V88H|3GA4>Y(?hZ}UB!wY8!Ptk%yEx})G
zEERW2>0x7e!uX7=HV%HSS3s>M$VZVhDL!v$g>TYcGp37XTRJuO$pwVq69^=1Lksxc
zLn(QI`2fTd@sV_qd**@Wg&EfPw*j|m5S%b(e!;R+O5Ac0Yo
z^eoBzcQOd`n{tKmNP|mSL7mbdz0aXl)>rg~6L^SuZan*OfOD|!VgZY(@Xkn^ZA
z?o%T??u>eUMQNHG&z$#XZ^Yz&^xB{LyNl0O>};rg`FR5fzyUf{!{TaJItDzT0A@_{
zK%Vea1?U11m|B#M!3CB;m`!o;w&CfjV<>_eXv@+3Fy${<4SS#jS9`N#xC{?%P0x~g
zYH8vTqP`ia5G4u?5SE6k3fKPNDGpB~uI2|*_~y}q-p`NjTn&W4wae8cEQ}KL_QKdu
zyIpmpA@#M<%1*!|aC3-SdWPf}+dMSI9+?=B3nN$jC!s0=-Votqqc}eq=r{3M>txm$
zo_A!ohX|wUnNskOOy9}m1su_NZA0QG4P!h)N+@mLkB)+Bq=}8Y^Ey=1id@E86=C
zK0hb^wu&U-SvhG`8v;zuC9U3`JM+*4^GsXfL~T71r{;rzLo5TinhlEp3as4{>N98{
z;Yi+zgNoy0RTC0qDIvk_2;Np2Sk410lE{D@*3oMV2xnB=M5xm{8|-?*$99-JQA6#(
zZMekkbi}OdEi1BvBP14Xi=(R)E`ce#tfe2nw?GCwq-gNkvH-5N;oy=Jkm7q6D-#(v8wHA&G#E695fU9?7Nta#
zX$bG+Vg~3{mzF{pA_^ERq^{PqsqKOTY0TM{`i!uQ`?O52*dCIeMT-%w8PfI#p_VZP
z!&8COHc3}>4*>2=ybHAdgO5HKgd9x~CRQGp+aRi=3*ez(v2?AAgAtXLF)!~;
zrV~zGxXMP^Fnm6tfcPBAk}DWT0i0QBranp#$r0k(Ao%8gWd)_4rn0@<7#Yy_Tz*u0001P2ZZAZ5oc2gpQWBUX?SN*
znx*wGsG~Xu{>%>Pies~O)%mX@2pmWtlj5Ud!%&67bK3}8)3p?cQxBg)jq0uyjCld9
z9fZU151JkMI0x~UATutLTz7U>{;AwcRNw_oceM7eRo&Dh;0cs%_=A+t8)qoX72%)m%KSEPdrxtV+C-1tcnElUc%P!h+?
z!m~|rX=lcp@>pAzsA(&^u5G>&E;T9flJS*`r6${k3}#Hj6HyHdWj~W{3x><%w2!GL
zE4C7oN~>&J6x7%7J3!UqcdTZJMKI7vO~$!ew&xm^M0aN!d&qukH*|2I3v*F1{p^xm
z#y8@+BA0R7F7N8Q-qX0(4Y{!!4&3n`z^iVH_irj(a#oNGFqBJD4%17%
zB&E5xHmUX{O9eGiZy6)~=4RJ+IRUpf!lWA1PAVz#PeDvOjw2&R33IzX^`=Kn^-FBu
zL|CCQlVBw;H;^yB9g0?C3K@3Uzu6@TjwWqHR#WAfih?zcb87}miHr``a67jSMyBg3
z*41q7*i`s4i8)y>8-)CaMal5;>tAdeV5iH(fEFWSCEJb)f}-n;E&!|jLdN`ZAczD>
z$GM;k*{H$qN|?#E*^Xx9wgYMB4hvDd_#BdPhWYJM5Brjx5pqLO$Y4!3Oh{+FVJKzS
zO^PF02&>KsE?aR$)!aqzECRwEing_2OHNW1<66h{dGB%h{|xlc(jQm^$q-QL~x9SuqZH5G`Tk^KX
z8lH12jV^s7%NjPYtEIu1YbixD-(>vD?q6bZmXV)RxO9`30JDvzufT7=rC18XU+!Z-
zfEF{X=psXB4NIx52ceaRJWKEOMN=c9Pmy~oAYNh+25X3hR^k^kY$GUj-7@87BP{`+
zGzb-z7)XIs%~oVo(4Ein01xMhnS68`QZiTLMyB+?YRXJ&4#sQU+)lUjnz_LVGBP&)
z(Y0cqEf)l6z~)de$UcLM+I#j;U*>+91>4W~WV%J1h=CMHm9&UecQ&lI7BD1a#MBZ*
z>NU>b7e2ISZ*la#J747MAIUYJS
z4KT3Wk}T0rK`YwR<#Id<4nkN$5Ua#u%L7O3?P7xST{Oo|=o_}w);-0k{+j!1pvA^h
zjM_^zwHNT=i6)6DcO#eWJsWp)w_9lSjlcZt$(|9@Trcu7(;7eT*LOMn3q0{iVhkl-
z^N}{a4|yR;J%$m9d6z
zP>RiuEe*pk3lOKs$3(ypXhb53xJWYpJM_qj!T=p;21WrGa07FEA>g(si79?EzJ7&o
z<2w^Pj^iS3^YK&E5*9lY){rDzBAKsGPn;zDHT~=6uSdUz-sSl9oIrSLdXm5x0A!GTSHYp-Q84j{DQFps4a9T(`Ad94NQi5)J91HI5jwPYkf(XIGxlw6
z@KMtNSdZ=PW!lBQ1QAPrQ|GbnHvqd{e-n%N|H%P75%QF{`gPo>`xyvIz8REzi(1mR
zl!w~y5b!Xa245|VJ?;rldd9P!v)=)SJ@1I4jydjxlTLZTi(ZlyRkIz4{DAX--z~Pf
z#Z>VLf934S-JW$o%*w*a%20|{0_{M1Z1Gzn9}lZYh>iB@8i*d(r^?%R$l
zo=l3VrJX^hS%H=8bIAh;JD;$hh@WVmn4fr`#J>3RvQx`1g}OZVfk|wq`gT<=zQ83Llmp#3<0p$fazUV(peEhl0kUQCZqUfvLynE^b;tL65V$HGs&x@%Y#SU2_%waaw(^gu9W&;{-^(|Xhh6Cx}Wf$
zD02FYYS?~7ivq%|h?AkXmus{c)Thr$doDbLxFf|%iBcLxOxa4_A2Ow4sp4GKN{!n#
zsY~i(HEi_oDf3or+H>r}ttam{rESp#lXzTP0y4{BENOzxn5r;c!E_aokjH7Po*~
zL1BthhKf|9HVq0fcbpcqrIYvGE!u*3r!722<1NK9Esw|Hg$BEzWwqNRBQJ|rz^kw;
z8@6$qnf2Ce+YapXvAwk?d*?<_uvRd!z!#L5>k1wqP`}rD_4+4~^82j|-lE6>ak~sF
z&jWGWDNhwkp@kK5`)T|)u;u+-_)iV)m`)xo>baVJ_bV3kUQp*v3P9`+p!Qb*;8KG_
zmBIJd9%(J3^MwP@(IoH5%Uja$n&iABxjXrQx5;SeVfM>75~jgQ1m-T>gMyuoGO@It
z##-)*_miid=BupKsBFa^rXq%ADtlk0{3!jKf^{Qhl%NP#fMV!^BU&EP5_Vizkf38|
zQ%H*6?X}L+P<2I~P-qhX2QD;;d_#hSOf(+xCQ`z2MuM58JxDn*?n9`O(43g$
zOu0-TVIp0>=f=DsT>Dv{G@&?TdhPAi3b=-ZpJ>=qa76f|j(Xh_F)7awe&hV4i8>yp
zC5LYaGtISIAqjQFkkLil3Ch}yj^OH0T0s2%cPh&X&;n!=AirC~sQTtXAdR5v3ZSRA
z^&@5GV?kDObL*#4ucykPnnnt)LYK~UZ89@;m#hilZF&LM7=Tj&tUnmirZ)*EbtX5R
zyVsoKxoB+^{{4fNnFa&bsLidcX$F8Pfn;33O*j|D5lKNuBYFyxg0pY}=C>?H%ETt}
z@cdqrZB5OVPHTz&ek;;zd)~r>N+^_Hfg&(YATai=WL^5dFjfFWQ_Nd0Y6vB5rSbJ7
z7wuN0;|v=0rcI=IQEsi_I$`7tJC$@3v-(B6H47?G1NBDuh5{Hqe}LlWhPxgBm9Seo
zp~5tr_g;lGtUVjX!r0Ta-fs+Ty?{wVSue>bq+7VX&nt!?svpBVGhlmmvByyE^gW=D
zD%X}A-#~*1Xm#HJnm;ucSe$fI=HC|wX2YHcgAW_&!MtxO6uPT$-I9II@zVG_0!!W#
zwzIl4dFJ%K=oQjDM)NWq8bA*5(SUez7x9G~IwR~0rEF-{jksqS$SU07@5rZ
zj46~;|H(vVHb6gDnji9_$J$RSR={3F_CrwTdK1b&Nzf$`{osIHB$%`m_78gGU?!=A
z{(}sbWU3W+kPH&b^AB_wVXQU^OvEQN7BEE$gwuTb<0#Y?7&|(lQ^GkULZBRwybES+
z!)b97Vs1)531USrF91A2v{u~tfj#hzCb<{S)%27{cquv1eco-#dz)z>o30PCGNm(>
zyL0A$V@J2R2MyHu3aPG=>)R@DVD$tUF4KIsm?KT|eDyplUBEV7Jt9jy@a}TuXywe?
zfsxSt5YBUom)DnB&FPsR{^!u7T>gDWo4|oi08+{M-IOgx12+5Zh5aJznP_B#R7xKm!r4)OV~CBqjNy1`mGPA^n%
zVzTn|h-1fbh{MymbEUbIxesxvLw~|4m(^8lYH74hM9Y7lZ_bo#U
z=&(swm{=P!+NhRw+tVgK*T(F7jjQ+vK6{EX-d-Qu9
zPD^tPq=m1Mf^>Z(J4o$>7=BC1z`C3gr)-He{t`i}02(79o$S#8raAj&7ptf;jOe&v
z^Xxt?1-M|lX@u6hX9z}1yGIDjAhI5`G!wcT~ZiR&Y2AvGtLSw$Pp+QDf?EmjN`%8wy^_S#`lK?d6
z5_sC>2ml69)Vvko2;1t_Gyo&4Jw-En0Law@0BDx5)BcD408FOa_$3_7E+>=kf|`*{
z^;RFyR%CaQIQX94#MDQ^dVawNt-5bnE4!cp-8OGU?esLTFrY8%N>aG^x}^1~^hsT&
zNm4xSU=!yt5z0<-H=Xl=E1k(>3s=MkV~RrPou?T(#?VDz2$LI0xQ1Nm5N5J4?1S&J
z(iP^xvos3X*h4=AOO5wdCVt!+L?SeetO+e57juz2W}_8h9&YdDO9ctPG@XY+=1!V=
zWvTDsR+A${>nlyPu?fQ(kMP99p2iIuV^(9deIw)b>PF=~YL{oIj_Mz#G{nxhs0QWD
zLl@KqYw*ycK49|_^4V~W9ds7nq_{1zFM#NGk<@#}`gu(I*3uVQ0P;mGF1
zwBjUCQ^uBgjNECv^52mWDCtH-vwhi|uShTvMiOMj<$OQ_5LPV3g*Tb4Kf0lq3?!e^
z6%lEy{A9CKgq&Z;&ldoBt593nLZKC+n&H^Aq)=@%m>MHw<_YZ>MR0d;V?|M6EutK$&E386PP=@DXmEzp@*NDL5PfFTc>PN(_99!muJ5A
zZUW@Ti9C2XUN;-~GrDgDC
zIz8Wo6@~pjhLJMq4Xc9lu^j5Mf;;jR8bbM-*r3ZOO|d{%X_}az4yrmfK#Wr0^yp=CSnv$u~
z7vebO%dt?P_N)u#9=@Yc^`PZ8qJpHxbgPxwge1SNe);Z59wj!7(w7L3^9;T@A0?Eg
zVAGFG&$1F2iDFvC!;;V5#T`+8Or^L+I%jWw-$Fr5j^9F^1rQ6e#zXhTD&dQ0G5)MH
zqp{;fmCs@rqP&j!#siZRD}eHCf=H4OHAs=71EH;O{v1NWwZwA7GC{d9&tf*>`$-(g
zuL+5l{dqtB6b2&~|7=ntUpP?n#uiM?UDIeO4E(AQe|e-9+TwmSVODMDJN$y|!588r
zsYVFdy;BM18b5ZzbS+qdyHX)>#GW|c1p$O{?+R18)Cu=bt~6;xo{-e8%u#|U)rI+y
zK7fEE?)WxW!UefGXiF9pPXYyBb`hId?jjO+i@WXvh$r$cz?&|ANmu~=)I{4tV_ATz
zOF&HGC2g{8{G(+sMwXrR2E+WwFNIJoTf|R4t^@p_{9(9@)qo^#fXwNNU@S%3S)_Rm
zGN&1I%_e&5LRSXp<^M?cg&*n$tL5M{rf@hc
z_J(dy6ijF77;%c>vZ(Th@vbECv@w9RwIv0dR#OyHAT1-FoWrfRDzmgzyQ!QflEhL=
z)7@BZ42~elEbPmIj_*?iLYeyM4DP6@chBk1I_9~&!=$ePK!=ZU(RqkYjZOQJ>Yu%|
z=XC2LZX(rO=9)N=#|&TLl4q+eu9??Yr5dP%)v_?z^FZG-NQr{>DrV8apMZ-)iEy^n
z1VPEoyNw-pYXq}M+Si!z@%*V5@-nQ2K4i}=13Ae!>3
zMJD{8tWV%e9<=~caGw-%yE)*x~S4n!l0UgnPf0$^3lE=gc(;q^G{_+1bZL%S^n&7T|31l8}1n
zYsU0rH$b8a4E#i@dnLJ1fOGwImbS87DlNp;)MU#YoFv;*B`z1
z)nm%?Ero>R267j9QHz@(G;^JxvO3CN|K~ijj!iE&a+?P=FW?u3j^phRQWl4`h4D2B
z+32M7jIhBT#BV0W>0Lx}c9C3cQ8SMAdeIXt%iYB=s$n(N70Rfq@}W~Tae&goBAVG1
zM78CfjPSf6YIOM?Ll4}c<(f2OB{4g-8nJwDm*y|@L5DRw8};6H`I&Mo+S~rl4g%OT
zCIY((Kd^C(8)y|~AgW{(Ndy*!hg}3Q>Kl$hKdM0m2wR(-YrkKCpnK?7PR@^ZXwG8O
z4|KdfEQe7cdf#it(&U==qp_#2co^}t81?ZP+@(X)_K3qLr9W!oTW((AH^7TTRVeB0
zm>9kE0~hhBIZsO_WVu?5(!i~oCqey*KtYJYqU}hDiGsZAAHB`IHNo~rDN0Stc@yf0KHqh%ohu7O%c*93;-A%k(d%DqQDDf^w>)LrZ
zjeL1S;W*T5yWuc-YdQ7$&AylZXy3Nv{WJehl&|93WW(vdv5|0mOf_$BxLSx7x9)Ip
zmB7pO`lW~3@2cg?hpD`T0Ce(*ufyfvXlbl?-3l1T-(P0UjzWebl`B13CB=>G34igY
zTJK?}TyEy!wT=Aj_0GOd=}{*(cv>#h7hRTpc&B0&!eC=)JcQ)ovoZ)l)(S#^%lo_%
za3Cr7*p)qy9PvK~KjQaqs#919MDG63SRWb-&(WsErm+f(lc)65f=8>r$7TK7vl!1m
z)$``$3B}HT0_z(a5_|scfPxUi^ACs9IB$a9yK`7|8qZ(N%@sWd)z3;(6&j#XoL0H|
zcAD0|_Us8}zIx*b{h%fhrc=@Aa!}DU@C4Dn;DF)a;ua4BcNT0;U~_>{&(
z19`zWK~ncLirkTpREl)-#-SuH#fr!^YrZVn8#PzBG{KEbN?iX^&NY@4TZoWBa2esp
z8#o7*SkT!VOSDd%1yp~+f4S{Q@kr`C4^0Zs=kC^__v^f{i=CUblYw{@yW|JipY6&@leAnBvpOg`
z`dJvHl|iNlp;3^r@$9_QRIEf#N!>GbHxKE&8^S4$pn+E#oR@
z1Son7E@v+lzQ-J^O^^Iyfwg09k}g4BANiPUuT~>QwVU%mC*>c#TavERI&_*{Gvy6h
z=<1ptk9K<-p8o$6nrSx2bzRpvstp0PrHmTs%1V8l?M}yJFDaQBBfYS>UCWU}F%18m@?9Gl
zx~A`H8#ap@hOe~h@z8x+fS0cJ+w{NLs28B-yc7z}w;`!e9IK-^MMV0YjmSd$o$*=7
zAp{h?LEPX23Y@v%asd-gl{zj3wz(wD+cA9w8LlFsg-KMFk9mGsQc?F=YD7Dv0x>^$VD
zb{eViXgi!a1|Dp?+C6QO08r4i=?G>^L~&K+&ArYxNB>AiCXQ@o9{*?z)CMc-wHSTH+KEsayVCqVO^WQ
zsJ6JJ9IoFIYKOL4%;KQTv-l*r(cdZ76z$!l>(5IHX5JeizoE7WMzM=f&L@Lw_u_6h
z(~IS)S%B_#jb13TG&ZC!1hIP7nKepk&o-NWIS}H<`sC0^r9|Y(wq2A}?xOlP8>#$AjJX6Y`}3+_=AshfTbz
zmb4nvXHt#>`x=+{c={p++Uui_ihTHxN#j>{*+%);9Jokd`YZtE4Ec`zF-5{6(nR2q
z=HE92QPR?nGyve|YG(q($Oy^g4)hJN-JR8BBnl&)#N*xH-tvuWOv=aR&U8QToo9l)
z{jFlk!t2YQ;4OK%89ZvH`PlS>JpH92mb>FGdh&2VabNQo+Vau@q2#np;bd;k9m-5w
zLyTf_W4^uC@5TE%DAR6|(kQfhRrl@VSM9i+I)oxLxl{Rjjl_-8A-+il1aNM=<}m;6TgGm
ztm5T|SvXJfD%B_gRifd!6YGW=Jjb}?K&t`C*L6rto^N>EP5K6sy3U+gJbe|YBpc3$
z@V^SnJ2ISn8m9d-62rbdTI1?GJa)An{ln_08e7JO~Q!yUACW4aBBuT${!@i
zh_ZQnJ?p{l8xk^WuJ%!E+nS@_($U5*--6~8am||p#Yq}`)^j+;U3zeM?kqiNrmq)|
z&7!e61NR`ztV3p5)IaU$ze}rm%7(ZD7xV)~^QaZ+Ey;gM=v8^rvh+Hq=`nfGlJvC1
zKMC4U+Q_J-$-qH4vhZ7|uT$4R=%jSr9-gx6y}IOSE^i!cME1D)?caFn))g??F@Fm(
zVk8F{vR2HvC>5}y_~)aIu#s$F-Z(5pSEPO;!18m2Ios)snV(`(L(e&D$rxmC
z$)4iNFl=y99u;N?HV~wX@QY6uqka+}2J&d83)sVj=lF43ei(0lyg;6O`Y$<%hnwXM
z1#ts#nbq!JpGJz=gtF$(
zwqyJlvx**>zkhxR;Sq%ygP2+5Lii*G-mn}uAfK^G@!Spa<2Pim<22>zwY`B2qOBca
zI<6(BlAD>%4-dm8^f0Cl9Z~1p45B=$U|d+?)HhKaWg8b9!8*Fj!e7cayQ{N_AGus<
z$cE=lcveu>M;avpnn>i*f}fg+{~AQ-Pf5-Jfu%Pf4-u7j@xZ`!NEJLdFww`S0?w`0B^d`^`gta#sS))FiY#vJ-q
zTq6Bn8(NL`Cq+H5X6rwjC*B}PCKX)^=YuFn?NSiLz{0W+PNEBqJ@O}~?~wIxEL_Bx
zvCTa;j!DoJ1j?6ml$BlT=uOD{LlI6Uwh~$icvo1g^kvX;((5z6#ORU&YJfT~g>s(4
zre}!($ehoW>BA@_^?^?RBq0}muV1utTIn72Yej+L?i3OI<{rYClWm7q6Aa|QL$kb0
z?yMqn#pq7Vv6X9bL*>%G{f@cT<_0`#g|M$5GF?@mRc(AfMx(yg#(ER_H!A_cr+Yos
zP2MoymvPrgv8-TB&XZiSWw74O^nGq2q!r#L7s`3q*ATjwDo`?o%Dq5Dr&hF!-kcYG
z&5b15VAFCm_KF~bNh~9i2!leqnZD=e0_*2)#AF|L(@!RQY~b|L
zd@(FODea0^gGtiZr`$|@I}RzH63cOflZpD3Y}-S0ThFa$JTR{yEbD0Df@Yhon^Kx>^wt*Z23BW{!&?i`ne?N~I4Tf1#s&5gY>idPRl;9X^Ob5lv_owxGGBvT3wDpTV5KpPnB-Zm+7Fvi+dc@lY`!63
zpP2w|;b*L2hP`fF`jd5WytUr(!fL&-)xW6pJ-POpa{eOCSK>nQan{O!PkFymru$d|
z-ECCA^`7WqO>z_do7Jx&3SC`(Imqa?92NZqrT}4GyoK?-O4DIFEj7J6+rQC?m7OGHDt%AmDcsWp-3{842|?k(FWB583pMo-10g`tys(fq3@Icb4rMPVn=
z3~TQAnu(RUCekQ+pB!~hd;c^}o5@roX&5am(Rw2d1tA53b$5o{^|}{d_Y5#qgN!o(
zT9{4ChZCx=Zjl00)x~bZqw3VnTvs3gud&Cx)H*n%<}m`*!c*;lrW$88t|P-NgYvjf
z+O%tPxQ4VdJ(3oLCP~wZRpBG5Qbvk$fmFxo43K2HQU}L%9lEM$NNnuKqbe4DMJt&t
zFQh)n;PmI(CuhkNA5%Xw^Dpn4(d~e5x`|9r%2j>NS2p8c!bxSxSMQVw+zlNn+rHAo
z=e|Rw%2h|UNe#POh=YSz&hH$1>-=Z!{n2d?v}{)Kfy~n2;+xq#XCD)$Mu&Pun93
zVcA3wroIBrn|qMGE#;wf`qGN)%+2$6@q2jY
zOYP+Z5v5u>a@IgsDJ?m&3d<=cQmLlyu2{-EYMMz-Bfb>DoGc*oO;kI8Wd#F?%wt8A
zDUB?&FUeX;d`YD0@QAy3s%i_b0TLIy9_dQV5FQi&wMQdQ67eg~VYFQAxKQ
z;-&;?7gaHr=l@Q1Ur}7(Uj=(qtc$N=+TA}}hS|DB^8`2P>M<|k0xuz(lp+ZW{cf~)-N1>3|
z#}gvBnF^#a_#~bNRTrEua*00=s>BqWQa|LwWHOj&IU7`Q4PvqW&<~g?5aVKBz#aF0
z%4!t?B))i^j{+gJBRJDJrqLUw!F=)t*5$6QID?t8ETG`=j}Z-1sBB+3sQk3v8|sI<
zWa~Q613K9cg>ssTaFR-JoVrs~`vNCA??cS`eWohAJ@L80F5fvG*Z3Y32exq;CCtOz
z3A%od{2lK<C!i{9po32ZP=8Nmn*89+-x(u0B&=|D^#X@N(EG{B@_
zsewWTs|xU{t18e^QU;t1DFQ^UD$jRbWcf5EC28K0`#H(2dnq30R0;0UBF0U~_c+d#
zBFg#BoWCw&z4n;``AAvdzLX1?Ej-f%-fk>o29D}ew;&ren
zP+ddZzS1+R=_1=5IX_KP
z*MM{dq`MR%UWLrbdU3*OBHu}nt2m0IAJ*%gt_o2|0Yc>?`Zu0XZ@A?|#Ot8#wt*~L
z67-ab%-Z7l*!h*QXt^~y5?tX72$L8x|{E;hyb7BkqSST+fg8dWHUgS
zV1BI77T;2#KF218YA_8SB8?a(_IU-dSva4~jq3!Lns&wTj9ugz85{VY*D
z%CB~Tft-CuYnEFpLO%K_h!q|KO@-Xyf12vhcTf5
z@G%NbiZ=B?_$`>txTw=dr4`Prp1}{i+z+_iD|%MBljm2rxu)43y%9W3IRP^+GjyXR
zPf_6`2}+Z1k?heqpAwIEW12R9bV1)9Is=+DwEY8*Fgd+VRL^{WM2*S)I(Ozs^OpdohdbX?|L
zY85RyxY>dzOl7Qi*