/*************************************************************************
*	GS音源制御
*************************************************************************/

#define	MODEL_ID_SC55	(0x45)
#define	MODEL_ID_GS		(0x42)

int		GsDeviceID = 16;

char	*GsFuncTbl[32] =
{
	"GS_setDeviceNumber" , 
	"sysEx_gs"           , 
	"sysEx_sc55"         , 

	"exGs_reset"         , 
	"exGs_masterVolume"  , 
	"exGs_partialReserve", 
	"exGs_reverbMacro"   , 
	"exGs_reverbPara"    , 
	"exGs_chorusMacro"   , 
	"exGs_chorusPara"    , 

	"exGs_rxChannel"     , 
	"exGs_assignMode"    , 
	"exGs_rymMap"        , 

	"exGs_mod"           , 
	"exGs_bend"          , 
	"exGs_caf"           , 
	"exGs_paf"           , 
	"exGs_cc1number"     , 
	"exGs_cc2number"     , 
	"exGs_cc1control"    , 
	"exGs_cc2control"    , 

	"exSC55_msgSet"      , 
	"exSC55_dotSet"      , 
	"SC55_initDotBuffer" , 
	"SC55_setDotBuffer"  , 
	"exSC55_dotBuffer"   , 

	NULL
};

int		GS_macroInit( char *sqr )
{
	int			i;

	GsDeviceID = 17 - 1;
	for ( i = 0; GsFuncTbl[i] != NULL; ++i )
		MMac_extDefine( sqr, GsFuncTbl[i], GsFuncTbl[i], MMAC_ATT_EXT, NULL );
	MMac_extDefine( sqr, "_GS_MACRO_DEFINED", "", MMAC_ATT_NORMAL , NULL );
	return (NORMAL);
}

/*************************************************************************
*	デバイス番号の設定
*-------------------------------------------------------------------------
*	GS_setDeviceNumber(n)
*	n	…	1〜32
*************************************************************************/

int		GS_setDeviceNumber( char *sqr, size_t bufSiz, char *buf, int argc, char **argv )
{
	int		n;

	if ( argc < 1 )
	{
_ERR:	MM_setErrMsg(sqr,"[GS] device number error!");
		return (ERR);
	}
	n = atoi(argv[0]) - 1;
	if ( n < 1 || n > 32 )
		goto _ERR;
	GsDeviceID = n - 1;
	return (0);
}

/*************************************************************************
*	ローランドのエクスクルーシブメッセージを生成する
*************************************************************************/

int		roland_excl( UCHAR *buf, int deviceID, int modelID, UINT adr, size_t siz, UCHAR *dat )
{
	int		i, sum;

	buf[0] = 0xF0;
	buf[1] = 0x41;		/* maker ID   */
	buf[2] = deviceID;	/* device ID  */
	buf[3] = modelID;	/* model ID   */
	buf[4] = 0x12;		/* command ID */
	buf[5] = (adr>>16);	buf[6] = (adr>>8);	buf[7] = (adr);
	sum = buf[5] + buf[6] + buf[7];
	for ( i = 0; i < siz; ++i )
	{
		buf[8+i] = dat[i];
		sum += dat[i];
	}
	sum = (0x80 - (sum & 0x7F)) & 0x7F;
	buf[8+siz] = sum;
	buf[9+siz] = 0xF7;

	return (siz + 10);
}

int		gs_genMML( char *sqr, size_t bufSiz, char *buf, size_t adr, size_t siz, char *dat)
{
	int		ret;
	char	excl[256], tmp[1024];

	ret = roland_excl( excl, GsDeviceID, MODEL_ID_GS, adr, siz, dat );
	ret = make_sysEx( tmp, ret, excl );
	if ( ret >= bufSiz )
	{
		MM_setErrMsg(sqr,_OUT_OF_STRING_SPACE);
		return (ERR);
	}
	memcpy( buf, tmp, ret );
	return (ret);
}

int		sc55_genMML( char *sqr, size_t bufSiz, char *buf, size_t adr, size_t siz, char *dat)
{
	int		ret;
	char	excl[256], tmp[1024];

	ret = roland_excl( excl, GsDeviceID, MODEL_ID_SC55, adr, siz, dat );
	ret = make_sysEx( tmp, ret, excl );
	if ( ret >= bufSiz )
	{
		MM_setErrMsg(sqr,_OUT_OF_STRING_SPACE);
		return (ERR);
	}
	memcpy( buf, tmp, ret );
	return (ret);
}


