2022.5.27
前回のプログラムで「MMLを配列に入れ、1文字ずつ取り出し、ノート番号に変換する」といった基本的な解析プログラムができました。
ここからが頭を抱える作業です。と言っても、ルール通を理解し、ルール通りに動くプログラムを作ればいいだけなんですよね。
どういうことかと言いますと、例えば、このようなMML表記をした場合・・・
CDE2CDE2
CD処理できたので気にすることはありません。次のE2で「ミを2拍伸ばす」わけですが、前回のプログラムでは1文字ずつ取得するので、「2」の処理ができません。
まだまだあります。
C1D2.E-4F8.G16A32.B>C
ご覧のように1文字ずつ処理できないことは明白です。では今までの考え方やプログラムが間違っていたのでしょうか?そんなことはありません。ここで登場するのが冒頭のルールです。MMLの記述は必ず英字から始まります。つまり1文字です。この始まりを見つけるためには1文字ずつ見る必要があるので、前回のプログラムは無意味ではありません。どんなルールになるか整理してみましょう。
【英字から始まる】
・A~Gは音程、Rは休符、Lはオクターブ、Lは音の長さの初期値などなど
・英字の次は英字になるかもしれない→英字の処理をすればいい
・英字の次は+/-(半音上げ下げ)になるかもしれない→半音上げ下げの処理をする
・+/-の次の文字は英字になるかもしれない→英字の処理をすればいい
・+/-の次の文字は数(音の長さ)かもしれない→音の長さは付点を含めて3桁かもしれないので先の文字を見てから処理する
・英字の次は数(音の長さ)かもしれない→音の長さは付点を含めて3桁かもしれないので先の文字を見てから処理する
もっと細かく書くことはありますが、おおよそこんな感じですね。これはプログラムの考え方なので、人間的と言うか、もうちょっと言葉で説明するとこのようになります。
MMLは必ずアルファベットで始まる。続いて半音記号もしくは音調が続く。
順番のルールは「C、C4、C+、C+4、C+16.」であり、「C4+」のような音程が確定する前に音長を指定しない。
「音程+音長」の記述で1音が確定する。
付点を付ける場合は基準となる音長を必ず指定する「C.、C+.」は存在しない
どちらの方が分かりやすいかは人それぞれですが、だいたい言ってることは同じです。他に休符などの条件もありますが、それはスタートの段階で発見できる文字なので、後から考えることにします。さて、このようなルールが分かってきたので、プログラムをしていきましょう。配列を使うとややこしいので、変数で作っていきます。最初は簡単な方法で確認するのがベストです。
10 BPS 312500:UART 3・・・MIDIの設定
20 Z="CDEC4D4E4"・・・MMLデータ
30 LET[65],69,71,60,62,64,65,67・・・ノートナンバー
40 A=0・・・MMLを読み込む位置を0(先頭)にする
50 M=PEEK(Z+A)・・・MMLを1文字読み込む
60 IF M==0 END・・・MMLが終わったら終了
70 IF (64<M AND M<71) OR R==114 GOTO 100・・・MMLがA~G,Rだったら100行へ
80 </>だったらオクターブを変える
90 A=A+1:GOTO 50・・・読み込む位置を1つずらして50行へ
100 '英字が見つかった
110 N=[M]・・・ノートナンバーとりあえず確定
120 A=A+1:M=PEEK(Z+A)・・・次の文字を読み込む
130 IF M==43 OR M==45 N=N+(M==43)-(M==45):GOTO 120・・・+/-だったらノートナンバーを半音変えて120行へ
140 IF 47<M AND M<58 GOTO 210・・・数字だったら210行へ
150 'ここから発音
160 ? CHR$(#90,N,127)・・・鍵盤を押す
170 WAIT 60・・・待つ
180 ? CHR$(#80,N,127)・・・鍵盤を離す
190 GOTO 50・・・50行へ
200 ' 音長を決める
210 ~~~つづく~~~
もしちゃんと動かなかったらごめんなさい
はい、これは目が回りますね。でもゆっくりと1行ずつ読んでいくと、先ほど整理したルールに従ってプログラムを作っているだけだと思いませんか?
最初にやることはスタートとなる英字を見つけることです。それ以外は何もしません。(終了は除く)
まだ音の長さと、オクターブ処理が終わってませんので完璧とは言えませんが、骨格はできたので、あとは見つけた文字によってどのように処理するかを書くだけです。
今回はここまで。
