日記(1011)

<前 次>

シフト移動

女郎蜘蛛ですよ女郎蜘蛛!でっかいの!
一匹は大きい女郎蜘蛛。もう一匹は今まで見た中でも1・2を争うぐらいのもっとでかいの。一匹はそれに匹敵するぐらい大きいの。
蜘蛛は元々好きなんだけどこれまで立派なのは数年ぶりだったので、それも小学校以来だったので手でつかむ気にはなれませんでしたがそこらの棒切れでちょっといたずらしていました。
蜘蛛は棒切れをガリガリ噛んでて、その感触が棒を通して指に伝わってくるのが面白かったですわ。

ふにゃさんのステージエディタにシフト移動機能を追加しました。
その他ボタンを押すとポップアップメニューが出てきます。
マップウィンドウに直接メニューを入れるとメインウィンドウのメニューが消えてしまうのでその対策でメニュー専用のフォームを作っています。
メニュー専用フォームはマップウィンドウごとに割り当てられていて、相互に連携しています。
シフト移動機能そのものは再帰を使って1ずつ移動しているため効率はよくないです。
しかも1ずつ動かす処理も馬鹿正直にマップチップ一つ一つを移動しているため効率は悪いです。
気が向けば効率のよいアルゴリズムで書き直すかもしれません。

縦横スクロール

LineConstructor、選択した場所が変わったときスクロールが付いてきていなくて不便だったので追随するようにしてみました。
今のところマウスのボタンを押したまま画面外までカーソルを持っていってスクロールさせる方法が中途半端にしかできていないのでSetCapture/ReleaseCapture系のAPIを用いて画面外でも正しく位置を検知できるようにするのが当面の課題、って、すぐできますが。
ByteEditでもそのうち同じ機能をつけるつもりです。
それと、必要なのは閉じるときの保存確認ですね。
ついつい保存を忘れて閉じちゃいます。
そうそう。横スクロールもつけないと。

ミディビ受信プログラムの正規表現の件、バッチリOKみたいです。
\x00のような記法でバイナリデータ全部問題なく正規表現に使えそうです。
テキストを抜き出すのも比較的簡単にできそうですよ。

MIDIチェック

ふにゃさん、ステージ内に埋め込まれた画像を読み込む処理の改良に成功しました。
やはりこの前考えたとおり、GlobalAllocで確保したメモリアドレスと違う位置を渡していたのが原因だったようです。
mapを使って識別子とデータを関連付け、データクリア時にはそれぞれを別々にメモリ解放します。
要するに今回はこの関連付けるデータを一つ一つGlobalAllocで確保したというわけです。
また、確認はしていませんしその必要もないと思うのですが、以前のものだとデータの長さ(というよりデータの要素数)にほぼ比例した検索時間が必要でしたが、新しいほうだとその対数オーダーでの増加になるので大きなステージでは読み込みが速くなるはずなのです。
もしかしたらメモリの解放忘れがあるかも。でも多分無いかと。うん。自分を信じよう。スペル間違い以外に不具合は無かったんだし。

ミディビのMIDI受信プログラムを少し改良しました。
データを簡単に検査することでMIDIかどうかを判別し、MIDIデータでなければ保存しないのです。
MIDIには必ず存在するデータというものがあるのです。
それが存在するかどうかさえ調べればおかしなデータが送られてきたときにエラーを出すことができるというものです。
ミディビは一応完成したら配布するつもりなので悪意のあるデータを排除するというのも必要になってくるわけです。
そういえばPerlの正規表現ってバイナリデータに対してはどう動くんだろう?
PHPについてはどうやら一行のデータを前提にしているらしいのですが。
ん?でも掲示板とかで複数行のデータを渡したときもちゃんと動いてる?どーなってんだろー。
しかしもしバイナリデータでも正規表現が使えるなら強いですよ。
なにせ正規表現だけで曲名も作者もコメントも抜き出せるのです。
JavaのおかげでMIDIのバイナリデータを直接扱うことはありませんでしたがやはりいずれにせよMIDIファイルの知識は必要だったようです。
それでも一応MIDIメッセージの段階まではMIDIに踏み込むことができたのでできる自信はあります。
正規表現の挙動しだいですが…。

そしてCGIへ...

ふにゃさんの設定プログラムを作り始めました。
今本体に実装されている設定項目はBGMだけなのでそちら優先で。
設定項目が増えても更に増やす手間が必要以上に増えないように、作業時間がO(n^2)じゃなくO(n)になるように、追加された設定の画面への反映を半自動化するようにしてみました。
ただ、少しばかり本体と設定プログラムでデータの読み書きの勝手が違うのでそこらへんまた手間が増えそうです。

ミディビ、ついに保存できるようになりました。
実際は昨日日記を書いた直後にできたのですが、プログラミングのページの更新と微調整とかで時間をとられました。
今後の方針としてはそろそろいい加減ビュークラスも本番用にして、あと、保存する前に聞けるようにしたりというのも、複数のトラックを編集できるようにしたりとか、音色を変えたり、そこらあたりを最優先事項として作っていくことにしています。

データの受け渡し。

ミディビ作ってました。
もうほんとに色々あって。

