PC-88シリーズには、PC-8801mk2SRからFM/SSG音源が内蔵されました。それ以前の機種でも拡張すれば使えます。また、上位互換の音源を内蔵していたり、それを増設したりと、様々な組み合わせが考えられます。
今回の記事では、一番基本的なYM2203(OPN)を内蔵していた場合についての処理を解説します。
PC-88では、音源をI/Oポート経由で制御します。そのポート番号は 0x44, 0x45 に割り当てられています。増設したりした場合には異なるポートになる可能性がありますが、ここでは解説しません。
【参考】PC-8801 Programing - Sound Information -(外部サイト)
#include <stdlib.h>
void main()
{
outp( 0x44, 0x08 ); // 音量設定
outp( 0x45, 0x0a ); // 値(0-15)
outp( 0x44, 0x00 ); // 音階設定(L)
outp( 0x45, 0xee ); // 「ド」(L)
outp( 0x44, 0x01 ); // 音階設定(H)
outp( 0x45, 0x00 ); // 「ド」(H)
outp( 0x44, 0x07 ); // 出力選択
outp( 0x45, 0b00111110 ); // 出力開始
for( int i = 0; i < 20000; i++ ){} // 音の長さ
outp( 0x44, 0x00 ); // 音階設定(L)
outp( 0x45, 0xd4 ); // 「レ」(L)
outp( 0x44, 0x01 ); // 音階設定(H)
outp( 0x45, 0x00 ); // 「レ」(H)
for( int i = 0; i < 20000; i++ ){} // 音の長さ
outp( 0x44, 0x00 ); // 音階設定(L)
outp( 0x45, 0xbd ); // 「ミ」(L)
outp( 0x44, 0x01 ); // 音階設定(H)
outp( 0x45, 0x00 ); // 「ミ」(H)
for( int i = 0; i < 20000; i++ ){} // 音の長さ
outp( 0x44, 0x07 ); // 出力選択
outp( 0x45, 0b00111111 ); // 出力停止
}
I/Oポート0x44へSSGレジスタの番号を指定後、I/Oポート0x45へ値を書き込むことによって、SSGレジスタの値を設定することが出来ます。
SSGレジスタには多くの種類がありますが、ここでは最低限必要な「音量」「音階」「出力選択」のみを解説します。
【参考】YM2203のレジスタ設定(PSG音源編) - 滴了庵日録(外部サイト)
レジスタ0x08~0x0aが、SSGチャンネルA~Cの音量に割り当てられています。
エンベロープを使用しない場合、bit0-3の下位4ビットで音量を設定し、bit4には0を指定します。
レジスタ0x00~0x05が、SSGチャンネルA~Cの音階に割り当てられています。
分周比を12bitで指定することによって音階を変化させます。例えばチャンネルAであれば、レジスタ0x00に下位8bit、レジスタ0x01に上位4bitを指定します。
書き込むべき値の計算式は、以下の通りです。
124800 / 周波数
例えば、「ラ」の音(440Hz)を鳴らしたい場合、124800 / 440 = 283(11Bh)ですので、レジスタ0x00に0x1b、レジスタ0x01に0x01を書き込みます。
【参考】FM音源チップYM2203(OPN)PC-8801mkIISR はどの程度高周波数を出しているのか | PHILE WEBコミュニティ(外部サイト)
レジスタ0x07で各チャンネルの出力を選択します。bit0-2で、チャンネルA-Cそれぞれのトーン出力を指定します。0:ON、1:OFFになります。bit3-5はノイズ出力の指定です。