/*
**	< High C V1.4  &  386ASM V2.0 >
**
**	PMBﾌｧｲﾙで音を出します。
**
**	1990.08.29 : CREATE
**	1990.08.31 : FINISH
**
**	< HISTORY >
**	1990.08.29 : CREATE
**
**	< note > : TABS = 4
**
**	Programmed by Y.Hirata ( Nifty ID : NAB03321 )
**
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <snd.h>
#include <fmc.h>
#include <dos.h>
#include <msdos.cf>
#include "pmb.h"

#define		SworkSize	16384						/*  ｻｳﾝﾄﾞ用作業域ｻｲｽﾞ	*/
char	Swork[SworkSize];							/*  ｻｳﾝﾄﾞ用作業域		*/

char	Pmbfile[128] ;								/*  PCM 音色ﾌｧｲﾙ		*/

int		Pmbsize ;									/*  PCM 音色ﾃﾞｰﾀｻｲｽﾞ	*/
char	*Pmbdata ;									/*  PCM 音色格納領域	*/
char	Pmbflg = FALSE ;							/*  PCM 音色 READ ﾌﾗｸﾞ	*/

int		Inst1 = 0 ;									/*  ｷｰﾎﾞｰﾄﾞ上段用		*/
int		Inst2 = 0 ;									/*  ｷｰﾎﾞｰﾄﾞ下段用		*/

int		Pan1 = 64 ;									/*  ｷｰﾎﾞｰﾄﾞ上段			*/
int		Pan2 = 64 ;									/*  ｷｰﾎﾞｰﾄﾞ下段			*/

int		ValNote1 = 0 ;								/*  ｷｰﾎﾞｰﾄﾞ上段音程用	*/
int		ValNote2 = 0 ;								/*  ｷｰﾎﾞｰﾄﾞ下段音程用	*/

typedef struct {
	char	_reserved[21] ;					/*  reserved area			*/
	char	_attrib ;						/*  attribute byte			*/
	ushort	_ftime ; 						/*  time of file			*/
	ushort	_fdate ;						/*  date of file			*/
	ulong	_fsize ;						/*  file size				*/
	char	d_name[13] ;					/*  packed file name		*/
} DIR ;

/*************************  ＤＴＡの設定  ************************************/
void setdta( p )
DIR *p ;
{
	Registers.AX.LH.H = 0x1a ;
	Registers.DX.R = (uint)p ;
	Registers.DS.R = getds() ;
	calldos() ;
}

/*******************  最初に一致するファイル名の検索  ************************/
int firstsearch( path,attr,dta )
char	*path ;
int		attr ;
DIR		*dta ;
{
	setdta( dta ) ;
	Registers.AX.LH.H = 0x4e ;
	Registers.CX.R = attr ;						/*  ファイルの種類	*/
	Registers.DX.R = (uint)path ;				/*  ファイル名		*/
	Registers.DS.R = getds() ;
	calldos();
	if ( (Registers.Flags & 0x0001) != 0 )
		return ( FALSE ) ;
	else
		return ( TRUE ) ;					/*  成功ならば 真 でreturn	*/
}

/***************************  ファイルサイズ取得  ****************************/
int getfsize()
{
	DIR		dta ;
	ushort	attr=0 ;

	if ( firstsearch( Pmbfile,attr,&dta ) ) {		/*  最初のエントリ	*/
		Pmbsize = dta._fsize ;
		return( dta._fsize ) ;
	} else {									/*  ファイルが見つからない	*/
		return( -1 ) ;
	}
}

/***************************  PMB DATA の読込み  *****************************/
void pmb_load()
{
	FILE *fp;

	getfsize() ;
	Pmbdata = malloc( Pmbsize ) ;				/*  PMB データ格納領域確保	*/
	if ( Pmbdata == NULL ) {
		Pmbflg = FALSE ;
		printf("<pmb_load> malloc error!\n") ;
	} else {
		fp = fopen( Pmbfile,"rb" ) ;
		fread( Pmbdata,1,Pmbsize,fp ) ;
		fclose( fp ) ;
	}
}

/******************************************************************************
	KEY_test : マトリクスからキーが押されているかどうかをチェックする。
******************************************************************************/
int		KEY_test( char *matrix, char keyadrs )
/*	*matrix : ｷｰﾏﾄﾘｸｽ情報( 16 ﾊﾞｲﾄ )										*/
/*	keyadrs : ｷｰｱﾄﾞﾚｽ														*/
{
	unsigned char	testbit ;
	int		c ;

	testbit = 0x01 ;
	for ( c=0; c<(keyadrs%8); c++ ) testbit <<= 1 ;
	if ( (matrix[keyadrs/8] & testbit) == testbit ) return( TRUE ) ;

	return( 0 ) ;
}

