• 雛形2 を使用します。
  • 短形波・三角波・ノイズの設定と再生を行います。
  • STARTを押しながらSELECTでタイトルに戻ります。
  • 各項目で左右を押すと値が増減します。
  • SHUHASUはSELECT・A・Bいずれかのボタンを押しながら左右を押すと増分値が変わります。
  • SHUHASUには以下の内容を設定します。
    • 矩形波:1790000/ (周波数 * 32 - 1) ・・・「ラ」(440hz)を鳴らそうと思えば127になります
    • 三角波:1790000/ (周波数 * 64 - 1) ・・・多分。
  • STARTを押すと音が鳴り、フラグの内容が16進数で表示されます。
    ゲームを開発する際にフラグとshuhasu、timeの値を指定すれば同じ音を鳴らすことができます。
#include <kihon.h>
#include <kanade.h>
 
#define DMA	(char*)0x0700
 
typedef enum {
	menuTITLE    = 0,
	menuSQUARE   = 1,
	menuTRIANGLE = 2,
	menuNOISE    = 3,
} emenu;
 
emenu menu;
char init;
 
void ClearScreen()
{
	unsigned char i,first,pos[2];
	first = 1;
	for (i = 0; i < 64; i++)
	{
		SetDMA( DMA,first, 0, 240, 0, 0);
		first = 0;
	}
	for (i = 0; i < 30; i++)
	{
		GetBackgroundAddress(0, 0, i, pos);
		VBlank();
		FillBackground(*(pos + 0),*(pos + 1),0,32);
		SetScroll( 0, 0 );
	}
}
 
void DrawString(char x, char y,char *str,char len)
{
	char pos[2];
	GetBackgroundAddress(0, x, y, pos);
	VBlank();
	SetBackground(*(pos + 0), *(pos + 1), str, len);
	SetScroll( 0, 0 );
}
 
void DrawHexdecimal(char x, char y,char val)
{
	char ret1, ret2, str[1];
 
	ret2 = val % 16;
	ret1 = (val - ret2) / 16;
 
	if (ret1 < 10) {
		str[0] = ret1 + 0x30;
	} else {
		str[0] = ret1 + 0x37;
	}
	DrawString(x    , y, str, 1);
 
	if (ret2 < 10) {
		str[0] = ret2 + 0x30;
	} else {
		str[0] = ret2 + 0x37;
	}
	DrawString(x + 1, y, str, 1);
}
 
void DrawArrow(char y)
{
	SetDMA( DMA,1, 30, (y * 2 + 3) * 8 - 1, 0x40, 0);
}
 
void DrawNumMax(char x, char y, char val, char max)
{
	char wrk;
	wrk = val % 10;
	SetDMA( DMA,0, (x + 0) * 8, y * 8, (val - wrk) / 10 + 0x30, 0);
	SetDMA( DMA,0, (x + 1) * 8, y * 8, wrk + 0x30             , 0);
 
	SetDMA( DMA,0, (x + 2) * 8, y * 8, 0x5c                   , 0);
 
	wrk = max % 10;
	SetDMA( DMA,0, (x + 3) * 8, y * 8, (max - wrk) / 10 + 0x30, 0);
	SetDMA( DMA,0, (x + 4) * 8, y * 8, wrk + 0x30             , 0);
}
 
void DrawNumLen(char x, char y, char val, char max)
{
	unsigned char wrk;
	signed char   i;
 
	for (i=2; i>=0; i--) {
		wrk = val % 10;
		SetDMA( DMA,0, (x + i) * 8, y * 8, 0x30 + wrk, 0);
		val /= 10;
	}
	SetDMA( DMA,0, (x + 3) * 8, y * 8, 0x5c                   , 0);
	for (i=2; i>=0; i--) {
		wrk = max % 10;
		SetDMA( DMA,0, (x + i + 4) * 8, y * 8, 0x30 + wrk, 0);
		max /= 10;
	}
}
 
void DrawNumber(char x, char y, int val)
{
	unsigned int wrk;
	signed char i;
 
	for (i=6; i>=0; i--) {
		wrk = val % 10;
		SetDMA( DMA,0, (x + i) * 8, y * 8, 0x30 + wrk, 0);
		val /= 10;
	}
}
 
