shithub: riscv

Download patch

ref: 297bf25f612d2dde0d28d7feaae0ea381be114a7
parent: 009bec07521287ebfc9f4dcfddac18d8f27f1fb9
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Feb 26 14:23:52 EST 2017

add games/mus midi converter (by qu7uux)

--- /dev/null
+++ b/sys/man/1/mus
@@ -1,0 +1,25 @@
+.TH MUS 1
+.SH NAME
+mus \- MUS to MIDI converter
+.SH SYNOPSIS
+.B games/mus
+[
+.I musfile
+]
+.SH DESCRIPTION
+The MUS format is a simplified MIDI music format used in
+.IR doom (1)
+and several related games.
+.PP
+.I Mus
+decodes MIDI music encoded in MUS format, either from
+.B musfile
+or from standard input, and produces a MIDI format file on standard output.
+.SH "SEE ALSO"
+.IR doom (1) ,
+.IR midi (1)
+.SH SOURCE
+.B /sys/src/games/mus.c
+.SH HISTORY
+.I Mus
+appeared first for 9front (September, 2015).
--- a/sys/src/games/mkfile
+++ b/sys/src/games/mkfile
@@ -10,6 +10,7 @@
 	life\
 	memo\
 	mole\
+	mus\
 	glendy\
 	packet\
 	mandel\