/****************************  1つ上の音色に変更  ****************************/
void inst_change_up( int kyb1, int kyb2 )
/*	kyb  : ｷｰﾎﾞｰﾄﾞの上/下段ﾌﾗｸﾞ												*/
{
	char	matrix[16] ;							/*  ｷｰﾏﾄﾘｸｽ取得用		*/
	char	keyrepflg ;								/*  ｷｰﾘﾋﾟｰﾄ用ﾌﾗｸﾞ		*/
	char	name[9] ;								/*  FMBｲﾝｽﾄ名			*/

	if ( !Pmbflg ) {
		printf("\x1b[33m") ;
		printf("☆☆☆  音色の変更はできません！  ☆☆☆") ;
		printf("\x1b[m\n") ;
		return ;
	}

	keyrepflg = FALSE ;								/*  ｷｰﾘﾋﾟｰﾄﾌﾗｸﾞ･ｸﾘｱ		*/
	do {

		if ( kyb1 == KYB_UPPER || kyb2 == KYB_UPPER ) {		/*  ｷｰﾎﾞｰﾄﾞ上段	*/
			if ( Inst1 == 31 )
				Inst1 = 0 ;
			else
				Inst1 ++ ;
			SND_inst_change( 64,Inst1 ) ;
			SND_inst_change( 65,Inst1 ) ;
			SND_inst_change( 66,Inst1 ) ;
			SND_inst_change( 67,Inst1 ) ;
			printf("ｷｰﾎﾞｰﾄﾞ上段の音色を変更しました。") ;
			printf("(INST:%03d)",Inst1) ;
			strncpy( name,&Pmbdata[8+Inst1*128],8 ) ;
			name[8] = '\0' ;
			printf(" < %s >\n",name) ;
		}

		if ( kyb1 == KYB_LOWER || kyb2 == KYB_LOWER ) {		/*  ｷｰﾎﾞｰﾄﾞ下段	*/
			if ( Inst2 == 31 )
				Inst2 = 0 ;
			else
				Inst2 ++ ;
			SND_inst_change( 68,Inst2 ) ;
			SND_inst_change( 69,Inst2 ) ;
			SND_inst_change( 70,Inst2 ) ;
			SND_inst_change( 71,Inst2 ) ;
			printf("ｷｰﾎﾞｰﾄﾞ下段の音色を変更しました。") ;
			printf("(INST:%03d)",Inst2) ;
			strncpy( name,&Pmbdata[8+Inst2*128],8 ) ;
			name[8] = '\0' ;
			printf(" < %s >\n",name) ;
		}

		if ( keyrepflg ) {
			SOFT_timer( KEY_repeat ) ;
		} else {
			SOFT_timer( KEY_wait ) ;
			keyrepflg = TRUE ;
		}

	 	KYB_clrbuf() ;								/*  ｷｰﾊﾞｯﾌｧ･ｸﾘｱ			*/
		KYB_matrix( matrix ) ;						/*  ｷｰﾏﾄﾘｸｽ取得			*/

	} while ( KEY_test( matrix,KEY_UP ) ) ;

	printf("\n") ;
}

/****************************  1つ下の音色に変更  ****************************/
void inst_change_down( int kyb1, int kyb2 )
/*	kyb  : ｷｰﾎﾞｰﾄﾞの上/下段ﾌﾗｸﾞ												*/
{
	char	matrix[16] ;							/*  ｷｰﾏﾄﾘｸｽ取得用		*/
	char	keyrepflg ;								/*  ｷｰﾘﾋﾟｰﾄ用ﾌﾗｸﾞ		*/
	char	name[9] ;								/*  FMBｲﾝｽﾄ名			*/

	if ( !Pmbflg ) {
		printf("\x1b[33m") ;
		printf("☆☆☆  音色の変更はできません！  ☆☆☆") ;
		printf("\x1b[m\n") ;
		return ;
	}

	keyrepflg = FALSE ;								/*  ｷｰﾘﾋﾟｰﾄﾌﾗｸﾞ･ｸﾘｱ		*/
	do {

		if ( kyb1 == KYB_UPPER || kyb2 == KYB_UPPER ) {		/*  ｷｰﾎﾞｰﾄﾞ上段	*/
			if ( Inst1 == 0 )
				Inst1 = 31 ;
			else
				Inst1 -- ;
			SND_inst_change( 64,Inst1 ) ;
			SND_inst_change( 65,Inst1 ) ;
			SND_inst_change( 66,Inst1 ) ;
			SND_inst_change( 67,Inst1 ) ;
			printf("ｷｰﾎﾞｰﾄﾞ上段の音色を変更しました。") ;
			printf("(INST:%03d)",Inst1) ;
			strncpy( name,&Pmbdata[8+Inst1*128],8 ) ;
			name[8] = '\0' ;
			printf(" < %s >\n",name) ;
		}

		if ( kyb1 == KYB_LOWER || kyb2 == KYB_LOWER ) {		/*  ｷｰﾎﾞｰﾄﾞ下段	*/
			if ( Inst2 == 0 )
				Inst2 = 31 ;
			else
				Inst2 -- ;
			SND_inst_change( 68,Inst2 ) ;
			SND_inst_change( 69,Inst2 ) ;
			SND_inst_change( 70,Inst2 ) ;
			SND_inst_change( 71,Inst2 ) ;
			printf("ｷｰﾎﾞｰﾄﾞ下段の音色を変更しました。") ;
			printf("(INST:%03d)",Inst2) ;
			strncpy( name,&Pmbdata[8+Inst2*128],8 ) ;
			name[8] = '\0' ;
			printf(" < %s >\n",name) ;
		}

		if ( keyrepflg ) {
			SOFT_timer( KEY_repeat ) ;
		} else {
			SOFT_timer( KEY_wait ) ;
			keyrepflg = TRUE ;
		}

	 	KYB_clrbuf() ;								/*  ｷｰﾊﾞｯﾌｧ･ｸﾘｱ			*/
		KYB_matrix( matrix ) ;						/*  ｷｰﾏﾄﾘｸｽ取得			*/

	} while ( KEY_test( matrix,KEY_DOWN ) ) ;

	printf("\n") ;
}

