Moonsoundについて

Moonsoundとは海外で作成された高音質サウンドカード。
ここではC言語から利用する場合の説明をする。

Moonsoundは拡張カートリッジとして作られており、音源はYAMAHA製のPCMサンプリング
(16bitのwaveテーブル)とFM音源そしてPCM音源のデータセット(音のデータROM)を搭載している。
この音源に対しては、一部の海外製ゲームが対応していたり、音楽シーケンサーが作られた。
非常に良いサウンドを持つこのハードウエアには幾つかの互換性を持つクローンが存在する。

Moonsound自体は日本ではあまり有名ではなく、MIDI接続音源の方が一般的だった。
国内で多く流通してはいない。現在エミュレーション環境で再現することができる。
現在では幾つかのエミュレータにおいてMoonsoundの音源機能を再現しているので、そのステレオ
サウンド音を体験する事が可能である。

音源ハードウエア的にはYAMAHAのWaveテーブルシンセサイザOPL4であるYMF278が搭載されている。
サンプルサウンドのためのメモリが搭載されており、音源データを用意する必要はない。
ハードウエアにはステレオサウンド出力端子が備えられている。
(Moonsoundエミュレータの出力はステレオサウンド)
サウンドハードウエアは音源であるYMF278とサンプリングサウンドメモリ(RAMとROM)、
ステレオDACのYAC513によって構成されYMF278のFM音源部分はYMF262と互換性がある。

PCM, YMF278
FM音源, YMF262互換
RAM(WAVE), 1-2MB(容量はモデルによる)
DAC, YAC513
Wavetable音色ROM YRW-801(YAMAHA)


YMF278のFM音源部分についてはレジスタセットがY8950やYM262(Sound Blasterに搭載)と
非常に良く似ているので(OPL系)使い方はそれらを参考にすると良いだろう。
特に理解が難しいFM音源チャンネルのスロット部分は共通しており、パラメータセットアップ処理は
共通なので似ている。

Waveテーブル音源については音源そのものはROMに搭載されている。このROMは拡張カートリッジ内部に
搭載されており、ROM以外にRAMにも音源データを持たせる事が可能。
PCMWaveテーブル音源の音色データはROMに依存しているのでそれらを参照するとよいだろう。

このハードウエアはBIOS等はサポートしていないので、BASICのPLAY文等で発音する事は出来ない。
専用のソフトウエア(音楽シーケンサーやプレイヤーや対応ソフト)が必要である。
MBWaveというソフトはMoonsoundで動作する音楽シーケンサーソフトである。
既存の環境から音を再生する場合はI/Oポート経由でYMF278のレジスタを直接操作する。


I/Oアドレスは下記にマップされている

0x7E-0x7F, WAVE Register/data
0xC4-0xCF, FM Register

0x7E wave register
0x7F wave data
0xC4 FM bank 1 register
0xC5 FM data
0xC6 FM bank 2 register


YMF278のFM音源レジスタは多くのチャンネルをサポートする為にバンク切替となっており、
0xC4と0xC6の二つのI/Oポートで異なるバンクレジスタ番号を指定する。データ読み書きは
共通。


  • BASICによる音源テスト

エミュレータでMoonsoundをサポートしている場合、下記のプログラムで音が鳴る。
このテストプログラムはMoonsound(YMF278)のPCM Wavetableを使い、音色ROMのNo.45(笛)
の音を出力するもので、正しく動作する場合はスポーツで使う笛の音が鳴る。
音源のテストでWavetable音源が正しく動作する事を確認する。

100 'memtype
110 out &h7e,&h2
120 out &h7f,&h30

130 'octave
140 out &h7e,&h38
150 out &h7f,0

160 'attack rate
170 out &h7e,&h98
180 out &h7f,&hf0

190 'voice no
200 out &h7e,&h08
210 out &h7f,45

220 'keyon
230 out &h7e,&h68
240 out &h7f,&h80

250 for i=0 to 2000:next i

260 'keyoff
270 out &h7f,0


音色データ番号は様々な効果音や楽器のサンプリング音が収録されており、それらは
YRW-801に従う。
恐らく300程度の音色データを持っているが詳細は不明なので以下のプログラムで255までの
音色データを再生して確認する。
(OctaveやAttack rate初期化は省略なので上のプログラム実行後にRUNすること)

100 for i=0 to 255
110 out &h7e,&h08
120 out &h7f,i
130 print "No.";i
140 '
150 out &h7e,&h68
160 out &h7f,&h80
170 for j=0 to 3000:next j
180 out &h7f,0
190 next i


  • YMF278のPCM Wavetable音源について

