12.文字列テーブル

MIDIを作れるJavaアプレットを作っているのだ。
前回で一部の環境で音が鳴らない症状を改善したのだ。

曲の長さ

前回スクロールバーの移動範囲が狭く長い曲が作れなかったので曲の長さに合わせてスクロールバーを伸ばすようにしてみましょう。
TreeSet.last()で一番後ろの要素をもらってその開始時間をスクロールバーの最大値を決めてやればうまく行くような気がします。
MIDIAPTrackに長さを計算するメソッドを付けてみます。

public int getLength() {
	try {
		MIDIAPNote n2=(MIDIAPNote)notes.last();
		return n2.getStart();
	}catch (NoSuchElementException e) {
		return 0;
	}
}

TreeSet.last()は要素がない場合は例外を投げてくるのでそのときは長さを0とみなします。
しかし実際問題となるのは曲全体の長さなので各トラックの長さのうち最大値を曲全体の長さとしてその値をスクロールバーの最大値に設定することになります(実際のコードは省略)。

そして長さが0のMIDIは投稿させないように送信部分も変えておきましょう。
本当はメッセージボックスっぽいのを出したかったんですがわかんなかったので標準出力を使っています。

public void Send() {
	// 送信データ作成
	if (getLength()<=0) {
		System.out.println("データが短すぎるため送信しませんでした。");
		return;
	}
	(以下略)
}

外部設定ファイル

これからは色んな情報を表示していくために多くの文章を表示していくことになるのですが、そのようなデータをプログラム中に直接記述するとプログラムの見通しが悪くなったりデータの手直しが必要になったときなどに困りそうです。
なので、外部にデータを置いておいて、実行時にそれを読み込んで使うことにします。
アプレットを呼び出すときのパラメータとして指定するという手もありますが将来扱うデータはそんなもので間に合うような量のデータではないしほとんどの場合同じものを使うのでファイルとしてアプレットと一緒に提供できるようにすることにします。
ファイルの書式は…そうですね、1行につき1データ、タブ区切りで「データ名 データ内容」みたいにしましょう。
そういうわけでファイルを読み込みます。

try {
	FileInputStream fis = new FileInputStream("stringtable.txt");
	InputStreamReader isr = new InputStreamReader(fis,"SJIS");
	BufferedReader br = new BufferedReader(isr);
	String line;
	while ((line = br.readLine()) != null) {
		StringTokenizer st = new StringTokenizer(line, "\t\r\n");
		stringTable.put(st.nextToken(), st.nextToken());
	}
	br.close();
	isr.close();
}catch (Exception ex) {
	// ここではエラーが起こっても気にしない
	System.out.println(ex.getMessage());
}

stringTableだけどこにも説明されていませんがHashTableです。
FileInputStreamでファイルを読み込めるようにして、InputStreamReaderで文字コードを変換して、BufferedReaderで一行ごとに読み込んで、StringTokenizerでその行を解釈しているわけです。
例外が起こったときは何もせず続けるようにしていますが、例外でもstringTableにデータが入らないだけなので、使う段階でデータがあるかどうかチェックすればよいでしょう。
そんなわけでチェックしつつデータ名からデータ内容を返すメソッドを作ります。

public String getString(String key) {
	String value = (String)stringTable.get(key);
	return value!=null?value:key;
}

単純ですね。
ちなみに value?value:key というのはJavaではできません(null!=falseなので)。

しかし、ブラウザ上で実行してみると第7回のときと同じエラーが出るのです。
どうやら読み込むだけでもセキュリティの壁が立ちはだかるようです。
一応こちらについてはURIからファイルを読む、という方法が使えないこともなさそうだったのですが、最終的に関連するファイルはみんなJARの中に収められてしまい、それが読み込めるかどうかがまたわからないので、もう外部ファイルは諦めることにします。

変更するたびにコンパイルが必要になりますがここは素直にソース中に書いてしまいましょう。
ただ、できるだけデータ部分はデータ部分でまとめて、できればアルゴリズムやらなにやらとは無縁のところで設定することにしましょう。
ということで、stringTableを設定するためだけのメソッドを作ってしまいます。

public void setStringTable() {
	stringTable.put("Play", "演奏");
	(以下同様に)
}

要点

今回までのソース
さて、そろそろプログラム的に興味深い内容が少なくなってきました。
今後はミディビの更新はこことは離脱させて面白そうなことがあったらこっちを更新しましょうかね。

続く