/*** MIDIマネージャ関係 ***/

#include <stdio.h>
#include <snd.h>
#include <mmDEF.h>

#define EUPBUFFSIZE			(200*1024)
/*#define INTERVAL			(480000*2)*/		/* 2msec.				*/
#define MAXPLAYNOTE			(64)
#define MAXTRACK			(32)
#define EVENTSIZE			(256)
#define FMTOUTSIZE			(64*8)
#define FMTINSIZE			(128*4)
#define SMPUINSIZE			(128)
#define LOCALSTACKSIZE		(1024*4)


/*static char					*mbuff;*/
static char					mbuff[EUPBUFFSIZE];

static int					open_flag = 0;
static int					play_lock = 0;

static MIDIMANCTRL			midimanctrl;
static PLACE				place;
static NOTEOFFTABLE			noteoff_buff[MAXPLAYNOTE+1];
static TRACKWORK			trackwork_buff[MAXTRACK];
static char					trackwork_sreave[MAXTRACK*16];
static unsigned char		event_buff[EVENTSIZE];
static unsigned char		fmt_out_buff[FMTOUTSIZE];
static unsigned char		fmt_in_buff[FMTINSIZE];
static unsigned char		smpu_in_buff[SMPUINSIZE];
static unsigned char		local_stack[LOCALSTACKSIZE];

static char					out_port = 0x00;


static char		GSinit[]={
					0x00,0x00,0x00,0x00,
					0x0b,0x00,0x00,0x00,
					0xf0,
					0x41,0x10,0x42,0x12,0x40,0x00,0x7f,0x00,0x41,
					0xf7
				};

static char		AllNoteOff[]={
					0x00,0x00,0x00,0x00,
					0x30,0x00,0x00,0x00,
					0xb0,0x7b,0x00,
					0xb1,0x7b,0x00,
					0xb2,0x7b,0x00,
					0xb3,0x7b,0x00,
					0xb4,0x7b,0x00,
					0xb5,0x7b,0x00,
					0xb6,0x7b,0x00,
					0xb7,0x7b,0x00,
					0xb8,0x7b,0x00,
					0xb9,0x7b,0x00,
					0xba,0x7b,0x00,
					0xbb,0x7b,0x00,
					0xbc,0x7b,0x00,
					0xbd,0x7b,0x00,
					0xbe,0x7b,0x00,
					0xbf,0x7b,0x00
				};
static char		ResetAllControler[]={
					0x00,0x00,0x00,0x00,
					0x30,0x00,0x00,0x00,
					0xb0,0x79,0x00,
					0xb1,0x79,0x00,
					0xb2,0x79,0x00,
					0xb3,0x79,0x00,
					0xb4,0x79,0x00,
					0xb5,0x79,0x00,
					0xb6,0x79,0x00,
					0xb7,0x79,0x00,
					0xb8,0x79,0x00,
					0xb9,0x79,0x00,
					0xba,0x79,0x00,
					0xbb,0x79,0x00,
					0xbc,0x79,0x00,
					0xbd,0x79,0x00,
					0xbe,0x79,0x00,
					0xbf,0x79,0x00
				};

#define			port_lists	2			/* MIDIボード以外は未対応 */
static char		port_list[]={
					0x00,	/* A	*/
					0x01,	/* B	*/
					0x10,	/* RS	*/
					0x20,	/* MPU	*/
					0Xff	/* INT	*/
				};