/***************************  1つ右に音源定位変更  ***************************/
void pan_change_right( int kyb1, int kyb2 )
/*	kyb  : ｷｰﾎﾞｰﾄﾞの上/下段ﾌﾗｸﾞ												*/
{
	char	matrix[16] ;							/*  ｷｰﾏﾄﾘｸｽ取得用		*/
	char	keyrepflg ;								/*  ｷｰﾘﾋﾟｰﾄ用ﾌﾗｸﾞ		*/

	keyrepflg = FALSE ;								/*  ｷｰﾘﾋﾟｰﾄﾌﾗｸﾞ･ｸﾘｱ		*/
	do {

		if ( kyb1 == KYB_UPPER || kyb2 == KYB_UPPER ) {		/*  ｷｰﾎﾞｰﾄﾞ上段	*/
			if ( Pan1 < 127 ) {
				if ( Pan1 == 96 ) {
					Pan1 = 127 ;
				} else {
					Pan1 += 32 ;
				}
				/*  PCM 音源の場合 :
　					000〜007, 008〜015, 016〜023, 024〜031, 032〜039,
					040〜047, 048〜055, 056〜071, 072〜079, 080〜087,
					088〜095, 096〜103, 104〜111, 112〜119, 120〜127
					の 15段階設定可能										*/
				/*  しかし、ここでは 5段階にしている。						*/
				SND_pan_set( 64,Pan1 ) ;
				SND_pan_set( 65,Pan1 ) ;
				SND_pan_set( 66,Pan1 ) ;
				SND_pan_set( 67,Pan1 ) ;
				if ( Pan1 == 64 ) {
					printf("\x1b[36m") ;
					printf("ｷｰﾎﾞｰﾄﾞ上段の音源定位を中央に変更しました。  ") ;
					printf("\x1b[m") ;
				} else {
					printf("ｷｰﾎﾞｰﾄﾞ上段の音源定位を右よりに変更しました。") ;
				}
				printf("(PAN:%d)\n",Pan1) ;
			} else {
				printf("\x1b[33m") ;
				printf("ｷｰﾎﾞｰﾄﾞ上段の音源定位は、右いっぱいです。") ;
				printf("\x1b[m") ;
				printf("(PAN:%d)\n",Pan1) ;
			}
		}

		if ( kyb1 == KYB_LOWER || kyb2 == KYB_LOWER ) {		/*  ｷｰﾎﾞｰﾄﾞ下段	*/
			if ( Pan2 < 127 ) {
				if ( Pan2 == 96 ) {
					Pan2 = 127 ;
				} else {
					Pan2 += 32 ;
				}
				/*  PCM 音源の場合 :
　					000〜007, 008〜015, 016〜023, 024〜031, 032〜039,
					040〜047, 048〜055, 056〜071, 072〜079, 080〜087,
					088〜095, 096〜103, 104〜111, 112〜119, 120〜127
					の 15段階設定可能										*/
				/*  しかし、ここでは 5段階にしている。						*/
				SND_pan_set( 68,Pan2 ) ;
				SND_pan_set( 69,Pan2 ) ;
				SND_pan_set( 70,Pan2 ) ;
				SND_pan_set( 71,Pan2 ) ;
				if ( Pan2 == 64 ) {
					printf("\x1b[36m") ;
					printf("ｷｰﾎﾞｰﾄﾞ下段の音源定位を中央に変更しました。  ") ;
					printf("\x1b[m") ;
				} else {
					printf("ｷｰﾎﾞｰﾄﾞ下段の音源定位を右よりに変更しました。") ;
				}
				printf("(PAN:%d)\n",Pan2) ;
			} else {
				printf("\x1b[33m") ;
				printf("ｷｰﾎﾞｰﾄﾞ下段の音源定位は、右いっぱいです。") ;
				printf("\x1b[m") ;
				printf("(PAN:%d)\n",Pan2) ;
			}
		}

		if ( keyrepflg ) {
			SOFT_timer( KEY_repeat ) ;
		} else {
			SOFT_timer( KEY_wait ) ;
			keyrepflg = TRUE ;
		}

	 	KYB_clrbuf() ;								/*  ｷｰﾊﾞｯﾌｧ･ｸﾘｱ			*/
		KYB_matrix( matrix ) ;						/*  ｷｰﾏﾄﾘｸｽ取得			*/

	} while ( KEY_test( matrix,KEY_RIGHT ) ) ;

	printf("\n") ;
}

