Java Applet でマクロ音楽シーケンサーを作る(1) - Java の MIDI ライブラリ
- ウェブブラウザとMIDIについて
- Java の MIDI ライブラリ
- Java と JavaScript を連携する
Java Applet でマクロ音楽シーケンサーを作る その2
前回より、Webブラウザで動くマクロ音楽シーケンサーを作成しています。前回は、これを、Java Applet で製作することを決め、Java で MIDI を演奏する方法を調べてみました。今回は、マクロから演奏情報を書き込むシーケンサーの雛形を作ってみます。
マクロシーケンサーとは?
さて、前回は Java と MIDI について書いていたので、肝心の「何を作るのか?マクロシーケンサーとは何か?」について詳しく紹介していませんでした。
私が開発し公開しているソフトに『テキスト音楽「サクラ」』というWindowsアプリケーションがあります。これは、普通の音楽シーケンサーではなく、「ドレミードレミー ソミレドレミレー」のように文字列で楽譜情報を書くと、その文字列を解析して、音楽を演奏するというシーケンサーです。ワープロ感覚で作曲できるようになっています。
他にこれを英語表記して「cde^cde^ gedcded^」のように書くこともできます。これは、MML(Music Macro Language)と呼ばれるもので、古いBASIC(PC98、MSXやX68xx)全盛の時代に、ゲームのBGMの演奏などに使われていた表記方法です。
この『テキスト音楽「サクラ」』は、CodeGear(Borland) Delphi で開発されており、Windowsでしか動作しません。そこで、これを、Webブラウザ(Java Applet)で動くようにしようというのが本稿の狙いでもあります。
また最近では、はてなダイアリーに MML の演奏機能が実装されたり、マビノギというオンラインRPGの中で演奏できたり、密かにMMLが盛り上がっているのでは?!と思っています。
そこで、今回のプログラムを、『JAVAサクラ』と名付けて、完成したら公開しようと思います。
Java の MIDI ライブラリ
前回、Java で MIDI を演奏するいくつかの方法を紹介してみました。直接MIDIメッセージを送信する、Receiverクラスと、演奏情報を元に音楽を演奏する Sequencer クラスがあることが分かりました。また、Sequencer クラスは、MIDIファイルを元にして演奏を行ったり、演奏情報からMIDIデータを書き出すことができることが分かりました。
演奏を行う Sequencer クラスでは、まず、演奏情報(MIDIメッセージと再生のタイミング)を、Sequence オブジェクトに設定しておき、これを Sequencer に与えることで再生を行うことができるのでした。
このように、Java の MIDI 環境は、かなり充実しており、MIDIを利用することで、目標としている音楽シーケンサーを作ることができそうです。それで、将来的には、Receiverクラスを利用して、自分でプレイヤーを作ってみたいと思うのですが、今回は、Sequencer クラスを利用して演奏を行わせることにしました。
マクロ言語の設計
さて、音楽の演奏の方は、なんとかなりそうですので、次に、音楽を演奏するためのマクロ言語の設計について考えてみましょう。今回はこれが一番の課題となります。
文字列マクロ(音符の情報)を演奏情報に変換するわけですから、ちょっとしたコンパイラの製作と言えるかもしれません。しかし、MIDI情報は機械語ほど複雑ではなく、Java のライブラリ javax.sound.midi で扱いやすくラップされているので、コンパイラを作るよりはずっと易しいと思います。
では、コンパイルの手順を考えていきましょう。基本的には、演奏情報のマクロ(文字列)を1文字ずつ調べていって、マクロに応じた音符を計算して、最終的に Sequence オブジェクトに書き込んでいくという手順になるでしょう。
例えば、童謡のちょうちょのフレーズ、「ドレミー ドレミー ソミレド レミレー」を演奏させることを考えてみましょう。文字列を前方から1文字ずつ調べていきます。そして「ド」を見つけたら、演奏情報(MIDIメッセージのノートオン)を Sequence オブジェクトへ書き込みます。「レ」も同様に書き込みます。そして「ミ」ですが、直後に音符を伸ばす記号の「ー」がありますので、音符の長さを2倍にして書き込むことになります。このように考えていくと、1文字、音符(ドレミファソラシ)を読む時に、その後ろに音符の長さが指定されていないかを調べてから、音符を書き込めば良い事が分かります。
プログラミング言語をコンパイルする場合:
実は、プログラミング言語を作る場合にも、これに似たような処理を行っているのです。一般的なプログラミング言語では、まず、プログラムを最小限の意味単位(トークン)に分割します。これが字句解析処理です。そして、トークンが分割されたら、これを1つずつ読んでいって構文解析を行い、トークンを意味のあるまとまりとして意味解析を行います。意味解析が終われば機械語として出力することができるのです。
簡単にコンパイルの手順を箇条書きすると次のようになります。
- 字句解析
- 構文解析
- 意味解析
- 結果の出力
音楽マクロを解析する場合にも、音符ごとに文字列を分割していくのが、字句解析で、その後、分割した結果を元に音符情報へ変換するのが構文分割、意味解析と言えます。いきなりプログラミング言語を作るのは大変かもしれませんが、音楽マクロを解析するのは、それほど難しくないので、自分のプログラミング言語を作りたいと思っている人は、この辺りから始めると良いかもしれません。
音楽マクロのソースを解析
それでは、Javaで文字列を解析する処理を作ろうと思います。音楽マクロのソースのようなものを解析する場合、ソースのどの部分まで解析しておくのか位置を覚えておく必要があります。そこで、ソースを解析を行う汎用の Tokenizer クラスを作ってみました。
このクラスには、解析位置を表すインスタンス変数「position」があり、1文字取り出すごとに、この変数の値を足していきます。
public class Tokenizer { protected String source; protected int position; public Tokenizer(String source) { this.source = source; this.position = 0; } public char getChar() { char res = source.charAt(position++); return res; } // 続く.. }
ただし、解析位置から任意の単語があるかどうかチェックする場合などは、String クラスの「startsWith()」メソッドが使えると便利です。そこで、次のような定義もしておきます。
public boolean startsWith(String word) { return source.startsWith(word, position); }
そして、数値を取り出す処理などは、次のように書けるでしょう。
public int getInt(int default_value) { // get numeric string int len = 0; int ret = 0; int flg = 1; if (startsWith(‘-’)) { flg = -1; } while (!EOS()) { char c = getChar(); if (!isNumberic(c)) { back(1); break; } len++; ret = (ret * 10) + (c - ‘0′); } if (len == 0) return default_value; return ret * flg; }
このようにして、音楽マクロを解析していきます。
日本語表記とMML表記両方に対応する
次に、上記のテキスト音楽「サクラ」では、日本語表記のストトン表記と、cde のようなMML表記が使えます。そこで「JAVAサクラ」でも、同じように記述できるように工夫してみます。
このためには、まず、日本語で記述されたコマンドを全て MML 形式に変換してしまって、その後に、MML を解析するという処理を作ってみました。日本語コマンドをMMLに変換する場合、日本語のコマンドを最長一致で次々と照合させていって、日本語コマンドと合致する文字列があれば、MML と置換するという処理を行います。
public void convertSutoton() { String res = ""; SutotonList sutoton = new SutotonList(); //—(*1) // convert this.position = 0; while (!EOS()) { char c = getCur(); if (c < 256) { //—(*2) res += c; position++; continue; } // check sutoton boolean b_replace = false; for (int i = 0; i < sutoton.size(); i++) { SutotonItem item = (SutotonItem)sutoton.get(i); if (startsWith(item.sutoton)) { // —(*3) res += item.mml; position += item.len; b_replace = true; break; } } if (!b_replace) { res += c; position++; continue; } } // reset this.setSource(res); }
プログラム中の(*1)で日本語コマンドの一覧クラスを得ます。これは、Vector クラスを継承して作成したものです。(*2)では、文字コードが256以下の文字(つまり日本語コマンドに合致しないもの)は変換しないようにしています。(*3)では、現在の解析位置に日本語コマンドがあるかどうかを判断し、もしあれば、MMLのコマンドに置換します。
Applet にする
このような感じで、音楽マクロを Sequence オブジェクトに変換してみました。次に、これを Applet から鳴らせるように工夫してみます。Java のプログラムを、Java Applet にするには、Applet のために、Applet クラスを継承したクラスを作ります。
そして、JavaScript から操作できるように、Appletのメソッドを public にしておきます。以下のような SakuraApplet クラスを準備すれば完成です。
import java.awt.*; import java.applet.*; public class SakuraApplet extends Applet { private Label txtInfo = new Label("JAVAサクラ ver.0.02"); private Main compiler; public void init() { add(txtInfo); } public String compile(String mml) { try { compiler = new Main(); compiler.setMML(mml); compiler.compile(); return "[ok]"; } catch (Exception e) { return e.getMessage(); } } public void play() { compiler.play(); } }
最後に、これを表示するためのHTMLとJavaScriptを書いたら、ブラウザ上で動く音楽マクロシーケンサーの完成です。AppletをJavaScriptから操作する詳しい方法は、また次回紹介したいと思います。
まとめ
こうして「JAVAサクラ」が完成してきました。とりあえず動くようになったものを以下よりリンクしておきます。適当に「ドレミ」と入力したものが鳴るのを確認してみてください。(JRE1.4以上で動きますが、なぜか、1.4 だとリズムが乱れてしまうので、最新版の JRE 1.6 以上で試してみてください。)
それでは次回、JAVAサクラの改良と、Java Applet を JavaScript と連携して使う方法について紹介したいと思います。お楽しみに。
このサイトについて
TrackBack URL :

