/***************************************************************************

       TMENU.IF2 登録用  .FMB/.PMB 試聴プログラム  Ver 1.0

                 1990/12/01     HONESEN (自来也愛好会)

***************************************************************************/


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <egb.h>
#include <mos.h>
#include <snd.h>


#define ON	1
#define OFF	0
#define FM	0
#define PCM	64


struct	name {
	short	x, y;
	short	len;
	char	nam[9];
};


/**** BIOS ワークエリア ****/

char	eWork[1536],
	mWork[4096],
	sWork[16384];

/**** 共通変数エリア、テーブル ****/

int	ch;		/* チャンネル番号 FM:0 / PCM:64 */
struct name	tone[128],
		fsw[]  = {{0, 0, 4, "DOWN"},
		          {0, 0, 4, " UP "},
		          {0, 0, 4, "EXIT"}};

int	xy[][4] =      {{320,   8, 367,  31},		/* DOWN */
			{375,   8, 422,  31},		/*  UP  */
			{470,   8, 517,  31},		/* EXIT */
			{  0,  72, 639, 167},		/* TONE */
			{ 48, 236, 635, 315},		/* KEYh */
			{  4, 380, 591, 459}};		/* KEYl */

int	b_key[] = {12,25, 37,50, 75,88, 98,111, 121,134};
int	p_key[] = {10,20,30,40,55,70,80,92,100,115,125,140};
int	white[] = {0, 2, 4, 5, 7, 9, 11},
	black[] = {1, 3, 6, 8, 10};

int	base, offset, ch_flg, crnt_key, w_or_b;

int	cpybuf[10000];

/*------------ bload : FM/PCM 音色ファイル読み込み関数 -----------------*/

bload(path)		/* ret = 成功:0 / 失敗:1 */
char	*path;		/* ファイル名 */
{
	char	*p, dum[8];
	int	l;

	if ((l=strlen(path)) > 4) {
		p = path + l - 4;
		if (!strcmp(p,".fmb") || !strcmp(p,".FMB")) {
			if (!SND_fm_bank_load(path,dum)) {
				ch = FM;
				return(0);
			}
		}
		else if (!strcmp(p,".pmb") || !strcmp(p,".PMB")) {
			if (!SND_pcm_bank_load(path,dum)) {
				ch = PCM;
				return(0);
			}
		}
	}
	return(1);
}

/*----------- get_tname : 音色名を tone[] に読み込む関数---------*/

void get_tnam()
{
	char	buf[128], *p, *q;
	int	i;

	for (i=0; i<(ch==FM? 128: 32); i++) {
		SND_inst_read(ch, i, buf);
		buf[8] = '\0';
		tone[i].len = 0;
		p = tone[i].nam;  q = buf;
		while ((*p++=*q++) >= ' ') tone[i].len++;
		*(p-1) = '\0';
	}
}

/*------------------- box : 矩形描画関数 ------------------------*/

void box(x1, y1, x2, y2, c)
int	x1, y1, x2, y2;		/* 対角線座標 */
int	c;
{
	short	para[32];

	MOS_disp(0);
	EGB_color(eWork, 0, c); EGB_color(eWork, 2, c);
	para[0] = x1;	para[1] = y1;
	para[2] = x2;	para[3] = y2;
	EGB_rectangle(eWork, (char*)para);
	MOS_disp(1);
}

/*------------------- pset : 点描画関数 ------------------------*/

void pset(x, y, c)
int	x, y;			/* 座標 */
int	c;
{
	short	para[32];

	MOS_disp(0);
	EGB_color(eWork, 0, c);
	para[0] = 1;
	para[1] = x;	para[2] = y;
	EGB_pset(eWork, (char*)para);
	MOS_disp(1);
}

/*----------------- button : ボタンの縁取り関数 ----------------*/

void button(x1, y1, x2, y2, c1, c2)
int	x1, y1, x2, y2,		/* 対角線座標 */
	c1,			/* 左上の色 */
	c2;			/* 右下の色 */
{
	short	para[32];

	MOS_disp(0);
	EGB_color(eWork, 0, c1);
	para[0] = 3;
	para[1] = x1;	para[2] = y2;
	para[3] = x1;	para[4] = y1;
	para[5] = x2-1;	para[6] = y1;
	EGB_connect(eWork, (char*)para);

	EGB_color(eWork, 0, c2);
	para[0] = 7;
	para[1] = x2;	para[2] = y2;
	para[3] = x2;	para[4] = y1;
	para[5] = x2-1;	para[6] = y1+1;
	para[7] = x2-1;	para[8] = y2-1;
	para[9] = x1+1;	para[10] = y2-1;
	para[11] = x1+1;para[12] = y2;
	para[13] = x2;  para[14] = y2;
	EGB_connect(eWork, (char*)para);
	MOS_disp(1);
}