/***************************  1つ左に音源定位変更  ***************************/
void pan_change_left( int kyb1, int kyb2 )
/*	kyb  : ｷｰﾎﾞｰﾄﾞの上/下段ﾌﾗｸﾞ												*/
{
	char	matrix[16] ;							/*  ｷｰﾏﾄﾘｸｽ取得用		*/
	char	keyrepflg ;								/*  ｷｰﾘﾋﾟｰﾄ用ﾌﾗｸﾞ		*/

	keyrepflg = FALSE ;								/*  ｷｰﾘﾋﾟｰﾄﾌﾗｸﾞ･ｸﾘｱ		*/
	do {

		if ( kyb1 == KYB_UPPER || kyb2 == KYB_UPPER ) {		/*  ｷｰﾎﾞｰﾄﾞ上段	*/
			if ( Pan1 > 0 ) {
				if ( Pan1 == 127 ) {
					Pan1 = 96 ;
				} else {
					Pan1 -= 32 ;
				}
				/*  PCM 音源の場合 :
　					000〜007, 008〜015, 016〜023, 024〜031, 032〜039,
					040〜047, 048〜055, 056〜071, 072〜079, 080〜087,
					088〜095, 096〜103, 104〜111, 112〜119, 120〜127
					の 15段階設定可能										*/
				/*  しかし、ここでは 5段階にしている。						*/
				SND_pan_set( 64,Pan1 ) ;
				SND_pan_set( 65,Pan1 ) ;
				SND_pan_set( 66,Pan1 ) ;
				SND_pan_set( 67,Pan1 ) ;
				if ( Pan1 == 64 ) {
					printf("\x1b[36m") ;
					printf("ｷｰﾎﾞｰﾄﾞ上段の音源定位を中央に変更しました。  ") ;
					printf("\x1b[m") ;
				} else {
					printf("ｷｰﾎﾞｰﾄﾞ上段の音源定位を左よりに変更しました。") ;
				}
				printf("(PAN:%d)\n",Pan1) ;
			} else {
				printf("\x1b[33m") ;
				printf("ｷｰﾎﾞｰﾄﾞ上段の音源定位は、左いっぱいです。") ;
				printf("\x1b[m") ;
				printf("(PAN:%d)\n",Pan1) ;
			}
		}

		if ( kyb1 == KYB_LOWER || kyb2 == KYB_LOWER ) {		/*  ｷｰﾎﾞｰﾄﾞ下段	*/
			if ( Pan2 > 0 ) {
				if ( Pan2 == 127 ) {
					Pan2 = 96 ;
				} else {
					Pan2 -= 32 ;
				}
				/*  PCM 音源の場合 :
　					000〜007, 008〜015, 016〜023, 024〜031, 032〜039,
					040〜047, 048〜055, 056〜071, 072〜079, 080〜087,
					088〜095, 096〜103, 104〜111, 112〜119, 120〜127
					の 15段階設定可能										*/
				/*  しかし、ここでは 5段階にしている。						*/
				SND_pan_set( 68,Pan2 ) ;
				SND_pan_set( 69,Pan2 ) ;
				SND_pan_set( 70,Pan2 ) ;
				SND_pan_set( 71,Pan2 ) ;
				if ( Pan2 == 64 ) {
					printf("\x1b[36m") ;
					printf("ｷｰﾎﾞｰﾄﾞ下段の音源定位を中央に変更しました。  ") ;
					printf("\x1b[m") ;
				} else {
					printf("ｷｰﾎﾞｰﾄﾞ下段の音源定位を左よりに変更しました。") ;
				}
				printf("(PAN:%d)\n",Pan2) ;
			} else {
				printf("\x1b[33m") ;
				printf("ｷｰﾎﾞｰﾄﾞ下段の音源定位は、左いっぱいです。") ;
				printf("\x1b[m") ;
				printf("(PAN:%d)\n",Pan2) ;
			}

		}

		if ( keyrepflg ) {
			SOFT_timer( KEY_repeat ) ;
		} else {
			SOFT_timer( KEY_wait ) ;
			keyrepflg = TRUE ;
		}

	 	KYB_clrbuf() ;								/*  ｷｰﾊﾞｯﾌｧ･ｸﾘｱ			*/
		KYB_matrix( matrix ) ;						/*  ｷｰﾏﾄﾘｸｽ取得			*/

	} while ( KEY_test( matrix,KEY_LEFT ) ) ;

	printf("\n") ;
}