/*************************************************************************
*	GSのエクスクルーシブメッセージMML を生成する
*-------------------------------------------------------------------------
*	(<adr(hex)>,<siz>,<p1>,...<pn>
*************************************************************************/

int		sysEx_gs( char *sqr, size_t bufSiz, char *buf, int argc, char **argv )
{
	char	dat[128];
	UINT	adr, siz;
	int		i, ret;

	if ( argc < 3 )
	{
		MM_setErrMsg(sqr,"GS system exclusive error!");
		return (ERR);
	}
	sscanf(argv[0],"%x",&adr);
	siz = atoi(argv[1]);
	if ( siz < 1 || argc < 2 + siz )
		return (ERR);
	for ( i = 0; i < siz; ++i )
		dat[i] = atoi(argv[2+i]);

	return gs_genMML( sqr, bufSiz, buf, adr, siz, dat );
}

/*************************************************************************
*	SC55のエクスクルーシブメッセージMML を生成する
*-------------------------------------------------------------------------
*	(<adr(hex)>,<siz>,<p1>,...<pn>
*************************************************************************/

int		sysEx_sc55( char *sqr, size_t bufSiz, char *buf, int argc, char **argv )
{
	char	dat[128];
	UINT	adr, siz;
	int		i, ret;

	if ( argc < 3 )
	{
		MM_setErrMsg(sqr,"SC-55 system exclusive error!");
		return (ERR);
	}
	sscanf(argv[0],"%x",&adr);
	siz = atoi(argv[1]);
	if ( siz < 1 || argc < 2 + siz )
		return (ERR);
	for ( i = 0; i < siz; ++i )
		dat[i] = atoi(argv[2+i]);

	return sc55_genMML( sqr, bufSiz, buf, adr, siz, dat );
}

/*************************************************************************
*	GS音源の初期化
*************************************************************************/

int		exGs_reset( char *sqr, size_t bufSiz, char *buf, int argc, char **argv )
{
	char	dat[4];
	int		ret;

	if ( argc != 0 )
	{
		MM_setErrMsg(sqr,"[GS] \"reset\" error!");
		return(ERR);
	}
	dat[0] = 0x00;
	return gs_genMML( sqr, bufSiz, buf, 0x40007F, 1, dat );
}


/*************************************************************************
*	マスターボリューム
*-------------------------------------------------------------------------
*	(<vol>)
*************************************************************************/

int		exGs_masterVolume( char *sqr, size_t bufSiz, char *buf, int argc, char **argv )
{
	char	dat[4];
	int		ret;

	if ( argc != 1 )
	{
		MM_setErrMsg(sqr,"[GS] Master volume error!");
		return(ERR);
	}

	dat[0] = atoi(argv[0]);
	return gs_genMML( sqr, bufSiz, buf, 0x400004, 1, dat );
}

/*************************************************************************
*	パーシャルリザーブ
*-------------------------------------------------------------------------
*	(<p10>,<p1>,<p2>,<p3>,<p4>,<p5>,<p6>,<p7>,<p8>,<p9>,<p11>,..<p16>)
*************************************************************************/

int		exGs_partialReserve( char *sqr, size_t bufSiz, char *buf, int argc, char **argv )
{
	int		i;
	char	dat[32];
	int		ret;

	if ( argc != 16 )
	{
		MM_setErrMsg(sqr,"[GS] Partial reserve error!");
		return(ERR);
	}

	for ( i = 0; i < 16; ++i )
		dat[i] = atoi(argv[i]);
	return gs_genMML( sqr, bufSiz, buf, 0x400110, 16, dat );
}

/*************************************************************************
*	リバーブマクロ
*-------------------------------------------------------------------------
*	(<typ>)
*************************************************************************/

int		exGs_reverbMacro( char *sqr, size_t bufSiz, char *buf, int argc, char **argv )
{
	char	dat[4];
	int		ret;

	if ( argc != 1 )
	{
		MM_setErrMsg(sqr,"[GS] Reverb macro error!");
		return(ERR);
	}

	dat[0] = atoi(argv[0]);
	return gs_genMML( sqr, bufSiz, buf, 0x400130, 1, dat );
}