void Square()
{
	char flag1,flag2;
	static char top   ;
	static char duty  ,counter,onkyo ,vol ;
	static char henka ,sokudo ,houhou,hani;
	static char time  ;
	static unsigned int shuhasu;
 
	if (! init) {
		top     = 0;
		duty    = 0;
		counter = 0;
		onkyo   = 0;
		vol     = 0;
		henka   = 0;
		sokudo  = 0;
		houhou  = 0;
		hani    = 0;
		time    = 0;
		shuhasu = 0;
 
		ClearScreen();
 
		DrawString( 5, 3,"DUTY"       , 4);
		DrawString( 5, 5,"COUNTER"    , 7);
		DrawString( 5, 7,"ONKYO"      , 5);
		DrawString( 5, 9,"VOLUME"     , 6);
		DrawString( 5,11,"HENKA"      , 5);
		DrawString( 5,13,"SOKUDO"     , 6);
		DrawString( 5,15,"HOUHOU"     , 6);
		DrawString( 5,17,"HANI"       , 4);
		DrawString( 5,19,"SHUHASU"    , 7);
		DrawString( 5,21,"TIME"       , 4);
		DrawString( 7,26,"PUSH START" ,10);
		DrawString(17,26," TO PLAY"   , 9);
 
		init = 1;
	}
 
	if ( ButtonDown(0, BTN_UP  ) && top > 0) { top--; }
	if ( ButtonDown(0, BTN_DOWN) && top < 9) { top++; }
 
	DrawArrow(top);
 
	switch (top) {
	case 0:
		if ( ButtonDown(0, BTN_RIGHT ) && duty < 3 ) { duty++; }
		if ( ButtonDown(0, BTN_LEFT  ) && duty > 0 ) { duty--; }
		break;
	case 1:
		if ( ButtonDown(0, BTN_RIGHT ) ) { counter = 1; }
		if ( ButtonDown(0, BTN_LEFT  ) ) { counter = 0; }
		break;
	case 2:
		if ( ButtonDown(0, BTN_RIGHT ) ) { onkyo = 1; }
		if ( ButtonDown(0, BTN_LEFT  ) ) { onkyo = 0; }
		break;
	case 3:
		if ( ButtonDown(0, BTN_RIGHT ) && vol < 15 ) { vol++; }
		if ( ButtonDown(0, BTN_LEFT  ) && vol >  0 ) { vol--; }
		break;
	case 4:
		if ( ButtonDown(0, BTN_RIGHT ) ) { henka = 1; }
		if ( ButtonDown(0, BTN_LEFT  ) ) { henka = 0; }
		break;
	case 5:
		if ( ButtonDown(0, BTN_RIGHT ) && sokudo <  7 ) { sokudo++; }
		if ( ButtonDown(0, BTN_LEFT  ) && sokudo >  0 ) { sokudo--; }
		break;
	case 6:
		if ( ButtonDown(0, BTN_RIGHT ) ) { houhou = 1; }
		if ( ButtonDown(0, BTN_LEFT  ) ) { houhou = 0; }
		break;
	case 7:
		if ( ButtonDown(0, BTN_RIGHT ) && hani <  7 ) { hani++; }
		if ( ButtonDown(0, BTN_LEFT  ) && hani >  0 ) { hani--; }
		break;
	case 8:
		if        ( ButtonDown(0, BTN_SELECT) && ButtonDown(0, BTN_RIGHT ) ) {
			shuhasu+=1000;
		} else if ( ButtonDown(0, BTN_SELECT) && ButtonDown(0, BTN_LEFT  ) && shuhasu >= 1000 ) {
			shuhasu-=1000;
		} else if ( ButtonDown(0, BTN_B     ) && ButtonDown(0, BTN_RIGHT ) ) {
			shuhasu+=100;
		} else if ( ButtonDown(0, BTN_B     ) && ButtonDown(0, BTN_LEFT  ) && shuhasu >= 100 ) {
			shuhasu-=100;
		} else if ( ButtonDown(0, BTN_A     ) && ButtonDown(0, BTN_RIGHT ) ) {
			shuhasu+=10;
		} else if ( ButtonDown(0, BTN_A     ) && ButtonDown(0, BTN_LEFT  ) && shuhasu >= 10 ) {
			shuhasu-=10;
		} else if ( ButtonDown(0, BTN_RIGHT ) ) {
			shuhasu+=1;
		} else if ( ButtonDown(0, BTN_LEFT  ) && shuhasu >= 1 ) {
			shuhasu-=1;
		}
		break;
	case 9:
		if ( ButtonDown(0, BTN_RIGHT ) && time < 63 ) { time++; }
		if ( ButtonDown(0, BTN_LEFT  ) && time >  0 ) { time--; }
		break;
	}
 
	if ( ButtonPush(0, BTN_START) ) {
		flag1  = duty    << 6;
		flag1 |= counter << 5;
		flag1 |= onkyo   << 4;
		flag1 |= vol;
 
		flag2  = henka   << 7;
		flag2 |= sokudo  << 4;
		flag2 |= houhou  << 3;
		flag2 |= hani;
 
		SetChannel(0x00);
		SetSquare(0,flag1,flag2);
		SetChannel(0x01);
		PlaySquare(0,shuhasu,time);
 
		DrawHexdecimal(12, 23, flag1);
		DrawHexdecimal(18, 23, flag2 );
	}
 
	DrawNumMax(19, 3, duty   , 3);
	DrawNumMax(19, 5, counter, 1);
	DrawNumMax(19, 7, onkyo  , 1);
	DrawNumMax(19, 9, vol    ,15);
	DrawNumMax(19,11, henka  , 1);
	DrawNumMax(19,13, sokudo , 7);
	DrawNumMax(19,15, houhou , 1);
	DrawNumMax(19,17, hani   , 7);
	DrawNumber(19,19, shuhasu   );
	DrawNumMax(19,21, time   ,63);
 
	VBlank();
	SendDMA(7);
}
 