/*-------------- sw_on_off : ボタンのオン・オフ関数 ------------------*/

void sw_on_off(x1, y1, x2, y2, s, f1, f2)
int	x1, y1, x2, y2;		/* 対角線座標 */
struct name	*s;		/* キートップ文字列 */
int	f1, f2;			/* ON / OFF */
{
	int	c1, c2, sc;

	if (f1 == ON) {
		c1 = 8; c2 = 15; sc = 12;
	}
	else {
		c1 = 15; c2 = 8; sc = 0;
	}
	EGB_textZoom(eWork, 0, 8, 16);
	EGB_fontStyle(eWork, 0);

	if (f2) button(x1, y1, x2, y2, c1, c2);
	s->x = x1 + 8; s->y = y2 - 3;
	EGB_color(eWork, 0, sc);
	MOS_disp(0);
	EGB_sjisString(eWork, (char*)s);
	MOS_disp(1);
}

/*------------- disp_one_sw : 音色スイッチ表示関数 -----------------*/

void disp_one_sw(f1, f2)
int	f1, f2;
{
	int	x, y;

	x = (offset/4)*80 + xy[3][0] + 1;
	y = (offset%4)*24 + xy[3][1] + 1;
	box(x, y, x+75, y+19, 7);
	sw_on_off(x-1, y-1, x+77, y+21, &tone[base+offset], f1, f2);
}

/*------------- disp_all_sw : 全音色スイッチ表示関数 -----------------*/

void disp_all_sw(f2)
int	f2;
{
	int	i;
	struct name	s;

	for (offset=0; offset<32; offset++) {
		disp_one_sw(OFF, f2);
	}
	offset = 0;
	disp_one_sw(ON, 1);
	box(0, 52, 639, 71, 5);
	EGB_textZoom(eWork, 0, 8, 16);
	EGB_fontStyle(eWork, 1);
	EGB_color(eWork, 0, 3);
	s.len = 3;  s.y = 70;
	for (i=0; i<32; i+=4) {
		s.x = i * 20 + 32;
		s.nam[0] = (base+i+1)/100 + '0';
		s.nam[1] = (base+i+1)%100/10 + '0';
		s.nam[2] = (base+i+1)%10 + '0';
		MOS_disp(0);
		EGB_sjisString(eWork, (char*)&s);
		MOS_disp(1);
	}
	SND_inst_change(ch, base);  SND_inst_change(ch+1, base);
	SND_inst_change(ch+2, base);  SND_inst_change(ch+3, base);
}

/*-------------------- disp_key : 鍵盤表示 ---------------------------*/