/*************************************************************************
*	リバーブパラメータ
*-------------------------------------------------------------------------
*	(<charactor>,<pre-lpf>,<level>,<time>,<delay feedback>,<send to chorus>)
*************************************************************************/

int		exGs_reverbPara( char *sqr, size_t bufSiz, char *buf, int argc, char **argv )
{
	int		i;
	char	dat[8];
	int		ret;

	if ( argc != 6 )
	{
		MM_setErrMsg(sqr,"[GS] Reverb parameter error!");
		return(ERR);
	}

	for ( i = 0; i < 6; ++i )
		dat[i] = atoi(argv[i]);
	return gs_genMML( sqr, bufSiz, buf, 0x400131, 6, dat );
}

/*************************************************************************
*	コーラスマクロ
*-------------------------------------------------------------------------
*	(<typ>)
*************************************************************************/

int		exGs_chorusMacro( char *sqr, size_t bufSiz, char *buf, int argc, char **argv )
{
	char	dat[4];
	int		ret;

	if ( argc != 1 )
	{
		MM_setErrMsg(sqr,"[GS] Chorus macro error!");
		return(ERR);
	}

	dat[0] = atoi(argv[0]);
	return gs_genMML( sqr, bufSiz, buf, 0x400138, 1, dat );
}

/*************************************************************************
*	コーラスパラメータ
*-------------------------------------------------------------------------
*	(<pre-lpf>,<level>,<feedback>,<delay>,<rate>,<depth>,<send to reverb>)
*************************************************************************/

int		exGs_chorusPara( char *sqr, size_t bufSiz, char *buf, int argc, char **argv )
{
	int		i;
	char	dat[8];
	int		ret;

	if ( argc != 7 )
	{
		MM_setErrMsg(sqr,"[GS] Chorus parameter error!");
		return(ERR);
	}

	for ( i = 0; i < 7; ++i )
		dat[i] = atoi(argv[i]);
	return gs_genMML( sqr, bufSiz, buf, 0x400139, 7, dat );
}

int		GsPartTbl[16] = {1,2,3,4,5,6,7,8,9,0,10,11,12,13,14,15};

int		gs_getpart_n( int part )
{
	if ( part < 1 || part > 16 )
		return (-1);
	return (GsPartTbl[part-1]);
}
#define	GS_PARTADR(_part,_adr)	((_adr)+((_part)<<8))

/*************************************************************************
*	MIDIチャンネル
*-------------------------------------------------------------------------
*	(<part>,<ch>)
*************************************************************************/

int		exGs_rxChannel( char *sqr, size_t bufSiz, char *buf, int argc, char **argv )
{
	int		i, part, ch;
	char	dat[4];
	int		ret;

	if ( argc != 2 )
	{
_PARA_ERR:
		MM_setErrMsg(sqr,"[GS] 'Rx.channel' error!");
		return(ERR);
	}

	if ( (part = gs_getpart_n(atoi(argv[0]))) < 0 )
		goto _PARA_ERR;
	ch = atoi(argv[1]);
	if ( ch < 0 || ch > 16 )
		goto _PARA_ERR;
	if ( ch > 0 )
		--ch;
	else
		ch = 0;	/* OFF */
	dat[0] = ch;
	return gs_genMML( sqr, bufSiz, buf, GS_PARTADR(part,0x401002), 1, dat );
}

/*************************************************************************
*	アサインモード
*-------------------------------------------------------------------------
*	(<part>,<mode>)
*************************************************************************/

int		exGs_assignMode( char *sqr, size_t bufSiz, char *buf, int argc, char **argv )
{
	int		i, part;
	char	dat[4];
	int		ret;

	if ( argc != 2 )
	{
_PARA_ERR:
		MM_setErrMsg(sqr,"[GS] 'Assign mode' error!");
		return(ERR);
	}

	if ( (part = gs_getpart_n(atoi(argv[0]))) < 0 )
		goto _PARA_ERR;
	dat[0] = atoi(argv[1]);
	return gs_genMML( sqr, bufSiz, buf, GS_PARTADR(part,0x401014), 1, dat );
}

#include	"gs_cc.c"
#include	"gs_drum.c"