音源ROMはYAMAHA YRW-801(330種の音色)データROMを搭載し2MB搭載されており22khz,12bit
サンプルデータを保持している。音色データにはフォーマットがあるのでROM形式やRAMに書き込む
際には注意が必要となる。(非圧縮PCMらしい)
これらはMIDIスタンダードに準拠しているようだが、音色番号と音色との関係はGM規格と一致
していないようなので音色と番号の対応関係の詳細は不明。
MoonsoundにはRAMも搭載されているので音色データは別途外部からダウンロード可能。
サウンド音声はステレオ再生で、チャンネルは24ch。そのためのレジスタセットが用意されている。
C言語による制御はI/Oポートによる直接制御となり、ドライバ類などは無い。

C言語から使う場合の例を示す。以下の例では別途作成したI/Oポート操作関数を用いているので
リンク時に指定する必要がある。


extern unsigned char inp(unsigned char);
extern outp(unsigned char,unsigned char);

void ymf278fm1(unsigned char reg, unsigned char dat);
void ymf278fm2(unsigned char reg, unsigned char dat);
void ymf278wav(unsigned char reg, unsigned char dat);

void main(void){

	volatile long i;

	//memtype
	ymf278wav(0x2,0x30);

	//octave
	ymf278wav(0x38,0x0);

	//attack-rate
	ymf278wav(0x98,0xf0);

	//voice ch0=41
	ymf278wav(0x08,41);

	//key-on
	ymf278wav(0x68,0x80);

	for(i=0; i<50000; i++);

	//key-off
	ymf278wav(0x68,0x0);

}
 
//YMF278 Wavetable Sound Register
void ymf278wav(unsigned char reg, unsigned char dat){
	volatile int i;

	outp(0x7E,reg);

	for(i=0; i<3000; i++);

	outp(0x7F,dat);

	for(i=0; i<3000; i++);
}

//YMF278 FM Sound Register Bank1
void ymf278fm1(unsigned char reg, unsigned char dat){
	volatile int i;

	outp(0xC4,reg);

	for(i=0; i<3000; i++);

	outp(0xC5,dat);

	for(i=0; i<3000; i++);
}

//YMF278 FM Sound Register Bank2
void ymf278fm2(unsigned char reg, unsigned char dat){
	volatile int i;

	outp(0xC6,reg);

	for(i=0; i<3000; i++);

	outp(0xC5,dat);

	for(i=0; i<3000; i++);
}

これらをコンパイルする場合のコマンド引数を示す。
(io.relは別途作成したI/Oポート関数でリンクの際に指定する必要がある)

>sdcc -c -mz80 snd1.c
>sdld -b _CODE=0x100 -b _DATA=0x800 -i snd1.ihx snd1.rel io.rel
>makebin -s 4096 snd1.ihx > snd1.bin
>perl binout.pl snd1.bin > snd1.com


  • YMF278のFM音源について


FM音源のレジスタセットはY8950やYMF262と似ている。レジスタ指定はモジュレータとキャリア
それぞれにパラメータを指定する必要があるのでやや煩雑となる。
またチャンネル数が多いためレジスタバンク構成を持っており、バンク1,2それぞれを別関数
として実装してみた。
以下にC言語の例を示す

extern unsigned char inp(unsigned char);
extern outp(unsigned char,unsigned char);

void ymf278fm1(unsigned char reg, unsigned char dat);
void ymf278fm2(unsigned char reg, unsigned char dat);
void ymf278wav(unsigned char reg, unsigned char dat);

void main(void){

	volatile long i;

	//carrior multiple level
	ymf278fm1(0x23,3);

	//carrior total level
	ymf278fm1(0x43,0);

	//carrior attack&decay
	ymf278fm1(0x63,0xF0);

	//carrior sust&rel
	//ymf278fm1(0x83,0x13);

	//ch1 f-number
	ymf278fm1(0xA0,0x80);
	ymf278fm1(0xB0,0x10);

	//output enable (ch A/B)
	ymf278fm1(0xC0,0x30);

	//key-on
	ymf278fm1(0xB0,0x30);

	for(i=0; i<50000; i++);

	//key-off
	ymf278wav(0xB0,0x10);

}

//YMF278 Wavetable Sound Register
void ymf278wav(unsigned char reg, unsigned char dat){
	volatile int i;

	outp(0x7E,reg);

	for(i=0; i<3000; i++);

	outp(0x7F,dat);

	for(i=0; i<3000; i++);
}

//YMF278 FM Sound Register Bank1
void ymf278fm1(unsigned char reg, unsigned char dat){
	volatile int i;

	outp(0xC4,reg);

	for(i=0; i<3000; i++);

	outp(0xC5,dat);

	for(i=0; i<3000; i++);
}

//YMF278 FM Sound Register Bank2
void ymf278fm2(unsigned char reg, unsigned char dat){
	volatile int i;

	outp(0xC6,reg);

	for(i=0; i<3000; i++);

	outp(0xC5,dat);

	for(i=0; i<3000; i++);
}