--- /dev/null
+++ b/sys/src/games/mus.c
@@ -1,0 +1,267 @@
+#include <u.h>
+#include <libc.h>
+
+typedef struct Trk Trk;
+typedef struct Ch Ch;
+
+struct Ch{
+	uchar n[128];
+	uchar pitch;
+	uchar ctl[10];
+};
+struct Trk{
+	u32int len;
+	uchar *dat;
+	uchar *p;
+	uchar *end;
+	Ch c[16];
+	long delay;
+	int done;
+};
+Trk t;
+uchar *mcmd, *mp, *me;
+int fd;
+
+#define	PBIT16(p,v)	(p)[0]=(v);(p)[1]=(v)>>8
+#define BBIT32(p,v)	(p)[3]=(v);(p)[2]=(v)>>8;(p)[1]=(v)>>16;(p)[0]=(v)>>24
+
+void
+eread(int fd, void *u, long n)
+{
+	if(readn(fd, u, n) != n)
+		sysfatal("readn: %r");
+}
+
+uchar
+r8(void)
+{
+	return *t.p++;
+}
+
+u32int
+delay(void)
+{
+	u32int t;
+	uchar v;
+
+	t = 0;
+	do{
+		v = r8();
+		t = t << 7 | v & 0x7f;
+		*mp++ = v;
+	}while(v & 0x80);
+	return t;
+}
+
+void
+putcmd(uchar *cmd, int n)
+{
+	if(mp + n >= me){
+		me += 8192;
+		mcmd = realloc(mcmd, me - mcmd);
+		if(mcmd == nil)
+			sysfatal("realloc: %r");
+	}
+	memcpy(mp, cmd, n);
+	mp += n;
+}
+
+void
+ev(void)
+{
+	uchar e, v;
+	Ch *c;
+	uchar cmd[3], *p;
+
+	e = r8();
+	c = &t.c[e & 15];
+	p = cmd;
+	switch(e >> 4 & 7){
+	case 0:
+		v = r8() & 0x7f;
+		c->n[v] = 0;
+		*p++ = e | 0x80;
+		*p++ = v;
+		*p++ = 0x40;
+		break;
+	case 1:
+		v = r8();
+		if(v & 0x80){
+			c->n[v] = r8() & 0x7f;
+			c->ctl[3] = c->n[v];
+		}else
+			c->n[v] = c->ctl[3];
+		*p++ = e | 0x80;
+		*p++ = v & 0x7f;
+		*p++ = c->n[v];
+		break;
+	case 2:
+		c->pitch = r8();
+		*p++ = e | 0xc0;
+		PBIT16(p, c->pitch << 7 & 0x7f7f);
+		p += 2;
+		break;
+	case 3:
+		v = r8();
+		*p++ = 0xb | e & 15;
+		switch(v){
+		case 10:
+			for(v=0; v<128; v++)
+				c->n[v] = 0;
+			*p++ = 0x78;
+			break;
+		case 11:
+			for(v=0; v<128; v++)
+				c->n[v] = 0;
+			*p++ = 0x7b;
+			break;
+		case 12:
+			*p++ = 0x7e;
+			break;
+		case 13:
+			*p++ = 0x7f;
+			break;
+		case 14:
+			memset(c->n, 0, sizeof c->n);
+			memset(c->ctl, 0, sizeof c->ctl);
+			c->ctl[3] = 0x7f;
+			c->ctl[4] = 64;
+			if((e & 15) == 15)
+				c->pitch = 60;
+			else
+				c->pitch = 128;
+			*p++ = 0x79;
+			break;
+		default:
+			sysfatal("unknown system event %ux\n", v);
+		}
+		*p++ = 0;
+		break;
+	case 4:
+		v = r8();
+		if(v > 9)
+			sysfatal("unknown controller %ux\n", v);
+		c->ctl[v] = r8() & 0x7f;
+		*p++ = 0xb0 | e & 15;
+		switch(v){
+		case 1: *p++ = 0x00; break;
+		case 2: *p++ = 0x01; break;
+		case 3: *p++ = 0x07; break;
+		case 4: *p++ = 0x0a; break;
+		case 5: *p++ = 0x0b; break;
+		case 6: *p++ = 0x5b; break;
+		case 7: *p++ = 0x5d; break;
+		case 8: *p++ = 0x40; break;
+		case 9: *p++ = 0x43; break;
+		}
+		*p++ = c->ctl[v];
+		if(v == 0)
+			cmd[0] += 0x10;
+		break;
+	case 6:
+		*p++ = 0xff;
+		*p++ = 0x2f;
+		e = 0;
+		t.done++;
+		break;
+	default:
+		sysfatal("unknown event %ux\n", e >> 4 & 7);
+	}
+	if((e & 15) == 9)
+		cmd[0] += 1;
+	if((e & 15) == 15)
+		cmd[0] &= ~6;
+	putcmd(cmd, p-cmd);
+	t.delay = 0;
+	if(e & 0x80)
+		t.delay = delay();
+	else
+		*mp++ = 0;
+}
+
+void
+reset(void)
+{
+	Ch *c;
+
+	c = t.c;
+	while(c < t.c + nelem(t.c)){
+		c->pitch = 128;
+		c->ctl[3] = 0x7f;
+		c->ctl[4] = 64;
+		c++;
+	}
+	t.c[15].pitch = 60;
+	mcmd = mallocz(t.len * 2, 1);
+	if(mcmd == nil)
+		sysfatal("mallocz: %r");
+	mp = mcmd;
+	me = mcmd + t.len * 2;
+}
+
+void
+barf(void)
+{
+	static uchar hdr[] = {
+		'M', 'T', 'h', 'd',
+		0x00, 0x00, 0x00, 0x06,
+		0x00, 0x00,
+		0x00, 0x01,
+		0x01, 0x01,
+		'M', 'T', 'r', 'k',
+		0x00, 0x00, 0x00, 0x00,
+		0x00, 0xb0, 0x07, 0x7f,
+		0x00, 0xb1, 0x07, 0x7f,
+		0x00, 0xb2, 0x07, 0x7f,
+		0x00, 0xb3, 0x07, 0x7f,
+		0x00, 0xb4, 0x07, 0x7f,
+		0x00, 0xb5, 0x07, 0x7f,
+		0x00, 0xb6, 0x07, 0x7f,
+		0x00, 0xb7, 0x07, 0x7f,
+		0x00, 0xb8, 0x07, 0x7f,
+		0x00, 0xb9, 0x07, 0x7f,
+		0x00, 0xba, 0x07, 0x7f,
+		0x00, 0xff, 0x51, 0x03, 0x1b, 0x8a, 0x06,
+		0x00
+	};
+	int n;
+
+	n = sizeof(hdr) - 22 + mp - mcmd;
+	BBIT32(hdr + 18, n);
+	write(1, hdr, sizeof hdr);
+	write(1, mcmd, mp - mcmd);
+}
+
+void
+main(int argc, char *argv[])
+{
+	int n, ofs;
+	uchar s[8], b[1024];
+
+	if(argc > 1){
+		fd = open(argv[1], OREAD);
+		if(fd < 0)
+			sysfatal("open: %r");
+	}
+	eread(fd, s, sizeof s);
+	if(memcmp(s, "MUS\x1a", 4) != 0)
+		sysfatal("invalid mus file: %r");
+	t.len = s[5] << 8 | s[4];
+	ofs = (s[7] << 8 | s[6]) - 8;
+	while(ofs > 0){
+		n = ofs > sizeof b ? sizeof b : ofs;
+		eread(fd, b, n);
+		ofs -= n;
+	}
+	t.dat = malloc(t.len);
+	if(t.dat == nil)
+		sysfatal("malloc: %r");
+	t.p = t.dat;
+	t.end = t.dat + t.len;
+	eread(fd, t.dat, t.len);
+	reset();
+	while(!t.done && t.p < t.end)
+		ev();
+	barf();
+	exits(nil);
+}