/* SAP MAKER - Public Domain */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define word(l,h) ( ((h)<<8)|(l) )
#define lo(x) ((x)&0xff)
#define hi(x) ((x)>>8)

char author[300],name[300],date[300];
int songs,defsong;
enum {cmc=0,mpt,md1,tmc,tm8,unknown} type;
unsigned music,init,player;
char iname[300],oname[300];
FILE* ofile;
unsigned char msx[63000],*buf,*smp,*plr;

/* Read file to buffer */
void readfile(char* name,int offset) {
	FILE* tfile;
	if(!(tfile=fopen(name,"rb"))) {
		printf("Can't open %s\n",name);
		exit(2);
	}
	fseek(tfile,offset,SEEK_CUR);
	buf+=fread(buf,1,msx+sizeof(msx)-buf,tfile);
	fclose(tfile);
}

/* Create .SAP and write author,name,date,type */
void saphdr(char t) {
	if( strlen(oname)>30 )
		printf("WARNING: File name \"%s\" longer than 30 characters\n",oname);
	if(!(ofile=fopen(oname,"wb"))) {
		printf("Can't create %s\n",oname);
		exit(2);
	}
	fprintf(ofile,
		"SAP\r\n"
		"AUTHOR %s\r\n"
		"NAME %s\r\n"
		"DATE %s\r\n"
		"TYPE %c\r\n",
		author,name,date,t);
	if(songs!=1) {
		fprintf(ofile,"SONGS %d\r\n",songs);
		if(defsong)
			fprintf(ofile,"DEFSONG %d\r\n",defsong);
	}
}

/* Procs for different music formats */
void cmc_() {
	music=word(msx[2],msx[3]);
	player=( music>=0x1000?0x500:0xf500 );
	readfile( player==0x500?"cmc_0500.plr":"cmc_f500.plr",2 );
	saphdr('C');
	fprintf(ofile,
		"MUSIC %04X\r\n"
		"PLAYER %04X\r\n",
		music,player);
}

void mpt_() {
	player=( msx[3]>='\x10'?0x500:0xf500 );
/*	dta a(begin,end)
; = 4 bytes
	ldy #<msx
	ldx #>msx
	lda #0
	jsr player
	ldx #0	;song pos
	lda #2
; = 13 bytes
player	jmp init
	jmp play
*/
	plr=buf;
	buf+=17;
	readfile( player==0x500?"mpt_0500.plr":"mpt_f500.plr",6 );
	plr[0]=lo(player-13);		plr[1]=hi(player-13);
	plr[2]=lo(player-16+buf-plr);	plr[3]=hi(player-16+buf-plr);
	plr[4]='\xa0';	plr[5]=msx[2];
	plr[6]='\xa2';	plr[7]=msx[3];
	plr[8]='\xa9';	plr[9]='\x00';
	plr[10]='\x20';	plr[11]=lo(player);	plr[12]=hi(player);
	plr[13]='\xa2';	plr[14]='\x00';
	plr[15]='\xa9';	plr[16]='\x02';
	saphdr('B');
	fprintf(ofile,
		"INIT %04X\r\n"
		"PLAYER %04X\r\n",
		player-13,player+3);
}