OPL系のFM音源LSIで難しいのはレジスタセットの部分。
音の再生は普通はチャンネル単位で理解されている。
しかしLSIのレジスタパラメータを指定する場合はレジスタナンバーとの対応があり、資料など
ではチャンネルスロットなどという概念で記載されているので理解しづらい。
例としてY8950のチャンネルと各種レジスタパラメータの対応を以下に示す。

channel, modulator reg, carrier reg
ch1, 0x20, 0x23
ch2, 0x21, 0x24
ch3, 0x22, 0x25
ch4, 0x28, 0x2b
ch5, 0x29, 0x2c
ch6, 0x2a, 0x2d
ch7, 0x30, 0x33
ch8, 0x31, 0x34
ch9, 0x32, 0x35

YMF278のFM音源パラメータの指定時のチャンネルとオペレータの関係はY8950やYMF262とだいたい同じだ。
チャンネルch1のFM音源のパラメータは主にAttack/Decayなどのエンベロープ部分と、
各種モジュレータ、キャリアの周波数パラメータの指定となる。
普通はキャリア部分が中心で、この周波数パラメータがSIN波の基礎となる。
モジュレータはSIN波を変調するためのパラメータ。
単純なテスト信号であれば変調は必要ないのでキャリア部分パラメータにのみ注目すればよい。

もし2オペレータ動作時にch1のキャリアオペレータのマルチプルレベルを変更したい場合、
レジスタアドレスは0x23となる。
一方でch1のモジュレータオペレータのマルチプルレベルを変更する場合は0x20となる。

この関係をレジスタ番号で指定する場合、ch1のモジュレータが0x20、キャリアが0x23というように
アドレスが0x3増える場所に配置されている。

この関係はチャンネル単位では3チャンネルごとにインクリメントされる。
上の例では2オペレータ時の構成だが、4オペレータではこの関係も変化する。
このレジスタ対応は資料だけではわかりづらいので実際にコードを書いてチェックするとよいだろう。

音色データについてはYM2413のように予めプリセットされたROMがないので初期化し音色データを
書き込む必要がある。音色データはマイコンやCPU側で持っている必要がある。
これらはYMF262やY8950と同じで若干初期化の際の手順が煩雑で、音色データも自作する必要が
ある。(この点はYM2413は単純な音色で音色データは固定だが使い方は簡単である)

単純な音色サンプルデータの保持であればC言語の配列パラメータとして直接ハードコード
しておいて使う事も可能だろう。
シーケンサー用途だと外部ストレージなどからデータをロードしてレジスタ書き込みする必要
があるだろう。

単純なサンプルであればFM音源の音色パラメータを配列定数として書くことも出来るだろう。
これで幾つかのサンプルパラメータをCのソースに埋め込む事が可なはず。

const unsigned char voice1[] = {0xff,,,,,};
{Mod Multiple, Carr Multiple,
Mod Totallevel, Carr Totallevel,
Mod Attk&Decay, Carr Attk&Decay, Mod Sust&Relse, Carr Sust&Relse}



音階データについても数値を直接扱うのではなく、予め配列定数で用意した音階コードを使う
こともできるだろう。

const unsigned int keynote[] = {363,385....};

この場合、定数配列の引数がキーノートで、この値はオクターブを含めることもできるかもしれない。
MMLで"C"という音階であればO4Cという意味となる。
MMLで書く場合は適当にこのキーノートの数値をdefineでマクロ定義することも可能かもしれない。
単純な用途ではこれらで十分だろうと思う。

#define
O4C 1



  •  その他諸々

Moonsoundとは直接関係ない話になるが、
当時の記憶が確ならば、当時のMSX1の音源はPSGのみであった。その後にKonamiからSCC音源が開発され
音表現に幾つかの選択肢が生じる事になった。
コンピュータハードの製造業者としては家電メーカーが多かったので、新しい音源の登場は彼らを刺激した。
幾つかの企業はヤマハのFM音源を採用した。その後にMSX規格として取り込まれ採用されたものがAUDIOやMUSIC
規格だったと思う。
ソニーは音源については別途独自の研究に着手したが、多分この時の出来事が切っ掛けになっている部分もあるだろう。
その後に任天堂の16bit機に採用されるサウンドシステムを開発した。これはADPCMのサンプリングサウンドで、
これまたその後の初代Playstationの音源LSIにも採用された設計でもある。
で、この最初のPCM(ADPCM)サウンド音源の研究してた人が多良木さんで、その後のSCEIの人。
何やらそんな話であったように思う。


  • サンプル例

海外の人が作ったMoonsound用音楽。

こちらはデモ再生。音源はMoonsound

タグ:

+ タグ編集
  • タグ:

このサイトはreCAPTCHAによって保護されており、Googleの プライバシーポリシー利用規約 が適用されます。

最終更新:2014年10月25日 05:36
ツールボックス

下から選んでください:

新しいページを作成する
ヘルプ / FAQ もご覧ください。