周波数のレジスタに音程ごとの周波数をセットします。
周波数の値についてはここを参考にしました。
プログラムはこんな感じです。
#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 件のコメント:
コメントを投稿