/* 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];
char name[300];
char date[300];
int songs;
int defsong;
enum {
	cmc = 0, cmr, mpt, md1, md2, tmc, tm8, unknown
} type;
unsigned int music;
unsigned int init;
unsigned int player;
char iname[300];
char oname[300];
FILE* ofile;
unsigned char msx[63000];
unsigned char* buf;
unsigned char* smp;
unsigned char* 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(type == cmr	? (player == 0x500 ? "cmr_0500.plr" : "cmr_f500.plr")
				: (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 readSamples(char* ext) {
	smp = buf;
	buf += 4;
	strcpy(strrchr(iname, '.') + 1, ext);
	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])) {
		int i = hi(buf - smp - 0x25);
		int h = 0x0e + i < msx[3] ? 0x0e : 0xcf - i;
		printf("WARNING: Conflict between music and samples %s. Placing samples at $%02X00.\n", iname, h);
		h -= smp[4];
		smp[1] += h;
		smp[3] += h;
		for (i = 0; i < 0x20; i++)
			if (smp[4 + i])
				smp[4 + i] += h;
	}

	player = (msx[3] >= '\x10' && smp[4] >= '\x10' ? 0x500 : 0xf500);
}

void md1_() {
	/* Read .D15 samples */
	readSamples("d15");
/*	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 md2_() {
	/* Read .D8 samples */
	readSamples("d8");
/*	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
	lda #6
; = 27 bytes
*/
	plr = buf;
	buf += 31;
	readfile(player == 0x500 ? "mpt_0500.plr" : "mpt_f500.plr", 6);
	plr[0] = lo(player - 27);		plr[1] = hi(player - 27);
	plr[2] = lo(player - 30 + buf - plr);	plr[3] = hi(player - 30 + 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] = '\xa9';	plr[30] = '\x06';
	saphdr('D');
	fprintf(ofile,
		"INIT %04X\r\n"
		"PLAYER %04X\r\n",
		player - 27, 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);
}

int main(int argc, char** argv) {
	char* exts[] = {"cmc", "cmr", "mpt", "md1", "md2", "tmc", "tm8"};
	void (*procs[])() = {cmc_, cmc_, mpt_, md1_, md2_, 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 < unknown; 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;
}