/* MIDIマネージャのオープン */
int midi_man_open(char *SndWork, int interval)
{
	int i;
	
	/* MIDI Manager settings */
	midimanctrl.mc_interval   = interval*480000;
	midimanctrl.mc_maxnote    = MAXPLAYNOTE;
	midimanctrl.mc_maxtrack   = MAXTRACK;
	midimanctrl.mc_sbios      = SndWork;
	midimanctrl.mc_noteoff    = noteoff_buff;
	midimanctrl.mc_trackwork  = (TRACKWORK*)&trackwork_sreave;
	for(i=0; i<16; i++)
		midimanctrl.mc_filter[i] = NULL;
	midimanctrl.mc_event      = event_buff;
	midimanctrl.mc_eventsize  = EVENTSIZE;
	midimanctrl.mc_fmtout     = fmt_out_buff;
	midimanctrl.mc_fmtoutsize = FMTOUTSIZE;
	midimanctrl.mc_fmtin      = fmt_in_buff;
	midimanctrl.mc_fmtinsize  = FMTINSIZE;
	midimanctrl.mc_smpu       = smpu_in_buff;
	midimanctrl.mc_smpusize   = SMPUINSIZE;
	midimanctrl.mc_stackadr   = local_stack;
	midimanctrl.mc_stacksize  = LOCALSTACKSIZE;
	
	if( TMM_openMidiMan(&midimanctrl) )
		return -1;
	else {
		open_flag = 1;
		return 0;
	}
}

/* MIDIマネージャのクローズ */
int midi_man_close()
{
	if( !open_flag )
		return -1;
	
	open_flag = 0;
	
	midi_play_stop();
	
	TMM_termRsMidi();
	TMM_closeMidiMan();
	return 0;
}

/*
	演奏のロック(BGM OFF)
	プレイ関数へのアクセスを拒否します
	出力ポートを変更すると解除されます
*/
int midi_play_lock(int lock)
{
	play_lock = lock;
}

/* 各種ステータスの変更 */
int midi_relativeTempo(int relative_tempo)
{
	if( !open_flag )
		return -1;
	TMM_setRelativeTempo(relative_tempo);
	return 0;
}

int midi_play_mode(int mode)
{
	if( !open_flag )
		return -1;
	TMM_playMode(mode);
	return 0;
}

int midi_out_port(char port)
{
	out_port = port;
	play_lock = 0;
	if( !open_flag )
		return -1;
	TMM_setOutputPortMap(0x00, out_port);
	return 0;
}

int midi_play_reset()
{
	int		tempo;
	
	if( !open_flag )
		return -1;
	
	midi_play_stop();
	
	
	if( play_lock )
		return -1;
	
	tempo = (mbuff[0x0805]+30)*10;
	place.p_meas       = 1;
	place.p_beat       = 1;
	place.p_tick       = 1;
	place.p_clock      = 1;
	place.p_time.rt_lo = 0;
	place.p_time.rt_hi = 0;
	place.p_sign       = 0x04021808;
	TMM_setTempo(0, tempo);
	TMM_setRelativeTempo(100);
	
	/*TMM_outputMidiEvent(0, GSinit);*/
	TMM_playStart(1, 0, &mbuff[0x0806], EUPBUFFSIZE, &place);
}

int midi_play_start(char *filename)
{
	midi_file_read(filename);
	
	if( play_lock )
		return -1;
	TMM_outputMidiEvent(0, GSinit);
	TMM_playStart(1, 0, &mbuff[0x0806], EUPBUFFSIZE, &place);
	
	/*midi_play_reset();*/
}

