This example requires Jazz-Plugin v.1.2 or later.
Send messages to any or all connected MIDI devices and monitor their output.
Use <Up> and <Down> arrow keys to repeat previously sent messages; Use <Ctrl-number> for fast switch between the output devices; <Ctrl-0> selects all devices.
This demo dynamically creates as many instances of Jazz-Plugin as it is required to connect all available MIDI devices.
MidiPool.js describes the MidiPool object that keeps track of these instances.
<!DOCTYPE html> <html> <head> <title>MIDI Console</title> <script src="MidiPool.js"></script> <style type="text/css"> #main { width:80em; border-collapse:collapse; font-family:Courier New, monospace; font-size:.75em; } #main, #main tr, #main td{ margin:0; padding:0; border:0; } #msg { width:100%; height:32em; margin:0; padding:.2em; background-color:#eee; border:solid 1px #888; white-space:pre; font-family:Courier New, monospace; overflow:auto; display:block; } #msg span { color:#00f; } #inp { width:100%; margin:0; padding:.2em; background-color:#eee; border:solid 1px #888; color:#00f; font-family:Courier New, monospace; } </style> </head> <body> <h1>MIDI Console</h1> <table id=main><tr><!sorry for using table> <td colspan=2><div id=msg></div></td> </tr><tr> <td id=cell><select id=sel></select></td> <td><input id=inp onpaste='setTimeout(check_input,0);' value="90 3c 7f 40 7f 43 7f"></td> </tr><tr> <td colspan=2 align=right><button onmousedown='send_msg();'>Send</button></td> </tr><tr> <td colspan=2> <input type=checkbox id=ign checked=true><label for=ign>Ignore clock messages</label> <button onmousedown='play_all();' onmouseup='stop_all();'>Test note</button> </td> </tr></table> <div> <script><!-- var Pool; var ins; var outs; var msgarea=document.getElementById('msg'); var sel=document.getElementById('sel'); var cell=document.getElementById('cell'); var inp=document.getElementById('inp'); var ign=document.getElementById('ign'); var namelen=13; var hist=[]; var in_hist=0; try{ Pool=new MidiPool; ins=Pool.MidiInList(); outs=Pool.MidiOutList(); for(var i in outs) if(namelen<outs[i].length) namelen=outs[i].length; for(var i in ins) if(namelen<ins[i].length) namelen=ins[i].length; var allouts=outs.length>1?["All MIDI Outs"].concat(outs):outs; for(var i in allouts) sel[i]=new Option(allouts[i],allouts[i],i==0,i==0); var tmp=document.createElement('span'); tmp.innerHTML=Array(namelen+6).join("=");; msgarea.appendChild(tmp); cell.style.width=tmp.offsetWidth+"px"; sel.style.width=tmp.offsetWidth+"px"; msgarea.removeChild(tmp); for(var i in outs) Pool.OpenMidiOut(outs[i]); for(var i in ins) Pool.OpenMidiIn(ins[i],function(name){return function(t,a){print_msg(name,a);};}(ins[i])); } catch(err){ alert(err);} namelen+=2; function play_all(){ var note=60; for(var i in outs){ midi_out(outs[i],[144,note,0x7f]); note+=5;} } function stop_all(){ var note=60; for(var i in outs){ midi_out(outs[i],[128,note,0]); note+=5;} } function midi_out(name,msg){ Pool.MidiOut(name,msg); print_msg(name,msg,true); } function format(msg){ var tmp=[]; for(var i in msg) tmp[i]=(msg[i]<16?"0":"")+msg[i].toString(16); return tmp.join(" "); } function print_msg(name,msg,out){ if(ign.checked && !out && (msg[0]==0xfe || msg[0]==0xf8)) return; var str=name+" "; if(out) str+="<<"; str+=Array(namelen-name.length).join("="); if(!out) str+=">>"; str+=" "+format(msg); if(out) str="<span>"+str+"</span>"; msgarea.innerHTML=msgarea.innerHTML+str+"<br>"; msgarea.scrollTop=msgarea.scrollHeight; } function send_msg(){ var msg=[]; var a=fix_input(inp.value).split(" "); for(var i in a){ var x=parseInt(a[i],16); if(!isNaN(x)) msg.push(x);} if(msg.length){ if(sel.selectedIndex) midi_out(outs[sel.selectedIndex-1],msg); else for(var i in outs) midi_out(outs[i],msg); var str=format(msg); for(var i=0;i<hist.length;i++){ if(hist[i]==str){ hist.splice(i,1); i--; } } hist.push(str); in_hist=hist.length; } inp.value=""; setTimeout(function(){inp.focus();},0); } function keydown(e){ var e=window.event || e; if(e.altKey || e.ctrlKey) return; if(e.keyCode==38){ // arrow up if(in_hist>0){ in_hist--; inp.value=hist[in_hist]; } } if(e.keyCode==40){ // arrow down if(in_hist<hist.length){ in_hist++; inp.value=in_hist==hist.length?"":hist[in_hist]; } } } function keypress(e){ var e=window.event || e; if(e.altKey) return; var a=e.which===undefined ? e.keyCode : e.which; if(!a) return; if(e.ctrlKey) { if(outs.length && a>=48 && a<58 && a-48<=outs.length) sel.selectedIndex=a-48; return; } if(a==13){ send_msg(); return;} if(a<32) return; if(" 0123456789abcdef".indexOf(String.fromCharCode(a).toLowerCase())==-1){ if(e.preventDefault) e.preventDefault(); else e.returnValue=false; return; } setTimeout(check_input,0); } function check_input(){ var str=fix_input(inp.value); if(str!=inp.value) inp.value=str; } function fix_input(s){ var str=""; var n=0; for(var i=0;i<s.length;i++){ if(" 0123456789abcdef".indexOf(s[i].toLowerCase())==-1) continue; if(s[i]==' ') n=0; else n++; if(n>2){ str+=' '; n=1;} str+=s[i]; } return str; } if(inp.addEventListener){ inp.addEventListener('keypress',keypress,false); inp.addEventListener('keydown',keydown,false);} else if(inp.attachEvent){ inp.attachEvent('onkeypress',keypress); inp.attachEvent('onkeydown',keydown);} --></script> </div> </body> </html>
// Jazz-Soft.net // This code is totally free to copy, modify and distribute. function MidiPool(){ var place; var arr=[]; var inputs={}; var outputs={}; if(arguments.length){ if(arguments[0].isJazz){ place=arguments[0].parentNode; arr[0]={plugin:arguments[0]}; } else{ try{ // if this is a good location to create plugins var tmp=create_plugin(arguments[0]); arr[0]={plugin:tmp}; place=arguments[0]; } catch(err){} } } if(place===undefined){ // otherwise create plugins at where the current script is var scripts=document.getElementsByTagName('script'); place=scripts[scripts.length-1].parentNode; } if(!arr.length) arr[0]={plugin:create_plugin(place)}; if(navigator.appName=='Microsoft Internet Explorer'){ document.onfocusin=onFocusIE; document.onfocusout=onBlurIE;} else{ window.onfocus=connectMidi; window.onblur=disconnectMidi;} function create_plugin(where){ var obj=document.createElement('object'); obj.classid="CLSID:1ACE1618-1C7D-4561-AEE1-34842AA85E90"; if(!obj.isJazz) obj.type="audio/x-jazz"; obj.style.visibility='hidden'; obj.style.width='0px'; obj.style.height='0px'; where.appendChild(obj); if(obj.isJazz) return obj; where.removeChild(obj); throw "Cannot create Jazz-Plugin"; } function connectMidi(){ try{ for(i=0;i<arr.length;i++){ if(arr[i].in){ if(arr[i].func) arr[i].plugin.MidiInOpen(arr[i].in,arr[i].func); else arr[i].plugin.MidiInOpen(arr[i].in); } if(i && arr[i].out) arr[i].plugin.MidiOutOpen(arr[i].out); } } catch(err){res.innerHTML=res.innerHTML+' ERR: '+err;} } function disconnectMidi(){ try{ for(i=0;i<arr.length;i++){ if(arr[i].in) arr[i].plugin.MidiInClose(); if(i && arr[i].out) arr[i].plugin.MidiOutClose(); // don't close the default out } } catch(err){} } function onFocusIE(){ active_element=document.activeElement; connectMidi(); } var active_element; function onBlurIE(){ if(active_element!=document.activeElement){ active_element=document.activeElement; return;} disconnectMidi(); } this.MidiOutList=function(){ return arr[0].plugin.MidiOutList();} this.MidiInList=function(){ return arr[0].plugin.MidiInList();} this.MidiOut=function(name,msg){ if(outputs[name]) outputs[name].plugin.MidiOutLong(msg);} this.ClearMidiIn=function(name){ if(inputs[name]) inputs[name].plugin.ClearMidiIn();} this.QueryMidiIn=function(name){ if(inputs[name]) return inputs[name].plugin.QueryMidiIn();} this.OpenMidiOut=function(name){ if(outputs[name]) return; var i; for(i=0;i<arr.length;i++) if(!arr[i].out) break; if(i==arr.length){ arr[i]={plugin:create_plugin(place)}; } arr[i].out=name; arr[i].plugin.MidiOutOpen(name); outputs[name]=arr[i]; } this.OpenMidiIn=function(name,func){ if(!inputs[name]){ var i; for(i=0;i<arr.length;i++) if(!arr[i].in) break; if(i==arr.length){ arr[i]={plugin:create_plugin(place)}; } arr[i].in=name; inputs[name]=arr[i]; } if(func) inputs[name].plugin.MidiInOpen(name,func); else inputs[name].plugin.MidiInOpen(name); inputs[name].func=func; } }