データの構造/音名音長
このデータ形式にするには、コマンドFEHで(+09H)[データフラグ]のb0[音名音長タイプ]を1にします。
音名音長データの出現前にコマンドD0H-D5Hでオクターブ指定とE9Hで基本音長、EAHで音量を設定しておきます(コマンドの詳細はこちらなども参照してください)。
音名音長データのフォーマットは1バイトで以下の通りです。
- 上位4bit
-
音名。0H-CH。
0H-BHがMML表記でc, c+, d, d+, e, f, f+, g, g+, a, a+, bに対応。
CHは休符となり、消音。
- 下位4bit
-
音長値。0H-FH。
音の長さとしてのクロックは基本音長 * (音長値 + 1)。
サンプル
MMLでT120 V13 O4 L12 GB>D G4をデータにした場合。
データ | 意味 |
---|---|
FEH 01H | (+09H)を01Hにセットする。音名音長のデータ形式指定 |
E9H 0AH | 基本音長10 |
EAH 0DH | V13 |
D2H | O4 |
70H | G 基本音長10 * (0+1)=10クロック |
B0H | B 10クロック |
D1H | O5 |
20H | D 10クロック |
72H | G 基本音長10 * (2+1)=30クロック |
FFH | 曲データ終了 |
PSGで演奏させてみました。
音名とオクターブに分離したことと、音長を乗算に分解したことで1音の高さと長さを1バイトで表せるようになっています。
音名はともかく、音長が4bitで表せるのは目からウロコでした。
確かに扱われる音長はある長さの整数倍になるので、整数のクロック以上の音長はそれで表現できますし、端数が出る短い音長は基本音長を1として複数音で帳尻を合わせることができます。
当然表現できないテンポが存在しますが、それに近い表現できるテンポにしてしまうことで問題はクリアできるのだと思います。
まぁその代償に乗算という手間がありますが。
ここで実装されている乗算方法は足し算ループでした。
休符とタイについて
ドライバの機能ではなく使い方の問題ですが、休符はCHに割り当てられているものの、曲中には殆ど使われていないような気がします。
MMLで書けば、c8d8r8e8という部分はc8d4e8というデータに置き換わっていました。
当然、曲の頭や消音が必要なときは使用されると思われますが、殆どが何らかのエンベロープを使用しているので休符はエンベロープの続きを演奏することになり、消音はしないようです。
タイに関しては調べた限りでは1音の音長にしてあったので、ドライバの機能にタイはないと思われます。
分周比テーブルについて
テーブルは12音分が用意され、6AH,64H,5EH,59H,54H,4FH,4AH,46H,42H,3FH,3BH,38Hとなります。
PSG、SCC共用で使われているテーブルなので、基本的にどちらの音源用なのかと周波数にすると、6AH=1045.4Hz(SCC)、1055.3Hz(PSG)でo6cが1046.5Hzなので、SCCの計算を元にしたテーブルだと思われます。
テーブルから取得した値は(+09H)[オクターブ値]の回数だけ倍々されて分周比が算出されます。
そのような算出方法なので、オクターブは最高でo6までとなります。
PSGとSCCの周波数の違いについて
SCCとPSGは同じ周波数を鳴らすのに分周比が1違います。
PSG単体、SCC単体、PSG/SCC同時と言う鳴らし方を、分周比が同じ値のパターンと、PSGの分周比を+1したパターンで鳴らしています。
周波数が異なるので、同じ値を鳴らしたパターンはデチューンの効果が出て聞こえる一方、+1した方では全く同じ周波数になっています。
コナミのドライバはどのように扱っているのか気になったのですが、どうも気にしていないようです。
デチューン効果が自然に出て尚の事都合良し、という方針かなと思う程上記テーブルから取得した分周比そのままの値で使われています。
確かに実際に聞いてみると問題ないように聞こえます。
以下の部分は、ディレイ効果等はありますが同じ分周比で鳴らしているシーンです。