WebMidiApi


WebMidiApiとは

W3Cで策定しているブラウザでMidiを操作できるプロトコルです。
以前はChromeのみの対応でしたがEDGE、FireFoxも対応となりました。またPC/MAC/Androidのブラウザで動きます。
おそらくアップル側の意向と思われますがIOS(iphone)はまだ対応しておりません。
IOSでWebMidiApiに対応するには Web MIDI Browser で試してみてください。
各種ブラウザ対応の確認はこちらの Can I Useのサイトよりご確認ください。

wmican

おもにIEですが他のブラウザでも動くようにするにはWebMIDIAPIShimより「WebMIDIAPI.min.js」を読込ます,そしてJazzPlugInをインストールします。
システムエクスクルーシブ(sysex)を扱う場合、SSLのサーバーが必要になります。
下記コードではsysex:true部分がSysExのON設定です。SysExを使わない場合はfalseで非SSLサーバーで問題ありません。ちなみにローカルならどちらも使えます。



シンプルなWebMidiApiの実装

JavaScriptでシンプルなWebMidiApiを作ります。WebMidiApiの実験室様を参考にさせていただきました。機能としてはポートon/off表示、INPUT_MIDIデータ表示、textのMIDI_OUTPUT出力です


basicWMI

現状でWebMidiApiを作るときはChromeとIEだけに特化すればよいのですが、2つのブラウザ間だけでも少々問題があり、他、気になったところは以下になります。

1,IEで'\n'で改行すると無効になりましたので'br'にしました。

2.Web Midi Apiのport.idでinput,outputを表示させていたのですがIEで文字化けのような表示となりましたのでport.idの使用をやめました。

3.対応しないブラウザで開いたときchromeで開くようにアラートを出します。

4.ネットからの読込 <script src='http://cwilso.github.com/WebMIDIAPIShim/build/WebMIDIAPI.min.js'></script>

にすると反応しませんでした。ローカルにおいて読み込むと反応しました。

5.jazzPluginの作者様はjazz.jsに移行しているようで、ブラウザの独自搭載を待つよりないのかなというところです。

以下JavaScript付きhtmコードになります。

WebMidiApiのメインコードは、わずかなコードで動きます。

<!DOCTYPE html>
<html lang="en">
<head>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-127064675-1"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());

  gtag('config', 'UA-127064675-1');
</script>


<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width">
<title>Basic Web Midi Api | BooleanEffect</title>
<link rel="canonical" href="https://booleaneffect.info/wmi.htm">
<meta name="Description" content="Basic WebMidiApi Sample OnLine PortON/OFF,Input,Output:: Only works in Chrome browser " />
<meta name="Keywords" content="Port,On,Off,Midi,midi,web midi api,input,output,WebMIDIAPI,Boolean.Effect" />


<!--Spcial Thanks cwilso/WebMIDIAPIShim -->
<!--WebMIDIAPIShimの読み込み<script src='http://cwilso.github.com/WebMIDIAPIShim/build/WebMIDIAPI.min.js'></script>エラー -->
<script src="js/WebMIDIAPI.min.js"></script>

<script>
/*WebMidiAPI 部分*/
var inputs=[], outputs=[], Pins=[], pinStatus=[], m=null;
var input, output;

/*SysEx許可 SSL接続が必要 orローカルでも可*/
window.onload=function(){
	if(navigator.requestMIDIAccess)	navigator.requestMIDIAccess({sysex:true}).then(onMIDIsuccess, onMIDIfailure);
	else console.log("No MIDI support present in your browser.");
}
function $(id){ return document.getElementById(id); }
function onMIDIfailure(){
console.error('No access to your midi devices.');
alert('This Program only works in Chrome');
}
function onMIDIsuccess(midi){
	m=midi;
	var iIterator = midi.inputs.values();
	for(var o=iIterator.next(); !o.done; o=iIterator.next()) inputs.push(o.value);
	for(var i=0; i<inputs.length; i++) $("select1").appendChild(new Option(inputs[i].name),i+1);/*input*/
	if(inputs.length!=0)document.getElementById('select1').selectedIndex=1;
	if(inputs.length!=0)inputDeviceSelect();
	var oIterator = midi.outputs.values();
	for(var o=oIterator.next(); !o.done; o=oIterator.next()) outputs.push(o.value);
	for(var i=0; i<outputs.length; i++) $("select2").appendChild(new Option(outputs[i].name),i+1);/*output*/
	if(outputs.length!=0)document.getElementById('select2').selectedIndex=1;
	if(outputs.length!=0)outputDeviceSelect();
}
/*MIDIポート確認*/
function inputDeviceSelect(){
	inputs.forEach(function(port){
		port.close();
	})
	var port=inputs[$("select1").selectedIndex-1];
	if(port){
		port.onmidimessage=onMIDIMessage;
		port.open();
		input=inputs[$("select1").selectedIndex-1];
	}
	readinput();
}
/*ポートの表示*/
function readinput(){
	document.getElementById("log").innerHTML =""
	/*時間を入れないと直前の値となる*/
	function hogeinput(){
		inputs.forEach(function(port){
			console.log(port.id,port.name,port.state, port.connection );
			document.getElementById("log").innerHTML =  document.getElementById("log").innerHTML + "input: " + port.name +": " + port.connection + "<br>";
		});
		clearTimeout(setinput); 
	}
	var setinput = setTimeout(hogeinput, 200);
}