int midi_file_read(char *filename)
{
	FILE	*fp;
	char	*pp;
	/*char	out_port;*/
	char	str[16],dmy[8];
	int		msize;
	int		tempo;
	int		pdat;
	int		i,j,k;
	char name[64];
	
	if( !open_flag )
		return -1;
	/*
	if( play_lock )
		return -1;
	*/
	/*
	if( out_midi_port==(char)0xff )
		return 1;
	*/
	
	SND_elevol_mute(0x0f);
	SND_elevol_set(0, 127, 127);		/* line in */
	
	if( (fp=fopen(filename,"rb"))==NULL )
		return -1;
	
	/*
	mbuff = (char*)malloc(EUPBUFFSIZE);
	if( mbuff==NULL )
		error("out of memory");
	*/
	fread(mbuff, 1, EUPBUFFSIZE, fp);
	fclose(fp);
	
	/*
	bzero(str, 13);
	strncpy(str, &mbuff[0x06e2], 8);
	strcat(str, ".fmb");
	SND_fm_bank_load(str, dmy);
	
	bzero(str, 13);
	strncpy(str, &mbuff[0x06ea], 8);
	strcat(str, ".pmb");
	SND_pcm_bank_load(str, dmy);
	*/
	
	
	/*
		track work settings 
	*/
	for(i=0; i<MAXTRACK; i++)
		trackwork_buff[i].trk_number  = (TRACK)i;
	
	pp = &mbuff[0x0354];
	for(i=0; i<MAXTRACK; i++)
		trackwork_buff[i].trk_mute    = *pp++;
	
	for(i=0; i<MAXTRACK; i++)
		trackwork_buff[i].trk_filter  = 0x000003ff;
	
	pp = &mbuff[0x0374];
	for(i=0; i<MAXTRACK; i++)
		trackwork_buff[i].trk_port    = (*pp++)&(0xff);
	
	pp = &mbuff[0x0394];
	for(i=0; i<MAXTRACK; i++)
		trackwork_buff[i].trk_midich  = *pp++;
	
	for(i=0; i<MAXTRACK; i++){
		trackwork_buff[i].trk_notemap = -1;
		trackwork_buff[i].trk_ctrlmap = -1;
		trackwork_buff[i].trk_progmap = -1;
	}
	
	pp = &mbuff[0x03b4];
	for(i=0; i<MAXTRACK; i++)
		trackwork_buff[i].trk_bias    = *pp++;
	
	pp = &mbuff[0x03d4];
	for(i=0; i<MAXTRACK; i++)
		trackwork_buff[i].trk_oct     = *pp++;
	
	for(i=0; i<MAXTRACK; i++){
		trackwork_buff[i].trk_vol     = 0;
		trackwork_buff[i].trk_exp     = 0;
	}
	
	
	
	/*	master to sreave (pading cut) */
	
	pp = (char*)&trackwork_buff;
	for(i=0; i<MAXTRACK; i++){
		for(j=0; j<2; j++)
			trackwork_sreave[i*16+j] = *pp++;
		pp += 2;
		for(; j<16; j++)
			trackwork_sreave[i*16+j] = *pp++;
		pp += 2;
	}
	
	
	
	/* --- for test ---
	fp = fopen("tmm.out","wb");
	pp = (char*)&trackwork_sreave;
	fwrite(pp, 1, 16*32, fp);
	fclose(fp);
	*/
	
	msize = *((unsigned int*)&mbuff[0x0800]);
	tempo = (unsigned char)mbuff[0x0805];
	tempo += 30;
	tempo *= 10;
	
	/* place settings */
	place.p_meas       = 1;
	place.p_beat       = 1;
	place.p_tick       = 1;
	place.p_clock      = 1;
	place.p_time.rt_lo = 0;
	place.p_time.rt_hi = 0;
	place.p_sign       = 0x04021808;
	
	
	TMM_playMode(2);
	TMM_setTempo(0, tempo);
	TMM_setRelativeTempo(100);
	
	TMM_setOutputPortMap(0x00, out_port);
	TMM_setOutputPortMap(0xff, INTERNAL_VOICE);
	
	TMM_initInternalVoice();
	pp = &mbuff[0x06d4];
	for(i=0; i<6; i++)
		TMM_setInternalChannel(i, *pp++);
	pp = &mbuff[0x06da];
	for(i=0; i<8; i++)
		TMM_setInternalChannel(i+64, *pp++);
	
	/*TMM_setSyncln(0, 0, 0, 0, 7);*/
	
	/*printf("play buff size %d\n", msize);*/
	
	return 0;
}


int midi_play_stop()
{
	if( !open_flag )
		return -1;
	TMM_playStop();
	TMM_outputMidiEvent(0, AllNoteOff);
	TMM_outputMidiEvent(0, ResetAllControler);
	TMM_outputMidiEvent(0, GSinit);
	TMM_initInternalVoice();
	/*free(mbuff);*/
	return 0;
}

