周波数のレジスタに音程ごとの周波数をセットします。
周波数の値についてはここを参考にしました。
プログラムはこんな感じです。
#include <stdio.h> #include <gb.h> // タイルデータ #include "Ascii_misaki.c" // 音程に対応した周波数 UWORD scale_frequency[] = { // C C+ D D+ E F F+ G G+ A A+ B // Oct 44, 156, 262, 363, 457, 547, 631, 710, 786, 854, 923, 986,// 2 1046,1102,1155,1205,1253,1297,1339,1379,1417,1452,1486,1517,// 3 1546,1575,1602,1627,1650,1673,1694,1714,1732,1750,1767,1783,// 4 1798,1812,1825,1837,1849,1860,1871,1881,1890,1899,1907,1915,// 5 1923,1930,1936,1943,1949,1954,1959,1964,1969,1974,1978,1982,// 6 1985,1988,1992,1995,1998,2001,2004,2006,2009,2011,2013,2015,// 7 2017 }; UBYTE input_on, input_old, input_edge, input_trg;// キー入力用 UBYTE scale;// 音程 UBYTE length;// 音長 UBYTE play_flg;// 再生フラグ void bg_num_disp(UWORD n, UBYTE x, UBYTE y, UBYTE d); void snd_reg_init(); // 変数初期化 void var_init() { scale = 0;// 音程 length = 0;// 音長 play_flg = 0;// 再生フラグ } // サウンド処理 void proc_snd() { UWORD frequency; // ファースト処理 if (play_flg == 1) { // チャンネル制御 // b7:全チャンネルON=1 / b3-0:チャンネル4~1再生中フラグは読込のみ NR52_REG = 0x80; // b7:左VinOF=0F / b6-4:左音量=7 / b3:右VinOFF=0 / b2-0:右音量=7 NR50_REG = 0x77; // b7-4:チャンネル4~1左出力ON=F(1111) / b3-0:チャンネル4~1右出力ON=F(1111) NR51_REG = 0xFF; play_flg = 2; scale = 0;// 音程 length = 0;// 音長 } // 再生開始 if (length == 0) { frequency = scale_frequency[scale]; // チャンネル1(矩形波スイープあり) // b6-4:スイープ時間=0 / b3:スイープ方向=0(上) / b2-0:スイープ変化量=0 NR10_REG = 0x00; // b7-6:デューティ比=3 / b5-0:音長カウンタ=0 NR11_REG = 0xC0; // b7-4:初期音量=15 / b3:エンベロープ増減=0(減) / b2-0:エンベロープ単位時間=0 NR12_REG = 0xF0; // b7-0:周波数(11ビットの下位8ビット) NR13_REG = (UBYTE)(frequency & 0x00FF); // b7:開始フラグ=1 / b6:カウンタ再生フラグ=0 / b2-0:周波数(11ビットの上位3ビット) NR14_REG = (UBYTE)((frequency >> 8) & 0x00FF) + 0x80; gotoxy(5, 3); printf("SCALE="); bg_num_disp(scale, 11, 3, 2);// BGへ数字描画 } if (length++ > 15) { length = 0; if (scale++ >= 72) { scale = 0; } } } void proc() { if (input_trg & J_A) { gotoxy(5, 2); print("PLAY"); play_flg = 1; NR10_REG = 0x00; NR11_REG = 0xC0; NR12_REG = 0xF0; NR13_REG = 0x0A; NR14_REG = 0x86; } if (input_trg & J_B) { gotoxy(5, 2); print("INIT"); snd_reg_init();// サウンドレジスタ初期化 var_init();// 変数初期化 gotoxy(5, 3); print(" "); } if (play_flg != 0) { proc_snd();// サウンド処理 } } // VBL割込で呼ばれる void vbl_isr(void) { // キー入力 input_old = input_on; input_on = joypad(); input_edge = input_on ^ input_old; input_trg = input_on & input_edge; proc(); } // BGへ数字描画 // n=表示する数値 x=描画X座標(左端) y=描画Y座標 d=描画桁数 // 10で除算をやってるので処理が重いかも void bg_num_disp(UWORD n, UBYTE x, UBYTE y, UBYTE d) { UBYTE f = 1;// 最初の0は表示する do { d--; gotoxy(x+d, y); if (f == 0 && n == 0) setchar(0);// 空白 else setchar(0x30U+(n%10));// 数字 f = 0; if (n != 0) n /= 10; } while(d != 0); } // サウンド関連の全レジスタを初期化 void snd_reg_init() { NR10_REG = 0; NR11_REG = 0; NR12_REG = 0; NR13_REG = 0; NR14_REG = 0; NR21_REG = 0; NR22_REG = 0; NR23_REG = 0; NR24_REG = 0; NR30_REG = 0; NR31_REG = 0; NR32_REG = 0; NR33_REG = 0; NR34_REG = 0; NR41_REG = 0; NR42_REG = 0; NR43_REG = 0; NR44_REG = 0; NR50_REG = 0; NR51_REG = 0; NR52_REG = 0; } void main() { DISPLAY_OFF;// 画面全体を非表示 HIDE_BKG;// BGを非表示 HIDE_SPRITES;// スプライトを非表示 print(" ");// ダミー描画 set_bkg_data(32, 64, AsciiBgLabel);// アスキー文字 // SHOW_SPRITES;// スプライトを表示 SHOW_BKG;// BGを表示 DISPLAY_ON;// 画面全体を表示 disable_interrupts();// 割込無効 add_VBL(vbl_isr);// VBL割込に追加 enable_interrupts();// 割込有効 set_interrupts(VBL_IFLAG);// VBL割込セット snd_reg_init();// サウンドレジスタ初期化 var_init();// 変数初期化 // メインループ(無くても良いけど何となく) while(1) { delay(1000UL); } }
チャンネル1を鳴らしている所にチャンネル2・3も音程を変えて
鳴らせば和音になります。
鳴らせば和音になります。
0 件のコメント:
コメントを投稿