void Triangle()
{
	static char top;
	static char counter;
	static char length ,time;
	static unsigned int shuhasu;
	char flag;
 
	if (! init) {
		top     = 0;
		counter = 0;
		length  = 0;
		time    = 0;
		shuhasu = 0;
 
		ClearScreen();
 
		DrawString( 5, 3,"COUNTER"    , 7);
		DrawString( 5, 5,"LENGTH"     , 6);
		DrawString( 5, 7,"TIME"       , 4);
		DrawString( 5, 9,"SHUHASU"    , 7);
		DrawString( 7,26,"PUSH START" ,10);
		DrawString(17,26," TO PLAY"   , 9);
 
		init = 1;
	}
 
	if ( ButtonDown(0, BTN_UP  ) && top > 0) { top--; }
	if ( ButtonDown(0, BTN_DOWN) && top < 3) { top++; }
 
	DrawArrow(top);
 
	switch (top) {
	case 0:
		if ( ButtonDown(0, BTN_RIGHT ) ) { counter = 1; }
		if ( ButtonDown(0, BTN_LEFT  ) ) { counter = 0; }
		break;
	case 1:
		if ( ButtonDown(0, BTN_RIGHT ) && length < 127 ) { length++; }
		if ( ButtonDown(0, BTN_LEFT  ) && length >   0 ) { length--; }
		break;
	case 2:
		if ( ButtonDown(0, BTN_RIGHT ) && time   <  31 ) { time++; }
		if ( ButtonDown(0, BTN_LEFT  ) && time   >   0 ) { time--; }
		break;
	case 3:
		if        ( ButtonDown(0, BTN_SELECT) && ButtonDown(0, BTN_RIGHT ) ) {
			shuhasu+=1000;
		} else if ( ButtonDown(0, BTN_SELECT) && ButtonDown(0, BTN_LEFT  ) && shuhasu >= 1000 ) {
			shuhasu-=1000;
		} else if ( ButtonDown(0, BTN_B     ) && ButtonDown(0, BTN_RIGHT ) ) {
			shuhasu+=100;
		} else if ( ButtonDown(0, BTN_B     ) && ButtonDown(0, BTN_LEFT  ) && shuhasu >= 100 ) {
			shuhasu-=100;
		} else if ( ButtonDown(0, BTN_A     ) && ButtonDown(0, BTN_RIGHT ) ) {
			shuhasu+=10;
		} else if ( ButtonDown(0, BTN_A     ) && ButtonDown(0, BTN_LEFT  ) && shuhasu >= 10 ) {
			shuhasu-=10;
		} else if ( ButtonDown(0, BTN_RIGHT ) ) {
			shuhasu+=1;
		} else if ( ButtonDown(0, BTN_LEFT  ) && shuhasu >= 1 ) {
			shuhasu-=1;
		}
		break;
	}
 
	if ( ButtonPush(0, BTN_START) ) {
		flag  = counter << 7;
		flag |= length;
 
		SetChannel(0x00);
		SetTriangle(flag);
		SetChannel(0x04);
		PlayTriangle(shuhasu,time);
 
		DrawHexdecimal(15, 23, flag );
	}
 
	DrawNumMax(19, 3, counter, 1);
	DrawNumLen(19, 5, length,127);
	DrawNumMax(19, 7, time   ,31);
	DrawNumber(19, 9, shuhasu   );
 
	VBlank();
	SendDMA(7);
}
 
