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;
}
}