void disp_key()
{
	short	para[32], symbuf[4];
	int	i, x, y, o;

	box(xy[4][0],xy[4][1]-20,xy[4][0]+146,xy[4][1]-1, 7);
	button(xy[4][0],xy[4][1]-20,xy[4][0]+146,xy[4][1]-1, 15, 8);
								/*白鍵*/
	MOS_disp(0);
	EGB_color(eWork, 0, 0);   EGB_color(eWork, 2, 15);
	para[0] = 6;
	para[2] = 236;	para[4] = 312;	para[6] = 315;
	para[8] = 315;	para[10] = 312;	para[12] = 236;
	for (i=xy[4][0]; i<xy[4][0]+21*7; i+=21) {
		para[1] = i;	para[3] = i;	para[5] = i+3;
		para[7] = i+17;	para[9] = i+20;	para[11] = i+20;
		EGB_polygon(eWork, (char*)para);
	}
								/*黒鍵*/
	for (i=0; i<10; i+=2) {
		x = xy[4][0] + b_key[i];
		box(x,235,x+1,283, 7);
		box(x+12,235,x+13,283, 8);
		box(x+2,284,x+11,285, 8);
		box(x+2,235,x+11,283, 0);
		pset(x+1,284,8);
		pset(x+12,284,0);
		pset(x,235,8);
	}
								/*コピー*/
	MOS_disp(0);
	*(int**)para = cpybuf;
	para[2] = 0x14;
	para[3] = xy[4][0]; para[4] = xy[4][1]-20;
	para[5] = xy[4][0]+146; para[6] = xy[4][3];
	EGB_getBlock(eWork, (char*)para);
	EGB_color(eWork, 0, 14);  EGB_color(eWork, 1, 8);
	EGB_fontStyle(eWork, 5);
	EGB_textZoom(eWork, 0, 16, 16);
	symbuf[2] = 1;
	y = xy[4][1]-20;  o = 4;
	for (x=xy[4][0]; x<xy[4][0]+21*28; x+=21*7) {
		para[3] = x;  para[4] = y;
		para[5] = x+146;  para[6] = y+99;
		EGB_putBlock(eWork, 0, (char*)para);
		symbuf[0] = x+65; symbuf[1] = y+17;
		*(char*)(symbuf+3) = o + '0';
		EGB_sjisString(eWork, (char*)symbuf);
		o++;
	}
	y = xy[5][1]-20;  o = 0;
	for (x=xy[5][0]; x<xy[5][0]+21*28; x+=21*7) {
		para[3] = x;  para[4] = y;
		para[5] = x+146;  para[6] = y+99;
		EGB_putBlock(eWork, 0, (char*)para);
		symbuf[0] = x+65; symbuf[1] = y+17;
		*(char*)(symbuf+3) = o + '0';
		EGB_sjisString(eWork, (char*)symbuf);
		o++;
	}
	MOS_disp(1);
}

/*----------------- disp_tnam : 音色ファイル名の表示 -----------------*/

void disp_tnam(nam)
char	*nam;
{
	short	para[64];

	EGB_color(eWork, 0, 1);
	EGB_fontStyle(eWork, 1);
	EGB_textZoom(eWork, 0, 8, 16);
	para[0] = 8;  para[1] = 28;
	strcpy((char*)para+6, nam);
	para[2] = strlen(nam);
	if (para[2] > 38) para[2] = 38;
	EGB_sjisString(eWork, (char*)para);
}

/*--------------- paint_key : 鍵盤ペイント関数 ------------------------*/

void paint_key(n, c)
int	n, c;
{
	short	para[32];

	para[0] = ((n >= 60)?	xy[4][0] + 21*7*((n-60)/12) + p_key[n%12]:
				xy[5][0] + 21*7*((n-12)/12) + p_key[n%12]);
	para[1] = ((n >= 60)?	xy[4][1]+2: xy[5][1]+2);
	MOS_disp(0);
	EGB_color(eWork, 2, c);
	EGB_closePaint(eWork, (char*)para);
	MOS_disp(1);
}

/*------------------ key_off : キーオフ関数 ---------------------------*/

void key_off()
{
	if (crnt_key != -1) {
		paint_key(crnt_key, w_or_b);
		SND_key_off(ch+ch_flg++);
		ch_flg &= 3;
		crnt_key = -1;
	}
}

/*------------------ key_exit : "EXIT"キー関数 -----------------------*/

void key_exit()
{
	int	b, x, y;

	key_off();
	sw_on_off(xy[2][0],xy[2][1],xy[2][2],xy[2][3],&fsw[2],ON,1);
	while (MOS_rdpos(&b,&x,&y),b);
	sw_on_off(xy[2][0],xy[2][1],xy[2][2],xy[2][3],&fsw[2],OFF,1);
}

/*------------------ key_down : "DOWN"キー関数 -----------------------*/

void key_down()
{
	int	b, x, y;

	key_off();
	sw_on_off(xy[0][0],xy[0][1],xy[0][2],xy[0][3],&fsw[0],ON,1);
	if (ch == FM) {
		if (base > 31) {
			disp_one_sw(OFF, 1);
			base -= 32;
			disp_all_sw(0);
		}
	}
	while (MOS_rdpos(&b,&x,&y),b);
	sw_on_off(xy[0][0],xy[0][1],xy[0][2],xy[0][3],&fsw[0],OFF,1);
	SND_inst_change(ch, base);  SND_inst_change(ch+1, base);
	SND_inst_change(ch+2, base);  SND_inst_change(ch+3, base);
}

/*-------------------- key_up : "UP"キー関数 -------------------------*/