/*******************************  初期設定  **********************************/
void init()
{
	char	bankname[8] ;
	char	name[9] ;
	int		ret ;

	printf("\nｷｰﾎﾞｰﾄﾞを操作すると、PMB ﾌｧｲﾙの音色で演奏できます♪\n") ;

	printf("\n８重和音まで対応しています♪\n") ;
	printf("ｶｰｿﾙｷｰの上下で音色を変更できます♪") ;
	printf(" ( SHIFT+ で上段のみ, CTRL+ で下段のみ )\n") ;
	printf("ｶｰｿﾙｷｰの右左で定位を変更できます♪") ;
	printf(" ( SHIFT+ で上段のみ, CTRL+ で下段のみ )\n") ;
	printf("PFｷｰで、音程を変更できます♪ ( PF1 〜 PF9 : PF5 が標準 )\n") ;
	printf("取消ｷｰで、全ての発音を停止できます。\n") ;
	printf("終了は、") ;
	printf("\x1b[36mBREAKｷｰ\x1b[m") ;
	printf(" です！\n") ;

	SND_init( Swork ) ;								/*  ｻｳﾝﾄﾞ初期化			*/

	ret = SND_pcm_bank_load( Pmbfile,bankname ) ;	/*  PCMﾊﾞﾝｸﾛｰﾄﾞ			*/
	switch ( ret ) {
		case 0 :
			printf("\nPCM 音源の音色は、") ;
			printf("\x1b[36m%s \x1b[m",Pmbfile) ;
			printf("のデータを使用します。\n") ;
			pmb_load() ;
			Pmbflg = TRUE ;
			break ;
		case 1 :
			printf("\nPMBﾌｧｲﾙ") ;
			printf(" < \x1b[33m%s\x1b[m > ",Pmbfile) ;
			printf("が見つかりません！\n") ;
			printf("\x1b[33m") ;
			printf("☆☆☆  強制終了します！  ☆☆☆") ;
			printf("\x1b[m\n") ;
			break ;
		case 2 :
			printf("\nPMBﾌｧｲﾙ") ;
			printf(" < \x1b[33m%s\x1b[m > ",Pmbfile) ;
			printf("の読み込みに失敗しました！\n") ;
			printf("\x1b[33m") ;
			printf("☆☆☆  強制終了します！  ☆☆☆") ;
			printf("\x1b[m\n") ;
			break ;
		default :
			printf("\n\x1b[31m") ;
			printf("ERROR \x1b[m: SND_pcm_bank_load = %d\n",ret) ;
	}
	printf("\n") ;

/*
**	PCM 各ﾁｬﾝﾈﾙの音色を初期設定する
*/
	SND_inst_change( 64,0 ) ;
	SND_inst_change( 65,0 ) ;
	SND_inst_change( 66,0 ) ;
	SND_inst_change( 67,0 ) ;
	SND_inst_change( 68,0 ) ;
	SND_inst_change( 69,0 ) ;
	SND_inst_change( 70,0 ) ;
	SND_inst_change( 71,0 ) ;

	SND_elevol_mute( 0x0001 ) ;						/*  PCM 音源のみﾐｭｰﾄ解除*/
	SND_elevol_all_mute( -1 ) ;						/*  全ﾐｭｰﾄの解除		*/

	KYB_clic( 1 ) ;									/*  ｷｰｸﾘｯｸ音なし		*/

	if ( Pmbflg ) {
		printf("ｷｰﾎﾞｰﾄﾞ上段の音色は、") ;
		strncpy( name,&Pmbdata[8],8 ) ;
		name[8] = '\0' ;
		printf(" < %s > ",name) ;
		printf("(INST:000) です♪\n") ;
		printf("ｷｰﾎﾞｰﾄﾞ下段の音色は、") ;
		strncpy( name,&Pmbdata[8],8 ) ;
		name[8] = '\0' ;
		printf(" < %s > ",name) ;
		printf("(INST:000) です♪\n") ;

		printf("\n'\x1b[36mド\x1b[m' (C=60) の位置は、") ;
		printf("\x1b[36mW\x1b[m と \x1b[36m>\x1b[m です♪\n") ;
		printf("\n") ;
	}

}

/*************************  ｷｰﾎﾞｰﾄﾞ操作による音制御  *************************/
void key_play( char *matrix, char keyadrs )
/*	*matrix : ｷｰﾏﾄﾘｸｽ情報( 16 ﾊﾞｲﾄ )										*/
/*	keyadrs : ｷｰｱﾄﾞﾚｽ														*/
{
	/*  PCM のﾁｬﾝﾈﾙは 64 〜 71	*/
	static int	chan1=64 ;							/*  ｷｰﾎﾞｰﾄﾞ上段のﾁｬﾝﾈﾙ	*/
	static int	chan2=68 ;							/*  ｷｰﾎﾞｰﾄﾞ下段のﾁｬﾝﾈﾙ	*/
	static int	channel[128] ;						/*  各ｷｰでのON時FMﾁｬﾝﾈﾙ	*/
	static char	keymake[128] = {					/*  ｷｰ MAKE 状態か？	*/
							0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
							0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
							0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
							0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
							0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
							0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
							0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
							0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
								} ;
	int		ret ;

	if ( chan1 > 67 ) chan1 = 64 ;
	if ( chan2 > 71 ) chan2 = 68 ;

	if ( Key_inf[keyadrs] == KYB_UPPER ) {			/*  ｷｰﾎﾞｰﾄﾞ 上段		*/
		if ( KEY_test( matrix,keyadrs ) ) {			/*  ｷｰ MAKE				*/
			if ( !keymake[keyadrs] ) {				/*  ｷｰ BREAK -> MAKE	*/
				SND_key_off( chan1 ) ;
				ret = SND_key_on( chan1,Key_note[keyadrs]+ValNote1,127 ) ;
				if ( ret ) {
					if ( Key_note[keyadrs]+ValNote1 > 60 ) {
						printf("音が高すぎて発音できません。(NOTE=%d)\n",
							Key_note[keyadrs]+ValNote1) ;
					} else {
						printf("音が低すぎて発音できません。(NOTE=%d)\n",
							Key_note[keyadrs]+ValNote1) ;
					}
				} else {
					channel[keyadrs] = chan1 ;
					chan1 ++ ;
					keymake[keyadrs] = TRUE ;
				}
			}
		} else if ( keymake[keyadrs] ) {		/*  ｷｰ BREAK		*/
			SND_key_off( channel[keyadrs] ) ;
			keymake[keyadrs] = FALSE ;
		}
	} else if ( Key_inf[keyadrs] == KYB_LOWER ) {	/*  ｷｰﾎﾞｰﾄﾞ 下段		*/
		if ( KEY_test( matrix,keyadrs ) ) {			/*  ｷｰ MAKE				*/
			if ( !keymake[keyadrs] ) {				/*  ｷｰ BREAK -> MAKE	*/
				SND_key_off( chan2 ) ;
				ret = SND_key_on( chan2,Key_note[keyadrs]+ValNote2,127 ) ;
				if ( ret ) {
					if ( Key_note[keyadrs]+ValNote2 > 60 ) {
						printf("音が高すぎて発音できません。(NOTE=%d)\n",
							Key_note[keyadrs]+ValNote2) ;
					} else {
						printf("音が低すぎて発音できません。(NOTE=%d)\n",
							Key_note[keyadrs]+ValNote2) ;
					}
				} else {
					channel[keyadrs] = chan2 ;
					chan2 ++ ;
					keymake[keyadrs] = TRUE ;
				}
			}
		} else if ( keymake[keyadrs] ) {		/*  ｷｰ BREAK		*/
			SND_key_off( channel[keyadrs] ) ;
			keymake[keyadrs] = FALSE ;
		}
	}

}

