はじめに
この記事は 音楽ツール・ライブラリ・技術 Advent Calendar 2019 の 18 日目の記事です。
プチコン 4 が発売されて大分たちまして今更感もちょっとあるかと思いますが、プチコン 4 の MML 機能でやってみた事をざっとまとめてみました。
プチコン 4 の MML 関連命令
BASIC で MML というと基本的には
10 A$="O4L4 CCO3BO4C"
20 B$="O4L4 EF D E"
30 C$="O4L4 GA G G"
40 PLAY A$,B$,C$
みたいに書くよなあと思ってしまうのですが、プチコンは全然違います。
従来の BASIC の命令では多くの場合、 PLAY 文の実行時に同期的に再生 (一つの PLAY 文で指定した MML の再生が終わるまで再生から制御が返ってこない) されますが、プチコンの場合は BGM として非同期に再生が行われます。
※私が触ったことのある範囲だと PC-9801 の N88-BASIC(86) は同期再生ではなかった
一番簡単なのは BGMPLAY 命令で MML を文字列指定することです。
BGMPLAY "O4L4CDEFGAB<C"
これは下記と同一です。
BGMSET 255,"O4L4CDEFGAB<C"
BGMPLAY 255
BGMSET 命令で MML を登録し、 BGMPLAY で再生するわけですが、まずプチコンで最初に驚いたのが 1 曲全てを 1 つの文字列の MML で記述しなくてはならない ことです。 1 チャンネルではなく全チャンネル分です。
「え、そんなの完全に地獄モードじゃん・・・」と一瞬ここで挫けそうになるのですが、流石にそんな無茶な事は求められていません。
BGMSETD という命令を使うと DATA 命令で記述した DATA 列を一括で MML として読み込んでくれる機能です。例えば次のように使います。
BGMSETD 128, "@BGMTOP"
BGMPLAY 128
@BGMTOP
DATA "@0 V100
DATA "O4L4 CDEFGAB
DATA 0
BGMSETD では読み込み先 MML が記述されているラベル名を指定し、 MML を書いた DATA 命令列では終端に数値の 0 を設定します。
BGMSETD で一気に楽になりました。従来 BASIC のように PLAY 文を細々書く必要もないので感覚的には PC-8801 での MUCOM や PMD での MML 作成に近くなりました。
プチコン 4 で曲に使えるサウンド関連命令
WAVSET
波形メモリー機能です。配列でデザインした波形をセットするとその波形を音色として使用することができます。プチコン 4 の音色は GM 互換の音色セットが基本となりますが、がんばれば独自の音を作り出すことができます。
EFCEN / EFCSET / EFCWET
エフェクトを設定します。リバーブがかけれます。
EFCEN #EFCON
EFCSET #EFCSPACE
EFCWET 0,28,0,0
BGMWET という命令もあるのですが、うまく使えませんでした。
プチコン 4 の MML
基本的な文法は一般的な MML ですので、経験のある方ならすぐに音を出せます。 クォンタイズ、 LFO 、エンベロープもあるので音の鳴らし方もそれなりに作りこみ可能です。1 チャンネルで和音を入力する命令もあります。
個人的にはものすごい不満点が 2 つほどありました。
オクターブ記号の向き (< でオクターブ +1 、 > でオクターブ -1)- チャンネル毎にまとめて書かないといけない
前者はまあ宗教論争 (vim 対 emacs みたいな) の類なので言っても仕方のない話です。
(2020/9/22) コメントで指摘をいただきましたが、 "!" を入れることで反転させる事が可能とのことです。
後者は結構つらくて、チャンネルは ":(数字)" で指定しますが、一度使ったチャンネルは二度と指定することができないため途中でチャンネルを切り替えながら記述するということができません。
どうなるかというと
BGMSETD 128,"@BGMTOP"
BGMPLAY 128
@BGMTOP
DATA ":0
DATA "V92 @0 Q30 T96
DATA "O4L8 RDGA B2&BGAB< C>BAB&B4<F+4 E4.>B4.<F+4 E4.>B4BAB
DATA "O4 G2 E6F+6G6 G2F+2 G2A2
DATA ":1
DATA "V92 @0 Q30
DATA "O2L8 R2 G<DA2.> B<EBA&A2< B4. E4. B4 B4. G4GF+G
DATA "O4 E2> B6B6 B6< E2D2 E2F+2
DATA ":2
DATA "V100 @0 Q30
DATA "O2L8 R2 RG<DB&B2< E4.D+&D+2>> EB<F+G&G2> DB< F+G&G2
DATA "O2 C+B<C+E&E2> D2D2 D2D2
DATA 0
(オープニング / ソーサリアン / Copyright © Nihon Falcom Corporation)
本当は
DATA ":0 V92 @0 Q30 T96
DATA ":1 V92 @0 Q30
DATA ":2 V100 @0 Q30
DATA ":0 O4L8 RDGA B2&BGAB< C>BAB&B4<F+4 E4.>B4.<F+4 E4.>B4BAB
DATA ":1 O2L8 R2 G<DA2.> B<EBA&A2< B4. E4. B4 B4. G4GF+G
DATA ":2 O2L8 R2 RG<DB&B2< E4.D+&D+2>> EB<F+G&G2> DB< F+G&G2
DATA ":0 O4 G2 E6F+6G6 G2F+2 G2A2
DATA ":1 O4 E2> B6B6 B6< E2D2 E2F+2
DATA ":2 O2 C+B<C+E&E2> D2D2 D2D2
みたいに書きたいのですがこれはエラーになります。
ただこの辺の MML の不満 (オクターブ記号も) は自分でプリプロセッサを書けばなんとかなるとは思います。例えば
DIM MML$
DIM MMLCH$[3]
DIM L$
DIM CH=0
RESTORE @BGMTOP
@READLOOP
READ L$
IF LEN(L$)==0 THEN @READEND
DIM IDX=CH MOD LEN(MMLCH$)
MMLCH$[IDX]=MMLCH$[IDX]+L$
CH=CH+1
GOTO @READLOOP
@READEND
FOR I=0 TO LEN(MMLCH$)-1
MML$=MML$+":"+STR$(I)+" "+MMLCH$[I]
NEXT
BGMSET 128,MML$
BGMPLAY 128
@BGMTOP
DATA "V92 @0 Q30 T96
DATA "V92 @0 Q30
DATA "V100 @0 Q30
DATA "O4L8 RDGA B2&BGAB< C>BAB&B4<F+4 E4.>B4.<F+4 E4.>B4BAB
DATA "O2L8 R2 G<DA2.> B<EBA&A2< B4. E4. B4 B4. G4GF+G
DATA "O2L8 R2 RG<DB&B2< E4.D+&D+2>> EB<F+G&G2> DB< F+G&G2
DATA "O4 G2 E6F+6G6 G2F+2 G2A2
DATA "O4 E2> B6B6 B6< E2D2 E2F+2
DATA "O2 C+B<C+E&E2> D2D2 D2D2
DATA ""
みたいに自前で DATA 文を読み込んで (ここではやっていませんが) 文字列を解析して適宜変換した後、チャンネル毎に別々の文字列に格納しておいた上で後から結合すれば不満点は解消できそうです。
作例
プチコン4で打ち込んでみました
— TAN-Y(たに) (@TANY_FMPMD) December 17, 2019
オープニング / ソーサリアン / Copyright © Nihon Falcom Corporation pic.twitter.com/4PcqkpUyvT
これは BGMSETD を使っているので標準 MML の範囲で記述しています。
おわりに
プチコン 4 の MML 機能をざっとみてきました。
プチコン 4 の MML は音色がそろっているというのが大きなポイントかなと思いました。 FM 音源とかだと音色でつまづくパターンが多いかなあと思いますが、プチコンでは BGMPLAY でとりあえずさっと、かなり良い音で鳴らすことができるのでその辺の問題がなく、入門用としてもよいかなと思いました。
音色の作りこみもある程度可能ですので、熟練者でもやりがいのある環境ではないかと思います。機能面で不満な点は「プログラミング言語」らしく自力で解決していくのも楽しいのではないかと思います。
比較的お手軽に使える MML 環境だと思いますので可能であれば是非一度お試しください。