HTML5を使ってみた
2012年10月5日
去年がHTML5元年だそうで、HTML5はまだ始まったばかりの技術なのだけれど、モバイル環境でも使えるアプリケーションを開発できるという意味ではおもしろい。
最近、MZ-80K(SHARPが30年少し前に発表したパソコン)のレプリカを作ったり、それ用のBASICを開発したりで、これに少しはまりこんでいる。
そこで、出来て1年ほどの技術を用いて30年以上前のコンピューターを再現するのもおもしろかろうと思い、HTML5の勉強を兼ねてMZ-80Kのエミュレーターを作ってみた。「KM-Z80 web」と名付けている。
現物及び使用方法の説明、ソースコードのダウンロードなどはこちら
使い方などは別のページに譲るとして、ここではHTML5の技術に関することなどを書いてみたい。
HTML5のうち、利用した技術は次の通り。

FileReaderでは、動的HTMLページを用いなくても、クライアントサイドのファイルをデーターとしてJavaScriptの中に取り込むことが出来るのが面白い。この特性を利用して、KM-Z80 webは、静的なHTMLファイルとして構築することが出来た。セキュリティーに関してはブラウザ側に丸投げすることが出来るので、応用範囲は広いだろうと思う。ここでは、以下のように使っている。
最後は音源関連。これは残念ながら、対応しているブラウザが限られており、ブラウザごとにAPIが異なる。今のところ、FireFoxとChromeで動作確認をしているが、それぞれ、Audio Data API と Web Audio API という、2つの異なるAPIを使うことになった。詳しくは、ソースコードのaudio.jsを参照されたい。MZ-80Kの場合は矩形波で良いので、そこの部分は楽にプログラミングできた。
ところで、このKM-Z80 webには、これ用にスクラッチから開発した、JavaScriptによるZ80エミュレーターが搭載されている。以下、ソースコード(Z80.js)から。
使い方としてはわかりやすくできていると思うので、興味のある方はどうぞ。LGPLです。
最近、MZ-80K(SHARPが30年少し前に発表したパソコン)のレプリカを作ったり、それ用のBASICを開発したりで、これに少しはまりこんでいる。
そこで、出来て1年ほどの技術を用いて30年以上前のコンピューターを再現するのもおもしろかろうと思い、HTML5の勉強を兼ねてMZ-80Kのエミュレーターを作ってみた。「KM-Z80 web」と名付けている。
現物及び使用方法の説明、ソースコードのダウンロードなどはこちら
使い方などは別のページに譲るとして、ここではHTML5の技術に関することなどを書いてみたい。
HTML5のうち、利用した技術は次の通り。
- Canvas
- FileReader
- Web Audio API もしくは Audio Data API
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を用いれば、高速に処理がなされる。
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です。
