5.3 FM音源のデート構造だ  このページでは、FM音源のデータ構造と、実際に音源データを指定する方法を説明する。前に説明したマシン語でFM音源を操作するプログラムと合わせて利用しよう。 5.3.1 FM音源のデータを作ってみよう  前のページでは、FM-BIOSをマシン語から呼び出して、音を出すためのプログラム例を紹介した。ここでは、そのプログラムを使って演奏するための、FM音源のデータの作り方を説明しよう。  FM-BIOSのデータ構造を要約するならば、大きな配列ということになる。配列の中にあるそれぞれのデータ位置は、配列の先頭からのバイト数で数えられ、"オフセット"と呼ばれている。ただし、配列の先頭のオフセットは0だ。また、配列の先頭は"0バイト目"、その次は"1バイト目"というように、呼ばれることもある。  表5.4に掲載したのは、6楽器+1打楽器のデータ構造と、実際のデータ例を表わしたもの。これを見てもらえばわかるように、データ本体は配列の末尾の方に並べられ、配列の先頭の14バイトには、それぞれのデータが置かれるオフセットが書き込まれている。  順番にデータ構造を説明していくと、まず0バイト目と1バイト目(オフセット0と1)は、打楽器音データが置かれているオフセットで、かならず14が書き込まれる。この値をCPUのZ80が理解できるのように、下位バイト、上位バイトの順に2バイトで表わすと、それぞれ0EH、00Hとなる。  続く2バイト目から13バイト目(オフセット2〜13)には、楽器音のチャンネル1〜6までのデータのオフセットが置かれる。もしもこのときに、オフセット0が指定されていれば、そのチャンネルは使われていないというわけだ。  たとえば表5.5のデータ構造例では、2バイト目と3バイト目(オフセット2と3)に、21Hと00Hが書かれている。これが意味するのは、楽器音のチャンネル1の音源データが、オフセット33以降に置かれているということだ。そして4バイト目から13バイト目(オフセット4〜13)には、00Hが書き込まれているので、楽器音のチャンネル2〜6はつかわれないことがわかる。  前に紹介したFM音源をコントロールするプログラムでは、C言語のプログラムの中にあるテストデータを埋め込んだので、データの長さを数えてオフセット指定する必要があった。しかし、良く考えると、以下のようなアセンブラーあのプログラムで、音源データを作るほうが簡単だったかもしれない。参考までに書いておくと、 FMDATA: DW 14 DW CH1-FMDATA DW CH2-FMDATA DW CH3-FMDATA DW CH4-FMDATA DW CH5-FMDATA DW CH6-FMDATA DB 打楽器音データ... CH1: DB チャンネル1データ... CH2: DB チャンネル2データ... (以下、CH6まで同様)  ということになる。このプログラムなら、ソースリストをアセンブルするときに、MSX-DOSのアセンブラー(M80)がオフセットを自動的に計算してくれるからだ。  もっとも、このプログラムをそのまま実用として使うことはできない。BASIC言語におけるPLAY文の役割を果たすような、ミュージック・マクロ・ランゲージ(MML)を、FM-BIOSの音源データに変換するためのプログラムが、必要になるだろう。  さて、打楽器音なしで9楽器を演奏する場合は、表5.6に掲載したようなデータ構造になる。基本的には、6楽器+1打楽器のデータ構造と同じで、まず0バイト目から17バイト目(オフセット0〜17)までに、楽器音のチャンネル1〜9の音源データが書き込まれたオフセットを指定する。もしも00Hが指定された場合は、該当するチャンネルは使われないということだ。  また、チャンネル1の音源データは、かならず18バイト目(オフセット18)からはじまることなになるので、チャンネル1のデータオフセットには、12H、00H(10進数で18)の値がいつでも書き込まれている。  なお、これは余談になるけれど、FM-BIOSは、音源データの先頭が0EHであるか12Hであるかによって、打楽器の有無(つまり6楽器音+1打楽器音が、9楽器音のみか)を決めている。だから、打楽器音のデータはかならず14バイト目(オフセット14)から、打楽器音がない場合にはチャンネル1の楽器音データがかならず18バイト目(オフセット18)から、はじまる必要があるようだ。 5.3.2 打楽器音のデータを指定するには  図5.4に掲載したのが、打楽器音のデータ詳細と、実際のデータ列だ。ここでは、5種類の打楽器を"BSTCH"のアルファベットで、音のデータを2進数でそれぞれ表わしている。  まずは次のような2バイトのデータで、打楽器ごとの音量を指定してみよう。  101BSTCH  0000VVVV  このとき、"BSTCH"の5ビットの列には、音量を指定したい打楽器を1、そうでないものを0で指定する。また、"VVVV"の部分には、音量を指定する0〜15の値(実際には2進数の値)が入る。ただし、このときの"音量"は、最大音量に対する減衰量を指定するので、0なら最大の音が、15なら最小の音が出るので注意しよう。  たとえば、バスドラムの音量を0、スネアドラムとシンバルの音量を1に設定するには、  10110000  00000000  10101010  00000001 と指定すればいい。  音量の指定が終わったら、次に打楽器ごとの音長を指定しよう。ただし、打楽器音自体の長さは常に一定なので、この場合の"音長"とは、音を出してから次の音を出すまでの間隔を指している。そして、  001BSTCH によって、打楽器の種類が指定され、次の1バイトで音長(255までの値)を指定する。255以上の音長を指定するには、まず255を書き、その次に実際の音長から255を引いた値を指定する。この値が255以上ならば、同様の操作を繰り返せばいい。たとえば、  001110000  111111111  000000000 はバスドラム、音長255を表わし、  00110010  11111111  11111111  11111111  11101011 は、バスドラムとシンバル、音長1000を表わしている。  FM音源の仕様書には"音長"の単位が書かれていなかったけど、テストデータで実測した結果、音長の単位はタイマー割り込みの周期と同じ、60分の1秒だった。 5.3.3 楽器音のデータを指定しよう  表5.7に掲載したのが、楽器音のでデータの詳細だ。このデータの中には、表の1バイトの値だけで意味を持つものと、続く1バイトまたは2バイトの値との組み合わせで、意味を持つものがある。  実際に楽器音データを指定する順番は、音量、音色、サスティン、レガート、Qの順だ。  音量の指定は打楽器のデータを同じで、最大音量からの減衰量で表わす。つまり、0で最大の音が、15で最小の音が出るという具合。  サスティンは、楽器音の減衰を調整するためのものだ。楽器音のエンベローブは前にも説明したように、"ADSR"という値で決定される。繰り返すなら、Aはアタック(立ち上がりの速さ)、Dはディケイ(減衰)、Sがサスティン(持続の強さ)、Rがリリース(消える速さ)の略だ。  OPLL内蔵音色の"ADSR"は、音色ごとに固定されている。でも、サスティンをオンにすると、リリースが遅くなって、音が伸びる。さらに、サスティンはチャンネルべつに指定可能なので、チャンネル1と2の両方にギター音を割り当て、チャンネル1だけのサスティンをオンするというような、細かい工夫も可能だ。  レガートをオンすると、ひとつの音符と次の音符との音がつながる。ただし、レガートを使いすぎると曲のメリハリがなくなるので、一部分のチャンネルのみのレガートをオンにするような工夫が必要だろう。  Qに指定できる値は1〜8で、音符の長さと実際に音を出す長さの比を表わしている。たとえば、Q=6で音符の長さが80ならば、80×6÷8=60の長さの音が出て、80×(8-6)÷8=20の休みが入る。  以上の、レガート、サスティン、Qに指定する値の組み合わせで、音符のつながり方、つまり曲の滑らかさが決まるわけだ