function outputDeviceSelect(){
	outputs.forEach(function(port){
		port.close();
	})
	var port=outputs[$("select2").selectedIndex-1];
	if(port) port.open();
	output=outputs[$("select2").selectedIndex-1];
	readoutput();
}


function readoutput(){
	/*時間を入れないと直前の値となる*/
		function hogeout(){
		outputs.forEach(function(port){
			console.log(port.id,port.name,port.state, port.connection );
			document.getElementById("log").innerHTML = document.getElementById("log").innerHTML + "output: " + port.name +": " + port.connection +"<br>"  ;
		});
		clearTimeout(setout); 
	}
	var setout = setTimeout(hogeout, 200);
}

function onMIDIMessage( event ) {
	var str=null;
	var i,k;
	/*IEで\n改行できないため<br>にした*/
	/*アクティブセンシングよけ*/
	if( event.data[0] == 0xFE ) return;
	if( event.data.length>1) {
		document.getElementById("log").innerHTML += " 0x" +( "00" + event.data[0].toString(16) + ":" ).slice( -3 );

		for(i=1; i<event.data.length; i++){
			document.getElementById("log").innerHTML +=" 0x" + ( "00" + event.data[i].toString(16) + ":" ).slice( -3 );
	
			if(i%7==0){
				document.getElementById("log").innerHTML +="<br>";
			}
		}
	}
	str ="&nbsp;&nbsp;&nbsp;&nbsp;__Data_Length=" +event.data.length+ ":"+ "<br>"; 
	document.getElementById("log").innerHTML += str;

	var obj = document.getElementById("log");
	obj.scrollTop = obj.scrollHeight;
}
/*SendMIDI*/
function sendmidi(){
	var midievent=document.getElementById("out").innerHTML;
	var len=midievent.length;
	var str;
	if(len==0) return;
	var sysex=Array(1000);
	var j=0;
	for(var i=0; i<len; i++){
		str="0x";
		str+=midievent.substr(i,2);
		sysex[j]=parseInt(str);
		i+=2;
		j++;
	}
	sysex.length=j;
	output.send(sysex);
}
</script>

<style>
html,body{
 height: 100%;
 margin:15px;
}
#log{
  border: 1px solid #999;
  overflow: auto;
  width:100%;
  max-width: 430px;
  height: 40%;
}
#out{
  border: 1px solid #999;
  width:100%;
  max-width: 430px;
  height: 20%;
  overflow:auto;

}
</style>
</head>

<body>
<h2>Basic_Web_Midi_Api</h2>
<p style="color:red;"> Only works in Chrome Browser</p>

<div id ="inp" style="inline;">
	<p style="display:inline; margin-right:13px;">INPUT :</p>
	<label for="select1" class="select-1">
		<select class="ids" id="select1" onChange="inputDeviceSelect(this);">
			<option value="0">No Device
		</select>
	</label>
</div>

<p style="display:inline">OUTPUT:</p>
	<label for="select2" class="select-1">
		<select class="ids" id="select2" onChange="outputDeviceSelect(this);">
			<option value="0">No Device
		</select>
	</label>
<br><br>

<div id="log">Input</div>
<button onclick=readinput(),readoutput()>OpenClose check</button>
<br><br>
<div id ="out" contenteditable="true">C0 00</div>
<button onclick=sendmidi()>SendMidi</button>
<br><br>

<hr>
<a href="wmiinfo.htm" class="menu--link" title="WebMidiApiInfo">WebMidiApiInfo</a>
<div align=right>BooleanEffect</div>
</body>
</html>

参考リンク Spcial thanks

WebMidiApiの実験室
Web Midi APIのテスト

メインのコードは上記を参考にしました。

WebMIDIAPIShim
Jazz-Soft.net
logo