OutputStream探し。
MIDIデータをbyte配列としてメモリ上に一時置いておかなければならないんですが、可変長byte配列を扱うのに便利なクラスが無かったんです。
まずLinkedList。
これはオブジェクトなら何でも要素にできるし項目の追加が高速。
そしてデータは一気に配列としてもらうことができる!!
というものだったのですが、LinkedListで扱えるのはオブジェクトだけなんですよね。
byteはオブジェクトじゃないので扱えないんです。
そりゃByteオブジェクトにすれば入れられなくは無いけどそうすれば高速化が無意味ということで。
第二候補がByteBuffer。
名前の通りbyte型のバッファを扱うクラスで、こちらは正真正銘プリミティブ型のbyteなのです。
ところがどっこい抽象クラス。
何か実装しなきゃならないそうです。
実装が嫌だから既にあるクラスから探しているというのに!!
仕方なく自作。
経験上MIDIは数十キロバイト程度の大きさになるのでバッファを10kBごとに増やす方法で不必要にメモリの使用量を増やさず高速化を図っていました。
OutpurStreamのサブクラスとして作っていたんですよ。
そこでどんでん返し。
ByteArrayOutputStreamという私のやろうとしていたことまるっきりそのままの名前のクラスを発見したんですよ。
その内容を見てみてビックリ。
私が自作していたOutputStreamと同じことができて、さらに私が思いもしなかったさらに便利なメソッドまであるじゃありませんか!
速度は自作のほうが出せそうな気がしますけど、速度が何だってんです!
ここまで理想どおりのものをあつらえてもらいながら使わないというのはJavaに対して失礼というものです。

CGIに渡すデータをどうするか。
ここはお絵描き掲示板をお手本に。
というわけでしぃペインターの出力をそのままファイルに書き出すCGI作成。
binmodeを忘れたりして出力がおかしなことになったりしてました。
識別子・サイズ・実データが順番に並んでいるようです。
MIDIにはテキストとしていろんな情報が入れられるのでもろもろの情報はMIDIに埋め込んでしまえばミディビが受け取るデータはMIDIデータだけでよくなります。
そうすりゃオエビのように面倒な処理は抜きにしてデータ受け取りCGIは受け取ったデータをそっくりそのままファイルに出力することを考えればよいのです。

で、関係ないMIDI。
出だしの部分だけ。
後半で発展させてゆきます。

1128783251.mid

斜めマップ

爆ボンのマップを作成するための素材を作っていました。
EDGEでテクスチャを使って塗りつぶす方法を見つけて、というより、きっとあるはずだと信じて探したら本当にあって、その機能のおかげでずいぶんと作成速度が上がりました。
いろいろとマップチップ作成に便利な部品を作ったということも作成速度向上の一因には違いないでしょうが。
まだまだ調整が必要だけどここまでできてます。

1128696113.png

GlobalAllocの途中にて

ふにゃさんステージデータ改訂版。
ステージファイルに埋め込まれたGIF・JPEG画像は読み込めませんでした。
それで必死に原因を探して、原因がOleLoadPictureでエラー-2146827807が発生していることだということを突き止めました。
しかし、そのエラー、ヘルプにも記載されていなければ、どこのヘッダファイルを見てもそのエラーを返すコードもなし。
そこで、エラー番号で検索を掛けてみたら、唯一http://72.14.207.104/search?q=cache:geyhWb4AH8QJ:www.eggheadcafe.com/ng/microsoft.public.vc.atl/post22719515.asp+2146827807&hl=ja&inlang=jaが見つかりました。
ここのフォーラムのやり取りを要約すると、
「OleLoadPictureでエラー-2146827807が発生しているがこの意味が分からない」
「GlobalAllocを使いなされ」
ということだったのですが、実は今回、既にメモリ確保にはGlobalAllocを使っていたんですよね。
それで完全にわけが分からなくなってやけくそになってテンポラリファイルを使って読み込んで、普通のファイルならバッチリ問題なく読めるので一応解決はしました。
しかし、今考えてみると、ステージファイルに埋め込まれた画像というのは、GlobalAllocで確保されたメモリの途中にあるんですよね。必ず。
そして、グローバルメモリオブジェクトを扱うAPIを見てみると、どれもこれもGlobalAllocやGlobalReAllocで得たハンドルを使っているんですよね。
グローバルメモリオブジェクトをバイト配列とみなした途中の変数のアドレスじゃないんですよ。
まあ、分かりやすく言えば、
int *p = malloc(256);
free(&p[1]);
みたいなことをしていたというわけですね。正しく動くわけがありません。
だったら画像を読むときはテンポラリファイルの代わりに、改めて画像データだけを入れるメモリ領域をGlobalAllocで確保してそこにステージに埋め込まれたデータをコピーして使えばよさそうな気がしますがまだ実行していません。

ミディビの開発のため色々調べものをしていました。
CGIに渡すデータは、ヘッダ→空行→データ、という形式。CGIが返すデータとよく似た形式です。
具体的には、Content-Type: multipart/form-data;~だとかContent-Length:~をヘッダに記述して、データ部にMIDIのバイナリデータを書いてやればCGIにMIDIのデータが送られるわけです。
しかしOutputStreamに書き込まれる前にデータサイズが分からないためSocketでサーバに接続して得られたOutputStreamに直接書き込むのは危険そうです。
一応テスト用のOutputStream派生クラスでMidiSystem.writeはOutputStream.write(byte[] b, int off, int len)しか呼ばないことが分かっているので、MIDIデータを一時保存するためのOutputStreamを用意してそこから改めてサーバに接続して得られたOutputStreamに書き込むのがよさそうです。
これを日曜日あたりにプログラムとして書くつもり。

爆ボンやってました。
今度はどきどきモードでドラゴとリバイアを倒しました。
攻略ページのほうの更新はありません。
やっぱりどきどきモードだと強くなっています。

<前 次>