GBサウンドです。DMG(Dot Matrix Game)サウンドとも呼ばれる機能は初代GameBoyから継承されている技術です。正直なところGB資料の方が詳しくチップチューン界隈もある為、GBAカテゴリで限定する必要はないと思います。海外のPan Docなどのを参照するのもいいかもしれません。なおここを書いた中の人は1回も作曲経験がないプログラマー視点となります。ご了承ください(汗。
前回のDirectSoundでは音データはバイナリの塊で、波形図を見せて目で知覚しつつ理解してもらうノリで書いてみました。ざっくり言ってしまうとCD音質から劣化したものをGBAは取り扱っています。一方、GBサウンドはサウンド1~4まで存在していて、各レジスタがひしめき合っています。パラメータの内容をいくら文章ベースで説明したとしても、耳で知覚して覚えたこと以外の近道はないです。結論としてはHUGETrackerで実験した方が有意義だと思っています。TrackerのUIに勝るものはありません。ここから以下の文章は一応レベルで書かせてもらいました。順番としてはサウンド2→1→3→4とさせて頂きます。音を鳴らす順番に各レジスタを見ていきましょう。
4000084h - SOUNDCNT_X (NR52) - Sound on/off (R/W) Bits 0-3 are automatically set when starting sound output, and are automatically cleared when a sound ends. (Ie. when the length expires, as far as length is enabled. The bits are NOT reset when an volume envelope ends.) Bit Expl. 0 R Sound 1 ON flag (Read Only) 1 R Sound 2 ON flag (Read Only) 2 R Sound 3 ON flag (Read Only) 3 R Sound 4 ON flag (Read Only) 4-6 - Not used 7 R/W PSG/FIFO Master Enable (0=Disable, 1=Enable) (Read/Write) 8-31 - Not used While Bit 7 is cleared, both PSG and FIFO sounds are disabled, and all PSG registers at 4000060h..4000081h are reset to zero (and must be re-initialized after re-enabling sound). However, registers 4000082h and 4000088h are kept read/write-able (of which, 4000082h has no function when sound is off, whilst 4000088h does work even when sound is off).
REG_SOUNDCNT_X = 0x80; // turn on sound circuit
まず、Bit7をPSG/FIFO Master Enableにします。しないと音が出ません。
4000080h - SOUNDCNT_L (NR50, NR51) - Channel L/R Volume/Enable (R/W) Bit Expl. 0-2 R/W Sound 1-4 Master Volume RIGHT (0-7) 3 - Not used 4-6 R/W Sound 1-4 Master Volume LEFT (0-7) 7 - Not used 8-11 R/W Sound 1-4 Enable Flags RIGHT (each Bit 8-11, 0=Disable, 1=Enable) 12-15 R/W Sound 1-4 Enable Flags LEFT (each Bit 12-15, 0=Disable, 1=Enable)
REG_SOUNDCNT_L = 0x2277; // full volume, enable sound 2 to left and right
2進数は0010 0010 0111 0111bなので、Master Volume RIGHT,LEFTを0x7に、Sound 2 Enable Flags RIGHT,LEFTをEnableにします。
4000082h - SOUNDCNT_H (GBA only) - DMA Sound Control/Mixing (R/W) Bit Expl. 0-1 R/W Sound # 1-4 Volume (0=25%, 1=50%, 2=100%, 3=Prohibited) 2 R/W DMA Sound A Volume (0=50%, 1=100%) 3 R/W DMA Sound B Volume (0=50%, 1=100%) 4-7 - Not used 8 R/W DMA Sound A Enable RIGHT (0=Disable, 1=Enable) 9 R/W DMA Sound A Enable LEFT (0=Disable, 1=Enable) 10 R/W DMA Sound A Timer Select (0=Timer 0, 1=Timer 1) 11 W? DMA Sound A Reset FIFO (1=Reset) 12 R/W DMA Sound B Enable RIGHT (0=Disable, 1=Enable) 13 R/W DMA Sound B Enable LEFT (0=Disable, 1=Enable) 14 R/W DMA Sound B Timer Select (0=Timer 0, 1=Timer 1) 15 W? DMA Sound B Reset FIFO (1=Reset)
REG_SOUNDCNT_H = 2; // Overall output ratio - Full
ボリュームを100%にしています。
先ほどのレジスタ操作をまとめたのが以下のコードです。サウンド2を使いたい場合はこの形が基本になります。
REG_SOUNDCNT_X = 0x80; // turn on sound circuit REG_SOUNDCNT_L = 0x2277; // full volume, enable sound 2 to left and right REG_SOUNDCNT_H = 2; // Overall output ratio - Full
4000068h - SOUND2CNT_L (NR21, NR22) - Channel 2 Duty/Length/Envelope (R/W) Bit Expl. 0-5 W Sound length; units of (64-n)/256s (0-63) 6-7 R/W Wave Pattern Duty (0-3, see below) 8-10 R/W Envelope Step-Time; units of n/64s (1-7, 0=No Envelope) 11 R/W Envelope Direction (0=Decrease, 1=Increase) 12-15 R/W Initial Volume of envelope (1-15, 0=No Sound) Wave Duty: 0: 12.5% ( -_______-_______-_______ ) 1: 25% ( --______--______--______ ) 2: 50% ( ----____----____----____ ) (normal) 3: 75% ( ------__------__------__ ) The Length value is used only if Bit 6 in NR14 is set.
400006Ch - SOUND2CNT_H (NR23, NR24) - Channel 2 Frequency/Control (R/W) Bit Expl. 0-10 W Frequency; 131072/(2048-n)Hz (0-2047) 11-13 - Not used 14 R/W Length Flag (1=Stop output when length in NR11 expires) 15 W Initial (1=Restart Sound) 16-31 - Not used
音を作り出す重要な部分です。NR21, NR22などの記載はGameboyのレジスタ表記で互換性を持ちます。 突然ですが、焼きそばを自炊するときを想像してください(爆。麺をフライパンに放り込み、水で少しほぐします。 そしていい感じに水っけが飛んだらピーマン、レタス、玉ねぎ、小さ目の豚肉を投入してやや火を強めにして混ぜ合わせます。 最後にタレを投入して炒めれば完成です。焼きそばは麺やタレが主役で、他は個人の好みの具材を投入します。
Frequencyが主役で、他は引き立て役の意味を持ちます。まずFrequency(周波数)に注目してみましょう。0-2047という数字を入れますが、ドレミ音階のテーブルがすでに存在していて普段はこちらを使います。
400006Ch - SOUND2CNT_H (NR23, NR24) - Channel 2 Frequency/Control (R/W) 0-10 W Frequency; 131072/(2048-n)Hz (0-2047)
u16 FreqTable[12*6] = { // C C+ D D+ E F F+ G G+ A A+ B 44, 156, 262, 363, 457, 547, 631, 710, 786, 854, 923, 986, // o3 1046, 1102, 1155, 1205, 1253, 1297, 1339, 1379, 1417, 1452, 1486, 1517, // o4 1546, 1575, 1602, 1627, 1650, 1673, 1694, 1714, 1732, 1750, 1767, 1783, // o5 1798, 1812, 1825, 1837, 1849, 1860, 1871, 1881, 1890, 1899, 1907, 1915, // o6 1923, 1930, 1936, 1943, 1949, 1954, 1959, 1964, 1969, 1974, 1978, 1982, // o7 1985, 1988, 1992, 1995, 1998, 2001, 2004, 2006, 2009, 2011, 2013, 2015, // o8 };
オクターブ5のラ音、o5A=1750を計算してみると131072 / (2048-1750) = 131072 / 298 = 439.838...という数字が出てきました。四捨五入すれば440Hzです。TrackerやGB MMLドライバはテーブルで音符を抽出しています。