/*******************************  音程の変更  ********************************/
void note_change( char *matrix )
/*	*matrix : ｷｰﾏﾄﾘｸｽ情報( 16 ﾊﾞｲﾄ )										*/
{
	if ( KEY_test( matrix,KEY_PF1 ) ) {
		if ( KEY_test( matrix,KEY_SHIFT ) ||
			( !KEY_test( matrix,KEY_SHIFT ) &&
				 !KEY_test( matrix,KEY_CTRL ) ) ) {
			ValNote1 = -48 ;
			printf("ｷｰﾎﾞｰﾄﾞ上段の音程を標準より４つ下げました。(C=12)\n") ;
		}

		if ( KEY_test( matrix,KEY_CTRL ) ||
			( !KEY_test( matrix,KEY_SHIFT ) &&
				 !KEY_test( matrix,KEY_CTRL ) ) ) {
			ValNote2 = -48 ;
			printf("ｷｰﾎﾞｰﾄﾞ下段の音程を標準より４つ下げました。(C=12)\n") ;
		}

		printf("\n") ;

	} else if ( KEY_test( matrix,KEY_PF2 ) ) {
		if ( KEY_test( matrix,KEY_SHIFT ) ||
			( !KEY_test( matrix,KEY_SHIFT ) &&
				 !KEY_test( matrix,KEY_CTRL ) ) ) {
			ValNote1 = -36 ;
			printf("ｷｰﾎﾞｰﾄﾞ上段の音程を標準より３つ下げました。(C=24)\n") ;
		}

		if ( KEY_test( matrix,KEY_CTRL ) ||
			( !KEY_test( matrix,KEY_SHIFT ) &&
				 !KEY_test( matrix,KEY_CTRL ) ) ) {
			ValNote2 = -36 ;
			printf("ｷｰﾎﾞｰﾄﾞ下段の音程を標準より３つ下げました。(C=24)\n") ;
		}

		printf("\n") ;

	} else if ( KEY_test( matrix,KEY_PF3 ) ) {
		if ( KEY_test( matrix,KEY_SHIFT ) ||
			( !KEY_test( matrix,KEY_SHIFT ) &&
				 !KEY_test( matrix,KEY_CTRL ) ) ) {
			ValNote1 = -24 ;
			printf("ｷｰﾎﾞｰﾄﾞ上段の音程を標準より２つ下げました。(C=36)\n") ;
		}

		if ( KEY_test( matrix,KEY_CTRL ) ||
			( !KEY_test( matrix,KEY_SHIFT ) &&
				 !KEY_test( matrix,KEY_CTRL ) ) ) {
			ValNote2 = -24 ;
			printf("ｷｰﾎﾞｰﾄﾞ下段の音程を標準より２つ下げました。(C=36)\n") ;
		}

		printf("\n") ;

	} else if ( KEY_test( matrix,KEY_PF4 ) ) {
		if ( KEY_test( matrix,KEY_SHIFT ) ||
			( !KEY_test( matrix,KEY_SHIFT ) &&
				 !KEY_test( matrix,KEY_CTRL ) ) ) {
			ValNote1 = -12 ;
			printf("ｷｰﾎﾞｰﾄﾞ上段の音程を標準より１つ下げました。(C=48)\n") ;
		}

		if ( KEY_test( matrix,KEY_CTRL ) ||
			( !KEY_test( matrix,KEY_SHIFT ) &&
				 !KEY_test( matrix,KEY_CTRL ) ) ) {
			ValNote2 = -12 ;
			printf("ｷｰﾎﾞｰﾄﾞ下段の音程を標準より１つ下げました。(C=48)\n") ;
		}

		printf("\n") ;

	} else if ( KEY_test( matrix,KEY_PF5 ) ) {
		if ( KEY_test( matrix,KEY_SHIFT ) ||
			( !KEY_test( matrix,KEY_SHIFT ) &&
				 !KEY_test( matrix,KEY_CTRL ) ) ) {
			ValNote1 = 0 ;
			printf("\x1b[36m") ; 
			printf("ｷｰﾎﾞｰﾄﾞ上段の音程を標準にしました♪\x1b[m(C=60)\n") ;
		}

		if ( KEY_test( matrix,KEY_CTRL ) ||
			( !KEY_test( matrix,KEY_SHIFT ) &&
				 !KEY_test( matrix,KEY_CTRL ) ) ) {
			ValNote2 = 0 ;
			printf("\x1b[36m") ; 
			printf("ｷｰﾎﾞｰﾄﾞ下段の音程を標準にしました♪\x1b[m(C=60)\n") ;
		}

		printf("\n") ;

	} else if ( KEY_test( matrix,KEY_PF6 ) ) {
		if ( KEY_test( matrix,KEY_SHIFT ) ||
			( !KEY_test( matrix,KEY_SHIFT ) &&
				 !KEY_test( matrix,KEY_CTRL ) ) ) {
			ValNote1 = 12 ;
			printf("ｷｰﾎﾞｰﾄﾞ上段の音程を標準より１つ上げました。(C=72)\n") ;
		}

		if ( KEY_test( matrix,KEY_CTRL ) ||
			( !KEY_test( matrix,KEY_SHIFT ) &&
				 !KEY_test( matrix,KEY_CTRL ) ) ) {
			ValNote2 = 12 ;
			printf("ｷｰﾎﾞｰﾄﾞ下段の音程を標準より１つ上げました。(C=72)\n") ;
		}

		printf("\n") ;

	} else if ( KEY_test( matrix,KEY_PF7 ) ) {
		if ( KEY_test( matrix,KEY_SHIFT ) ||
			( !KEY_test( matrix,KEY_SHIFT ) &&
				 !KEY_test( matrix,KEY_CTRL ) ) ) {
			ValNote1 = 24 ;
			printf("ｷｰﾎﾞｰﾄﾞ上段の音程を標準より２つ上げました。(C=84)\n") ;
		}

		if ( KEY_test( matrix,KEY_CTRL ) ||
			( !KEY_test( matrix,KEY_SHIFT ) &&
				 !KEY_test( matrix,KEY_CTRL ) ) ) {
			ValNote2 = 24 ;
			printf("ｷｰﾎﾞｰﾄﾞ下段の音程を標準より２つ上げました。(C=84)\n") ;
		}

		printf("\n") ;

	} else if ( KEY_test( matrix,KEY_PF8 ) ) {
		if ( KEY_test( matrix,KEY_SHIFT ) ||
			( !KEY_test( matrix,KEY_SHIFT ) &&
				 !KEY_test( matrix,KEY_CTRL ) ) ) {
			ValNote1 = 36 ;
			printf("ｷｰﾎﾞｰﾄﾞ上段の音程を標準より３つ上げました。(C=96)\n") ;
		}

		if ( KEY_test( matrix,KEY_CTRL ) ||
			( !KEY_test( matrix,KEY_SHIFT ) &&
				 !KEY_test( matrix,KEY_CTRL ) ) ) {
			ValNote2 = 36 ;
			printf("ｷｰﾎﾞｰﾄﾞ下段の音程を標準より３つ上げました。(C=96)\n") ;
		}

		printf("\n") ;

	} else if ( KEY_test( matrix,KEY_PF9 ) ) {
		if ( KEY_test( matrix,KEY_SHIFT ) ||
			( !KEY_test( matrix,KEY_SHIFT ) &&
				 !KEY_test( matrix,KEY_CTRL ) ) ) {
			ValNote1 = 48 ;
			printf("ｷｰﾎﾞｰﾄﾞ上段の音程を標準より４つ上げました。(C=108)\n") ;
		}

		if ( KEY_test( matrix,KEY_CTRL ) ||
			( !KEY_test( matrix,KEY_SHIFT ) &&
				 !KEY_test( matrix,KEY_CTRL ) ) ) {
			ValNote2 = 48 ;
			printf("ｷｰﾎﾞｰﾄﾞ下段の音程を標準より４つ上げました。(C=108)\n") ;
		}

		printf("\n") ;

	}

}

