shithub: riscv

Download patch

ref: 3b9b7a6ab8b6e8c5eb37937b849d1e9f6106a386
parent: 2279c8609158c96b021fa437ee46c73b19bc179e
author: aiju <[email protected]>
date: Sat Apr 14 10:44:15 EDT 2012

added midi player

--- /dev/null
+++ b/sys/src/games/midi.c
@@ -1,0 +1,250 @@
+#include <u.h>
+#include <libc.h>
+
+enum { SAMPLE = 44100 };
+
+struct Tracker {
+	uchar *data;
+	char ended;
+	uvlong t;
+	uchar notes[16][128];
+	int cmd;
+} *tr;
+
+typedef struct Tracker Tracker;
+
+int fd, ofd, div, tempo = 500000, ntrack;
+uvlong T;
+int freq[128];
+
+void *
+emallocz(int size)
+{
+	void *v;
+	
+	v = malloc(size);
+	if(v == nil)
+		sysfatal("malloc: %r");
+	memset(v, 0, size);
+	return v;
+}
+
+int
+get8(Tracker *src)
+{
+	uchar c;
+
+	if(src == nil){
+		if(read(fd, &c, 1) == 0)
+			sysfatal("unexpected eof");
+		return c;
+	}
+	return *src->data++;
+}
+
+int
+get16(Tracker *src)
+{
+	int x;
+	
+	x = get8(src) << 8;
+	return x | get8(src);
+}
+
+int
+get32(Tracker *src)
+{
+	int x;
+	x = get16(src) << 16;
+	return x | get16(src);
+}
+
+int
+getvar(Tracker *src)
+{
+	int k, x;
+	
+	x = get8(src);
+	k = x & 0x7F;
+	while(x & 0x80){
+		k <<= 7;
+		x = get8(src);
+		k |= x & 0x7F;
+	}
+	return k;
+}
+
+int
+peekvar(Tracker *src)
+{
+	uchar *p;
+	int v;
+	
+	p = src->data;
+	v = getvar(src);
+	src->data = p;
+	return v;
+}
+
+void
+skip(Tracker *src, int x)
+{
+	if(x) do
+		get8(src);
+	while(--x);
+}
+
+uvlong
+tconv(int n)
+{
+	uvlong v;
+	
+	v = n;
+	v *= tempo;
+	v *= SAMPLE;
+	v /= div;
+	v /= 1000000;
+	return v;
+}
+
+void
+run(uvlong n)
+{
+	int samp, j, k, l, no[128];
+	uchar *s;
+	int t, f;
+	short u;
+	Tracker *x;
+	
+	samp = n - T;
+	if(samp <= 0)
+		return;
+	memset(no, 0, sizeof no);
+	for(x = tr; x < tr + ntrack; x++){
+		if(x->ended)
+			continue;
+		for(j = 0; j < 16; j++)
+			for(k = 0; k < 128; k++)
+				no[k] += x->notes[j][k];
+	}
+	s = emallocz(samp * 4);
+	for(l = 0; l < samp; l++){
+		t = 0;
+		for(k = 0; k < 128; k++){
+			f = (T % freq[k]) >= freq[k]/2 ? 1 : 0;
+			t += f * no[k];
+		}
+		u = t*10;
+		s[4 * l] = s[4 * l + 2] = u;
+		s[4 * l + 1] = s[4 * l + 3] = u >> 8;
+		T++;
+	}
+	write(ofd, s, samp * 4);
+	free(s);
+}
+
+void
+readevent(Tracker *src)
+{
+	uvlong l;
+	int n,t;
+	
+	l = tconv(getvar(src));
+	run(src->t += l);
+	t = get8(src);
+	if((t & 0x80) == 0){
+		src->data--;
+		t = src->cmd;
+		if((t & 0x80) == 0)
+			sysfatal("invalid midi");
+	}else
+		src->cmd = t;
+	switch(t >> 4){
+	case 0x8:
+		n = get8(src);
+		get8(src);
+		src->notes[t & 15][n] = 0;
+		break;
+	case 0x9:
+		n = get8(src);
+		src->notes[t & 15][n] = get8(src);
+		break;
+	case 0xB:
+		get16(src);
+		break;
+	case 0xC:
+		get8(src);
+		break;
+	case 0xF:
+		t = get8(src);
+		n = get8(src);
+		switch(t){
+		case 0x2F:
+			src->ended = 1;
+			break;
+		case 0x51:
+			tempo = get16(src) << 8;
+			tempo |= get8(src);
+			break;
+		case 5:
+			write(1, src->data, n);
+			skip(src, n);
+			break;
+		default:
+			print("unknown meta event type %.2x\n", t);
+		case 3: case 1: case 2: case 0x58: case 0x59: case 0x21:
+			skip(src, n);
+		}
+		break;
+	default:
+		sysfatal("unknown event type %x", t>>4);
+	}
+}
+
+void
+main(int argc, char **argv)
+{
+	int i, size;
+	uvlong t, mint;
+	Tracker *x, *minx;
+
+	if(argc != 2)
+		sysfatal("invalid arguments");
+	fd = open(argv[1], OREAD);
+	if(fd < 0)
+		sysfatal("open: %r");
+	ofd = open("/dev/audio", OWRITE);
+	if(ofd < 0)
+		sysfatal("ofd: %r");
+	if(get32(nil) != 0x4D546864 || get32(nil) != 6)
+		sysfatal("invalid file header");
+	get16(nil);
+	ntrack = get16(nil);
+	div = get16(nil);
+	tr = emallocz(ntrack * sizeof(*tr));
+	for(i = 0; i < ntrack; i++){
+		if(get32(nil) != 0x4D54726B)
+			sysfatal("invalid track header");
+		size = get32(nil);
+		tr[i].data = emallocz(size);
+		read(fd, tr[i].data, size);
+	}
+	for(i = 0; i < 128; i++)
+		freq[i] = SAMPLE / (440 * pow(1.05946, i - 69));
+	for(;;){
+		minx = nil;
+		mint = 0;
+		for(x = tr; x < tr + ntrack; x++){
+			if(x->ended)
+				continue;
+			t = tconv(peekvar(x)) + x->t;
+			if(t < mint || minx == nil){
+				mint = t;
+				minx = x;
+			}
+		}
+		if(minx == nil)
+			exits(nil);
+		readevent(minx);
+	}
+}
--- a/sys/src/games/mkfile
+++ b/sys/src/games/mkfile
@@ -12,6 +12,7 @@
 	glendy\
 	packet\
 	mandel\
+	midi\
 
 OFILES=
 HFILES=