/***************************************************
    Rhythm de Pon !! version 1.41421356
                copyleft 1995 Yamasyn.
                    ++  compile for gcc only
****************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#include <sys/extender.h>

#define ON  1
#define OFF 0

int part=10,port=0,key[256],vel[256];

typedef struct {
	clock_t tc;
	unsigned char   key;
}SMFBUF;

SMFBUF *smfbuf;
int smfbufSize=65535,smfbufNum=0,smfMake;

FILE *fpi,*fpo;

char smfHeader[]=	/* GCCでは分解能５０ */
{'M','T','h','d',0,0,0,6,0,0,0,1,0
,CLOCKS_PER_SEC/2,'M','T','r','k',0,0,0,0};

char *title=
"\n"
" ******************* RHYTHM de PON ********************\n"
"  KEY  :INSTRUMENT\n";


/* MIDI library                 -- midilib.o */
int MIDI_init(int);     /* MIDI 初期化       */
int MIDI_putch(int);    /* MIDI １バイト送信 */
int MIDI_restore(void); /* MIDI 終了         */

int key_check(void)
{
/*
	union REGS rg;
	rg.h.ah = 0x06;
	rg.h.dl = 0xff;
	intdos( &rg,&rg );
	return((rg.h.al != 0)? rg.h.al: -1);
*/
	return(_dos_direct_console_input());
}
void config(void)
{
	char buf[256],*s;
	static char *cfg_cmd[] = { "PORT","PART","SMFBUF","KEY" };
	int i,n=-1,l=0,m;

	if ((fpi=fopen("RHYTHM.CFG","r")) == NULL) {
		printf("'RHYTHM.cfg'が読めません\n");
		exit(EXIT_FAILURE);
	}
	while (fgets(buf,sizeof buf,fpi) != NULL) {
		l++;
		*(strchr(buf,'\n')) = '\0';
		if((s=strchr(buf,';')) != NULL) *s='\0';
		s=buf;
		while (*s == ' ' || *s == '\t') s++;
		if(*s == '\0')  continue;
		for (i=0;i<4;i++) {
			if(strncmp(s,cfg_cmd[i],strlen(cfg_cmd[i])) == 0) {
				n=i;
				break;
			}
		}
		if (n == -1) {
			printf("'RHYTHM.cfg'の %d 行に定義エラー\n",l);
			exit(EXIT_FAILURE);
		}
		s+=strlen(cfg_cmd[n]);
		while (*s == ' ' || *s == '\t') s++;
		switch(n) {
		case 0:
			if((port=toupper(*s)-'A')<0 || port>7) {
				printf("ＭＩＤＩポート指定に誤りがあります\n");
				exit(EXIT_FAILURE);
			}
			break;
		case 1:
			if((part=atoi(s)-1)<0 || part>15) {
				printf("パート指定に誤りがあります\n");
				exit(EXIT_FAILURE);
			}
			break;
		case 2:
			smfbufSize=atoi(s);
			break;
		case 3:
			if(*s==0x27 && *(s+2)==0x27) {
				m=*(s+1);
				s+=3;
			}
			else    m=atoi(s);
			s=strchr(s,',');
			m=toupper(m);      /* ここらへんはチェックしていない */
			key[m]=atoi(++s);  /* 手抜き */
			s=strchr(s,',');
			vel[m]=atoi(++s);
			s=strchr(s,',');
			printf("  '%c'  :%s\n",m,++s);
			break;
		}
	}
	fclose(fpi);
	return;
}
void record(int n)
{
	clock_t t;
	t=clock();
	if(smfbufSize <= (smfbufNum+1)*sizeof(SMFBUF)) {
		printf("ＳＭＦバッファが足りません");
		exit(EXIT_FAILURE);
	}
	smfbuf[smfbufNum].tc=t;
	smfbuf[smfbufNum].key=(unsigned char)n;
	smfbufNum++;
}

void note_on(int part,int note,int vel)
{
	MIDI_putch((0x90+part)&0xff);
	MIDI_putch(note & 0x7f);
	MIDI_putch(vel & 0x7f);

	return;
}

void key_main(void)
{
	int c;
	for(;;) {
		while ((c=key_check()) == -1);
		if (c == 13)	break;
		c=toupper(c);
		if(key[c] == -1)	continue;
		note_on(part,key[c],vel[c]);
		if (smfMake == ON)	record(c);
	}
	return;
}

int putvar(unsigned long n)
{
	int i,d[4],flags=0,ret=0;

	for(i=0;i<4;i++)
		d[i]=(int)((n>>(i*7))&0x7f);

	for(i=3;i>=0;i--)
	{
		if(flags==0 && d[i]==0 && i!=0) continue;
		flags=1;
		fputc(((i==0)?d[i]:d[i]|0x80),fpo);
		ret++;
	}
	return(ret);
}

void putSize(unsigned long dataSize)
{
	int d1,d2,d3,d4;

	d1=(int)((dataSize&0xff000000)>>24);
	d2=(int)((dataSize&0xff0000)>>16);
	d3=(int)((dataSize&0xff00)>>8);
	d4=(int)(dataSize&0xff);

	fputc(d1,fpo);
	fputc(d2,fpo);
	fputc(d3,fpo);
	fputc(d4,fpo);
}

int main(int argc,char *argv[])
{
	int c,i;
	clock_t t1,t2,t3;
	unsigned long d;

	if (argc != 1) {
		smfMake=ON;
		if ((fpo=fopen(argv[1],"wb")) == NULL) {
			printf("'%s'が作成できません\n",argv[1]);
			exit(EXIT_FAILURE);
		}
	} else smfMake=OFF;

	for(i=0;i<256;i++) {
		key[i]=-1;
		vel[i]=127;
	}
	printf(title);
	config();
	printf("[RET]:EXIT\n");
	MIDI_init(port);
	if((smfbuf=malloc(smfbufSize)) == NULL) {
		printf("ＳＭＦバッファが確保できません\n");
		exit(EXIT_FAILURE);
	}
	if (smfMake == ON)      printf("*** RECORDING NOW ***\n");
	t1=clock();
	key_main();
	if (smfMake == ON) {
		for (i=0;i<22;i++)      fputc(smfHeader[i],fpo);
		fputc(0x00,fpo);
		fputc(0xff,fpo);
		fputc(0x51,fpo);
		fputc(0x03,fpo);
		fputc(0x07,fpo);
		fputc(0xa1,fpo);
		fputc(0x20,fpo);
		for (i=0;i<smfbufNum;i++) {
			t3=smfbuf[i].tc;
			t2=t3-t1;
			t1=t3;
			putvar(t2);
			if (i==0) fputc(0x90+part,fpo);
			c=smfbuf[i].key;
			fputc(key[c],fpo);
			fputc(vel[c],fpo);
		}
		fputc(0x00,fpo);
		fputc(0xff,fpo);
		fputc(0x2f,fpo);
		fputc(0x00,fpo);
		d=ftell(fpo)-22L;
		fseek(fpo,18L,SEEK_SET);
		putSize(d);
		fclose(fpo);
	}
	return(0);
}