void md1_() {
	/* Read .D15 samples */
	smp=buf;
	buf+=4;
	strcpy( strrchr(iname,'.')+1,"d15" );
	readfile(iname,0);
	smp[0]='\xe0';
	smp[1]=smp[4]-1;
	smp[2]='\xff';
	smp[3]=smp[4]+hi(buf-smp-0x25);
	if(!( msx[5]<smp[1]||msx[3]>smp[3] ))
		printf("WARNING: Conflict between music and samples %s\n",iname);

	player=( msx[3]>='\x10'&&smp[4]>='\x10'?0x500:0xf500 );
/*	dta a(begin,end)
; = 4 bytes
	ldy #<msx
	ldx #>msx
	lda #0
	jsr player
	ldy #<smp
	ldx #>smp
	lda #3
	jsr player
	ldx #0	;song pos
	lda #2
	jsr player
	ldx #1	;0=7,5kHz 1=15kHz
	lda #5	
; = 29 bytes
player	jmp init
	jmp play
*/
	plr=buf;
	buf+=33;
	readfile( player==0x500?"mpt_0500.plr":"mpt_f500.plr",6 );
	plr[0]=lo(player-29);		plr[1]=hi(player-29);
	plr[2]=lo(player-32+buf-plr);	plr[3]=hi(player-32+buf-plr);
	plr[4]='\xa0';	plr[5]=msx[2];
	plr[6]='\xa2';	plr[7]=msx[3];
	plr[8]='\xa9';	plr[9]='\x00';
	plr[10]='\x20';	plr[11]=lo(player);	plr[12]=hi(player);
	plr[13]='\xa0';	plr[14]='\xe0';
	plr[15]='\xa2';	plr[16]=smp[4]-1;
	plr[17]='\xa9';	plr[18]='\x03';
	plr[19]='\x20';	plr[20]=lo(player);	plr[21]=hi(player);
	plr[22]='\xa2';	plr[23]='\x00';
	plr[24]='\xa9';	plr[25]='\x02';
	plr[26]='\x20';	plr[27]=lo(player);	plr[28]=hi(player);
	plr[29]='\xa2';	plr[30]='\x01';
	plr[31]='\xa9';	plr[32]='\x05';
	saphdr('D');
	fprintf(ofile,
		"INIT %04X\r\n"
		"PLAYER %04X\r\n",
		player-29,player+3);
}

void tmc_() {
	int len;

	player=( msx[3]>='\x10'?0x500:0xf500 );
/*	dta a(begin,end)
; = 4 bytes
	ldy #<msx
	ldx #>msx
	lda #$70
	jsr player
	lda #$60
; = 11 bytes
; 1/frame
; = 0 bytes
player	jmp init
	jmp play
	jmp sound
; 2/frame - FASTPLAY 156
	asl 0
	jmp player
play	lda 0
	inc 0
	lsr @
	bcc player+3
	bcs player+6 !
; = 14 bytes
player
; 3/frame - FASTPLAY 104
	ldx #1
	stx 0
	bne player !
play	dec 0
	bne player+6
	ldx #3
	stx 0
	bne player+3 !
; = 16 bytes
player
; 4/frame - FASTPLAY 78
	ldx #1
	stx 0
	bne player !
play	dec 0
	bne player+6
	ldx #4
	stx 0
	bne player+3 !
; = 16 bytes
player
*/
	plr=buf;
	len=" \x0b\x19\x1b\x1b"[msx[37]];
	buf+=4+len;
	readfile( player==0x500?"tmc_0500.plr":"tmc_f500.plr",6 );
	init=player-len;
	plr[0]=lo(init);		plr[1]=hi(init);
	plr[2]=lo(init-5+buf-plr);	plr[3]=hi(init-5+buf-plr);
	plr[4]='\xa0';	plr[5]=msx[2];
	plr[6]='\xa2';	plr[7]=msx[3];
	plr[8]='\xa9';	plr[9]='\x70';
	plr[10]='\x20';	plr[11]=lo(player);	plr[12]=hi(player);
	plr[13]='\xa9';	plr[14]='\x60';
	switch( msx[37] ) {
	case '\4':
	case '\3':
	plr[15]='\xa2';	plr[16]='\x01';
	plr[17]='\x86';	plr[18]='\x00';
	plr[19]='\xd0';	plr[20]='\x0a';
	player-=10;
	plr[21]='\xc6';	plr[22]='\x00';
	plr[23]='\xd0';	plr[24]='\x0c';
	plr[25]='\xa2';	plr[26]=msx[37];
	plr[27]='\x86';	plr[28]='\x00';
	plr[29]='\xd0';	plr[30]='\x03';
	break;
	case '\2':
	plr[15]='\x06';	plr[16]='\x00';
	plr[17]='\x4c';	plr[18]=lo(player);	plr[19]=hi(player);
	player-=9;
	plr[20]='\xa5';	plr[21]='\x00';
	plr[22]='\xe6';	plr[23]='\x00';
	plr[24]='\x4a';
	plr[25]='\x90';	plr[26]='\x05';
	plr[27]='\xb0';	plr[28]='\x06';
	break;
	case '\1':
	player+=3;
	break;
	}
	saphdr('B');
	if(type==tm8)
		fprintf(ofile,"STEREO\r\n");
	if(msx[37]>1)
		fprintf(ofile,"FASTPLAY %d\r\n",((unsigned char *)"  \x9c\x68\x4e")[msx[37]]);
	fprintf(ofile,
		"INIT %04X\r\n"
		"PLAYER %04X\r\n",
		init,player);
}