/********************************  ﾌﾟﾚｲ開始  *********************************/
void play_start()
{
	char	matrix[16] ;							/*  ｷｰﾏﾄﾘｸｽ取得用		*/
	int		c ;

/*
**	ｷｰ操作開始
*/
	do {

	 	KYB_clrbuf() ;								/*  ｷｰﾊﾞｯﾌｧ･ｸﾘｱ			*/
		KYB_matrix( matrix ) ;						/*  ｷｰﾏﾄﾘｸｽ取得			*/

/*
**	音色の変更( 1つ上の音色 )
*/
		if ( KEY_test( matrix,KEY_UP ) ) {
		
			if ( KEY_test( matrix,KEY_SHIFT ) ) {			/*  ｷｰﾎﾞｰﾄﾞ上段	*/
				inst_change_up( KYB_UPPER,KYB_DUMMY ) ;
			}
			if ( KEY_test( matrix,KEY_CTRL ) ) {			/*  ｷｰﾎﾞｰﾄﾞ下段	*/
				inst_change_up( KYB_DUMMY,KYB_LOWER ) ;
			}
			if ( !KEY_test( matrix,KEY_SHIFT ) &&
					!KEY_test( matrix,KEY_CTRL ) ) {		/*  上下段とも	*/
				inst_change_up( KYB_UPPER,KYB_LOWER ) ;
			}

/*
**	音色の変更( 1つ下の音色 )
*/
		} else if ( KEY_test( matrix,KEY_DOWN ) ) {

			if ( KEY_test( matrix,KEY_SHIFT ) ) {			/*  ｷｰﾎﾞｰﾄﾞ上段	*/
				inst_change_down( KYB_UPPER,KYB_DUMMY ) ;
			}
			if ( KEY_test( matrix,KEY_CTRL ) ) {			/*  ｷｰﾎﾞｰﾄﾞ下段	*/
				inst_change_down( KYB_DUMMY,KYB_LOWER ) ;
			}
			if ( !KEY_test( matrix,KEY_SHIFT ) &&
					!KEY_test( matrix,KEY_CTRL ) ) {		/*  上下段とも	*/
				inst_change_down( KYB_UPPER,KYB_LOWER ) ;
			}

/*
**	定位の変更( 1つ右の定位 )
*/
		} else if ( KEY_test( matrix,KEY_RIGHT ) ) {

			if ( KEY_test( matrix,KEY_SHIFT ) ) {			/*  ｷｰﾎﾞｰﾄﾞ上段	*/
				pan_change_right( KYB_UPPER,KYB_DUMMY ) ;
			}
			if ( KEY_test( matrix,KEY_CTRL ) ) {			/*  ｷｰﾎﾞｰﾄﾞ下段	*/
				pan_change_right( KYB_DUMMY,KYB_LOWER ) ;
			}
			if ( !KEY_test( matrix,KEY_SHIFT ) &&
					!KEY_test( matrix,KEY_CTRL ) ) {		/*  上下段とも	*/
				pan_change_right( KYB_UPPER,KYB_LOWER ) ;
			}

/*
**	定位の変更( 1つ左の定位 )
*/
		} else if ( KEY_test( matrix,KEY_LEFT ) ) {

			if ( KEY_test( matrix,KEY_SHIFT ) ) {			/*  ｷｰﾎﾞｰﾄﾞ上段	*/
				pan_change_left( KYB_UPPER,KYB_DUMMY ) ;
			}
			if ( KEY_test( matrix,KEY_CTRL ) ) {			/*  ｷｰﾎﾞｰﾄﾞ下段	*/
				pan_change_left( KYB_DUMMY,KYB_LOWER ) ;
			}
			if ( !KEY_test( matrix,KEY_SHIFT ) &&
					!KEY_test( matrix,KEY_CTRL ) ) {		/*  上下段とも	*/
				pan_change_left( KYB_UPPER,KYB_LOWER ) ;
			}

/*
**	発音の強制停止
*/
		} else if ( KEY_test( matrix,KEY_UNDO ) ) {
			SND_pcm_abort() ;

/*
**	ｷｰﾎﾞｰﾄﾞ操作で音を出す
*/
		} else {
			note_change( matrix ) ;						/*  音程の変更ﾁｪｯｸ	*/

			for ( c=0; c<NKYBINF; c++ ) {
				key_play( matrix,c ) ;
			}

		}

	} while ( !KEY_test( matrix,KEY_BREAK ) ) ;	/*  BREAKｷｰが押されるまで	*/

}

