プログラミング

HTML5を使ってみた

2012年10月5日

去年がHTML5元年だそうで、HTML5はまだ始まったばかりの技術なのだけれど、モバイル環境でも使えるアプリケーションを開発できるという意味ではおもしろい。

最近、MZ-80K(SHARPが30年少し前に発表したパソコン)のレプリカを作ったり、それ用のBASICを開発したりで、これに少しはまりこんでいる。

そこで、出来て1年ほどの技術を用いて30年以上前のコンピューターを再現するのもおもしろかろうと思い、HTML5の勉強を兼ねてMZ-80Kのエミュレーターを作ってみた。「KM-Z80 web」と名付けている。

2012-10-05-km-basic.png

現物及び使用方法の説明、ソースコードのダウンロードなどはこちら

使い方などは別のページに譲るとして、ここではHTML5の技術に関することなどを書いてみたい。

HTML5のうち、利用した技術は次の通り。
  • Canvas
  • FileReader
  • Web Audio API もしくは Audio Data API
Canvasはたぶん、HTML5の基本ともいえる技術のようだ。ここでは、基本中の基本である2次元データーとして扱っている。KM-Z80 webでのソースコードでは、以下の部分がそれに相当する。
display.init=function(){
	// Set the contexts.
	this.context=document.getElementById("display").getContext("2d");
	this.ledContext=document.getElementById("led").getContext("2d");
	// Load the font data. See also fonts.onload event.
	this.fonts.src="./fonts.png?"+ new Date().getTime();
};
display.fonts.onload=function(){
	display.onload();
}
// display.onload will be called after sucessfull loading of font PNG image.
display.onload=function(){
	// Show the PNG image
	this.context.drawImage(display.fonts,0,0);
	// Construction of images for font
	for (h8=0;h8<16;h8++) {
		for (l8=0;l8<16;l8++) {
			this.font[h8*16+l8]=this.context.getImageData(l8*8,h8*8,8,8);
		}
	}
	// Construction of images for LED
	this.ledImage[1]=display.context.getImageData(128,0,16,16);
	this.ledImage[0]=display.context.getImageData(128,16,16,16);
	// Clear display
	var i;
	for (i=0;i<1000;i++) {
		this.write(i,0);
	}
	// Construct blank canvas
	var blank=document.getElementById("blank");
	blank.getContext("2d").putImageData(this.context.getImageData(0,0,320,200),0,0);
	// Show LED (green)
	this.led(1);
	// All done let's start Z80
	start();
};
display.write=function(addr,data){
	var posy=0;
	var posx=addr & 0x3ff;
	if (1000<=posx) return;
	while(40<=posx) {
		posy++;
		posx-=40;
	}
	this.context.putImageData(this.font[data],posx*8,posy*8);
};
display.led=function(green){
	this.ledContext.putImageData(this.ledImage[green?1:0],0,0);
}
要するに、次のような画像をキャンバス上に貼り付けて、その一部を256回、フォントデーターとして取り込んで保存(getImageData)している。表示するときはputImageDataを用いれば、高速に処理がなされる。
2012-10-05-fonts.png

FileReaderでは、動的HTMLページを用いなくても、クライアントサイドのファイルをデーターとしてJavaScriptの中に取り込むことが出来るのが面白い。この特性を利用して、KM-Z80 webは、静的なHTMLファイルとして構築することが出来た。セキュリティーに関してはブラウザ側に丸投げすることが出来るので、応用範囲は広いだろうと思う。ここでは、以下のように使っている。
file.loaded=function(obj){
	// This will be called when a file is uploaded.
	// If FileReader API is not supported, following code will fail.
	var fr = new FileReader();
	fr.onload = function () {
		var data=new Uint8Array(fr.result);
		file.update(data);
	};
	fr.readAsArrayBuffer(obj.files[0]);
	obj.style.display='none';
};
file.update=function(data){
	// This will be called when a file is sucessfully loaded by FileReader API.
	var header=new Array();
	var body=new Array();
	var i;
	// First 128 bytes contain header info.
	for (i=0;i<128;i++) {
		header[i]=data[i];
	}
ここでは、バイナリファイルを扱うので「readAsArrayBuffer」を用いた少し複雑なコードになっているが、テキストでよいのであれば、「readAsText」を用いてもう少し簡単に記述できるようだ。あと、これはHTML5ではないのだろうけれど、以下のようなリンクを作成することで、バイナリオブジェクトをローカルに保存することを可能にしている。
<a href="data:application/octet-stream,%00%01%02">download</a>

最後は音源関連。これは残念ながら、対応しているブラウザが限られており、ブラウザごとにAPIが異なる。今のところ、FireFoxとChromeで動作確認をしているが、それぞれ、Audio Data API と Web Audio API という、2つの異なるAPIを使うことになった。詳しくは、ソースコードのaudio.jsを参照されたい。MZ-80Kの場合は矩形波で良いので、そこの部分は楽にプログラミングできた。

ところで、このKM-Z80 webには、これ用にスクラッチから開発した、JavaScriptによるZ80エミュレーターが搭載されている。以下、ソースコード(Z80.js)から。
/*
	Public methods:
	z80.reset();
	z80.setSpeed(clk);
	z80.getMicroSec();
	z80.exec(msec);
	z80.interrupt();
	z80.nmr();
	
	Required outside methods:
	Methods written in z80functions.js.
	memory.read(addr);
	memory.write(addr,data);
	io.read(addrL,addrH);
	io.write(addrL,addrH,data);
	z80.events(); // optional
*/

使い方としてはわかりやすくできていると思うので、興味のある方はどうぞ。LGPLです。

コメント

コメントはありません

コメント送信