main(int argc, char** argv) {
	char* exts[]={"cmc","mpt","md1","tmc","tm8"};
	void (*procs[])()={cmc_,mpt_,md1_,tmc_,tmc_};
	FILE* ifile;
	char line[1000];
	int i;
	char* p;
	char* q;
	char* t[6];
	unsigned endad;

	if(argc!=2) {
		puts("Give info file name");
		return 3;
	}
	if(!(ifile=fopen(argv[1],"r"))) {
		printf("Can't open %1\n",argv[1]);
		return 3;
	}
	while(!feof(ifile)) {
		/* Get input and output names, songs, defsong */
		fgets(line,sizeof(line),ifile);
		if( feof(ifile) )
			break;
		if( *line==';'||*line=='\n' )
			continue;
		switch( sscanf(line,"%s %s %d %d",iname,oname,&songs,&defsong) ) {
		case 0:
			printf("Invalid line %s\n",line);
			fclose(ifile);
			return 2;
		case 1:
			sprintf(oname,"%.*s.sap",strrchr(iname,'.')-iname,iname);
		case 2:
			songs=1;
		case 3:
			defsong=0;
		default:
			break;
		}
		/* Recognize extension */
		p=strrchr(iname,'.')+1;
		for(type=cmc;type<=tm8;type++)
			if( stricmp(p,exts[type])==0 )
				break;
		if(type==unknown) {
			printf("Unknown type of %s\n",iname);
			return 2;
		}
		/* Read music */
		buf=msx;
		readfile(iname,0);
		if( msx[0]!=0xff||msx[1]!=0xff ) {
			printf("%s is not valid music file\n",iname);
			return 2;
		}
		endad=word(msx[2],msx[3])+buf-msx-7;
		if( endad!=word(msx[4],msx[5]) ) {
			printf("WARNING: Fixing invalid header of %s\n",iname);
			msx[4]=lo(endad);
			msx[5]=hi(endad);
		}
		/* Get author, name and date */
		/* Defaults: "<?>", "sap name", "<?>" */
		strcpy(author,"\"<?>\"");
		for(p=oname,q=name+1;*p!='.';p++,q++)
			*q=(*p=='_'?' ':*p);
		*name=*q++='"';
		*q='\0';
		strcpy(date,"\"<?>\"");
		/* Find '"' */
		p=line;
		for(i=0;i<6;i++)
			if(!(t[i]=p=strchr(p+1,'"')))
				break;
		/* Set author, name and date if given */
		switch(i) {
		case 6:
			t[5][1]='\0';
			strcpy(date,t[4]);
		case 5:
		case 4:
			t[3][1]='\0';
			strcpy(name,t[2]);
		case 3:
		case 2:
			t[1][1]='\0';
			strcpy(author,t[0]);
		default:
			break;
		}
		/* Run proper procedure */
		procs[type]();
		/* Write binary part */
		fwrite(msx,buf-msx,1,ofile);
		/* Close file */
		fclose(ofile);
	}
	fclose(ifile);
	return 0;
}