/*********************************  メイン  **********************************/
void main( int ac, char *av[] )
{
	int		endp ;

	printf("PMB.EXP  v0.50  (c) ﾊﾟｵﾊﾟｵ 1990.            ") ;
	printf("<< Copyright (C) Y.Hirata 1990. >>\n") ;

	if ( ac > 1 ) {									/*  引数あり			*/
		strcpy( Pmbfile,av[1] ) ;
		endp = strlen( Pmbfile ) ;
		if ( strchr( Pmbfile,'.' ) == NULL ) {		/*  ﾌｧｲﾙ拡張子なし		*/
			strcat( Pmbfile,".PMB" ) ;
		} else {
			if ( strcmp( Pmbfile+endp-4,".PMB" ) &&
					strcmp( Pmbfile+endp-4,".pmb" ) ) {
				printf("\x1b[31mERROR\x1b[m : FILE NAME ( %s ) - ",Pmbfile) ;
				printf(".PMB ﾌｧｲﾙ しか指定できません！\n") ;
				exit( 1 ) ;
			}
		}
	} else {										/*  引数なし			*/
		strcpy( Pmbfile,PMB_FILE ) ;
	}

	INT23_init() ;									/*  ^C ﾏｽｸ設定			*/

	init() ;										/*  各種初期設定		*/

	if ( Pmbflg )
		play_start() ;								/*  ﾌﾟﾚｲ開始			*/

close:

	if ( Pmbflg ) {
		free( Pmbdata ) ;
	}

	KYB_clic( 0 ) ;									/*  ｷｰｸﾘｯｸ音あり		*/
 	KYB_clrbuf() ;									/*  ｷｰﾊﾞｯﾌｧ･ｸﾘｱ			*/

	SND_end() ;										/*  ｻｳﾝﾄﾞ終了			*/

	INT23_end() ;									/*  ^C ﾏｽｸ解除			*/

	printf("\nﾌﾟﾛｸﾞﾗﾑを終了します。\n") ;

}