void key_up()
{
	int	b, x, y;

	key_off();
	sw_on_off(xy[1][0],xy[1][1],xy[1][2],xy[1][3],&fsw[1],ON,1);
	if (ch == FM) {
		if (base < 96) {
			disp_one_sw(OFF, 1);
			base += 32;
			disp_all_sw(0);
		}
	}
	while (MOS_rdpos(&b,&x,&y),b);
	sw_on_off(xy[1][0],xy[1][1],xy[1][2],xy[1][3],&fsw[1],OFF,1);
	SND_inst_change(ch, base);  SND_inst_change(ch+1, base);
	SND_inst_change(ch+2, base);  SND_inst_change(ch+3, base);
}

/*------------ key_tchg : 音色切り替えキー関数 -----------------------*/

void key_tchg(x, y)
int	x, y;
{
	int	b, x1, y1;

	key_off();
	disp_one_sw(OFF, 1);
	offset = (x/80)*4 + (y-xy[3][1])/24;
	disp_one_sw(ON, 1);
	while (MOS_rdpos(&b,&x1,&y1),b);
	SND_inst_change(ch, base+offset);  SND_inst_change(ch+1, base+offset);
	SND_inst_change(ch+2, base+offset); SND_inst_change(ch+3, base+offset);
}

/*------------------ key_on : キーオン関数 ---------------------------*/

void key_on(x, y, o)
int	x, y, o;
{
	int	i, j, k, w;

	o += x / 147; x %= 147;
	i = white[x/21]; 
	w = 15;
	if (y < 50) {
		for (j=0; j<10&&(x<b_key[j]||b_key[j+1]<x); j+=2);
		if (j < 10) {
			i = black[j/2];
			w = 0;
		}
	}
	k = (o+1)*12 + i;
	if (crnt_key == -1) {
		SND_key_on(ch+ch_flg, k, 100);
		paint_key(k, 10);
		crnt_key = k;
		w_or_b = w;
	}
	else if (crnt_key != k ) {
		key_off();
		SND_key_on(ch+ch_flg, k, 100);
		paint_key(k, 10);
		crnt_key = k;
		w_or_b = w;
	}
}

/*--------------------- main : メイン関数 ----------------------------*/

void main(argc, argv)
int	argc;
char	*argv[];
{

	int	i, mb, mx, my;

/**** サウンド初期設定 ****/

	SND_init(sWork);
	SND_elevol_init();
	SND_elevol_mute(3);

/**** 音色ファイルの読み込み ****/

	if (argc==0 || bload(argv[1])) goto end;
	get_tnam();

/**** グラフィック初期設定 ****/

	EGB_init(eWork, 1536);
	EGB_displayPage(eWork, 0, 0);
	EGB_paintMode(eWork, 0x0022);

/**** マウス初期設定 ****/

	MOS_start(mWork, 4096);
	MOS_horizon(0, 639);
	MOS_vertical(0, 479);
	MOS_setpos(320, 240);
	MOS_disp(1);

/**** 画面初期設定 ****/
							/* 背景 */
	box(0, 0, 639, 479, 5);
							/* DOWN UP EXIT */
	for (i=0; i<3; i++) {
		box(xy[i][0], xy[i][1], xy[i][2], xy[i][3], 7);
		sw_on_off(xy[i][0], xy[i][1], xy[i][2], xy[i][3], 
							&fsw[i], OFF, 1);
	}
							/* 音色スイッチ表示 */
	base = 0;
	disp_all_sw(1);
							/* 鍵盤表示 */
	disp_key();
							/* ファイル名表示 */
	disp_tnam(argv[1]);
	EGB_displayPage(eWork, 1, 3);

/**** マウス入力ループ ****/

	crnt_key = -1;  ch_flg = 0;
	while (1) {
		while (MOS_rdpos(&mb, &mx, &my), mb==0) key_off();
		for (i=0; i<6&&(mx<xy[i][0]||xy[i][2]<mx
					||my<xy[i][1]||xy[i][3]<my); i++);
		switch (i) {
			case 0 : key_down();
				 break;
			case 1 : key_up();
				 break;
			case 2 : key_exit();
				 goto end;
			case 3 : key_tchg(mx, my);
				 break;
			case 4 : key_on(mx-xy[4][0], my-xy[4][1], 4);
				 break;
			case 5 : key_on(mx-xy[5][0], my-xy[5][1], 0);
				 break;
			default: key_off();
				 break;
		}
	}

/**** 終了 ****/
end:
	MOS_end();
	SND_elevol_mute(0);
	SND_end();
}