void Noise()
{
	static char top;
	static char counter;
	static char onkyo, volume, ransu, rate, time;
	char flag;
 
	if (! init) {
		top     = 0;
		counter = 0;
		onkyo   = 0;
		volume  = 0;
		ransu   = 0;
		rate    = 0;
		time    = 0;
 
		ClearScreen();
 
		DrawString( 5, 3,"COUNTER"    , 7);
		DrawString( 5, 5,"ONKYO"      , 5);
		DrawString( 5, 7,"VOLUME"     , 6);
		DrawString( 5, 9,"RANSU"      , 5);
		DrawString( 5,11,"RATE"       , 4);
		DrawString( 5,13,"TIME"       , 4);
		DrawString( 7,26,"PUSH START" ,10);
		DrawString(17,26," TO PLAY"   , 9);
 
		init = 1;
	}
 
	if ( ButtonDown(0, BTN_UP  ) && top > 0) { top--; }
	if ( ButtonDown(0, BTN_DOWN) && top < 5) { top++; }
 
	DrawArrow(top);
 
	switch (top) {
	case 0:
		if ( ButtonDown(0, BTN_RIGHT ) ) { counter = 1; }
		if ( ButtonDown(0, BTN_LEFT  ) ) { counter = 0; }
		break;
	case 1:
		if ( ButtonDown(0, BTN_RIGHT ) ) { onkyo = 1; }
		if ( ButtonDown(0, BTN_LEFT  ) ) { onkyo = 0; }
		break;
	case 2:
		if ( ButtonDown(0, BTN_RIGHT ) && volume < 15 ) { volume++; }
		if ( ButtonDown(0, BTN_LEFT  ) && volume >  0 ) { volume--; }
		break;
	case 3:
		if ( ButtonDown(0, BTN_RIGHT ) ) { ransu = 1; }
		if ( ButtonDown(0, BTN_LEFT  ) ) { ransu = 0; }
		break;
	case 4:
		if ( ButtonDown(0, BTN_RIGHT ) && rate <  15 ) { rate++; }
		if ( ButtonDown(0, BTN_LEFT  ) && rate >   0 ) { rate--; }
		break;
	case 5:
		if ( ButtonDown(0, BTN_RIGHT ) && time <  31 ) { time++; }
		if ( ButtonDown(0, BTN_LEFT  ) && time >   0 ) { time--; }
		break;
	}
 
	if ( ButtonPush(0, BTN_START) ) {
		flag  = counter << 5;
		flag  = onkyo   << 4;
		flag |= volume;
 
		SetChannel(0x00);
		SetNoise(flag);
 
		DrawHexdecimal(12, 23, flag );
 
		flag  = ransu << 7;
		flag |= rate;
 
		SetChannel(0x08);
		PlayNoise(flag,time);
 
		DrawHexdecimal(18, 23, flag );
	}
 
	DrawNumMax(19, 3, counter, 1);
	DrawNumMax(19, 5, onkyo  , 1);
	DrawNumMax(19, 7, volume ,15);
	DrawNumMax(19, 9, ransu  , 1);
	DrawNumMax(19,11, rate   ,15);
	DrawNumMax(19,13, time   ,31);
 
	VBlank();
	SendDMA(7);
}
 
void Title()
{
	static char top;
 
	if (! init) {
		top = 0;
 
		ClearScreen();
		SetChannel(0x00);
		DrawString( 5, 3,"SQUARE"    , 6);
		DrawString( 5, 5,"TRIANGLE"  , 8);
		DrawString( 5, 7,"NOISE"     , 5);
		init = 1;
	}
 
	if ( ButtonPush(0, BTN_UP  ) && top > 0) { top--; }
	if ( ButtonPush(0, BTN_DOWN) && top < 2) { top++; }
 
	DrawArrow(top);
	VBlank();
	SendDMA(7);
 
	if ( ButtonPush(0, BTN_A ) || ButtonPush(0, BTN_START ) ) {
		init = 0;
		switch (top) {
		case 0:
			menu = menuSQUARE;
			break;
		case 1:
			menu = menuTRIANGLE;
			break;
		case 2:
			menu = menuNOISE;
			break;
		}
	}
}
 
// メイン処理
void NesMain()
{
 
	const char palettebg[] = { 0x0f, 0x21, 0x30, 0x30, 0x0f, 0x21, 0x30, 0x30,
				   0x0f, 0x21, 0x30, 0x30, 0x0f, 0x21, 0x30, 0x30 };
	const char palettesp[] = { 0x0f, 0x21, 0x30, 0x30, 0x0f, 0x21, 0x30, 0x30,
				   0x0f, 0x21, 0x30, 0x30, 0x0f, 0x21, 0x30, 0x30 };
 
	InitPPU();
 
	SetPalette((char *)palettebg,0);
	SetPalette((char *)palettesp,1);
 
	SetPPU(0x08,0x1e);
 
	menu = menuTITLE;
 
	init = 0;
 
	while (1) {
		CheckPad();
		if ( ButtonDown(0, BTN_START) && ButtonPush(0, BTN_SELECT) ) {
			init = 0;
			menu = menuTITLE;
		}
		switch (menu) {
		case menuTITLE:
			Title();
			break;
		case menuSQUARE:
			Square();
			break;
		case menuTRIANGLE:
			Triangle();
			break;
		case menuNOISE:
			Noise();
			break;
		}
	}
}
 
//NMI割り込み
void NMIProc(void){}