ref: 55e0fd603151867eac865be660767dcc4289ed87
parent: 67b24e6dac5e9544171beb86ef657b71b87f9f5f
author: qwx <devnull@localhost>
date: Fri Aug 31 14:01:21 EDT 2018
dmid: add support for midi streams tested with a usb midi keyboard and a midi->usb adaptor
--- a/sys/man/1/dmid
+++ b/sys/man/1/dmid
@@ -4,7 +4,7 @@
.SH SYNOPSIS
.B dmid
[
-.B -2
+.B -2s
] [
.B -i
.I bank
@@ -33,6 +33,13 @@
.B -i
command line option.
.PP
+The
+.B -s
+flag enables streaming mode,
+in which the input file is a stream of MIDI events.
+The file needn't provide any timing information such as MIDI tics.
+This is suitable for MIDI instruments.
+.PP
In
.SM GENMIDI
lumps, two voices are defined per instrument.
@@ -55,6 +62,14 @@
createfile SW18_7: file already exists
% games/mus /mnt/wad/d_doom | games/dmid | games/opl3 >/dev/audio
.EE
+.PP
+Play a MIDI stream from a USB device (see
+.BR usb (3)):
+.IP
+.EX
+% games/wadfs /sys/games/lib/doom/doom2.wad >[2]/dev/null
+% games/dmid -s /dev/usb/ep10.1/data | games/opl3 >/dev/audio
+.EE
.SH SOURCE
.B /sys/src/games/dmid.c
.SH "SEE ALSO"
@@ -62,6 +77,7 @@
.IR mus (1) ,
.IR opl3 (1) ,
.IR audio (3) ,
+.IR usb (3) ,
.IR wadfs (4)
.SH HISTORY
.I Dmid
--- a/sys/src/games/dmid.c
+++ b/sys/src/games/dmid.c
@@ -1,6 +1,7 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
+#include <thread.h>
typedef struct Inst Inst;
typedef struct Opl Opl;
@@ -82,8 +83,9 @@
Trk *tr;
double freq[128];
-int mfmt, ntrk, div, tempo, opl2;
+int mfmt, ntrk, div = 1, tempo, opl2, stream;
uvlong T;
+Channel *echan;
Biobuf *ib, *ob;
void *
@@ -436,6 +438,29 @@
}
void
+tproc(void *)
+{
+ vlong t, Δt;
+ uchar u[4];
+ Trk x;
+
+ x.e = u + sizeof u;
+ t = nsec();
+ for(;;){
+ if(nbrecv(echan, u) > 0){
+ u[0] = 0;
+ x.p = u;
+ ev(&x);
+ }
+ putcmd(0, 0, 1);
+ t += 10000000 / (Rate / 100);
+ Δt = (t - nsec()) / 1000000;
+ if(Δt > 0)
+ sleep(Δt);
+ }
+}
+
+void
readinst(char *file)
{
int n;
@@ -475,6 +500,8 @@
Trk *x;
ib = file != nil ? bopen(file, OREAD) : bfdopen(0, OREAD);
+ if(stream)
+ return;
if(get32(nil) != 0x4d546864 || get32(nil) != 6)
sysfatal("invalid header");
mfmt = get16(nil);
@@ -501,16 +528,17 @@
void
usage(void)
{
- fprint(2, "usage: %s [-2] [-i inst] [mid]\n", argv0);
+ fprint(2, "usage: %s [-2s] [-i inst] [mid]\n", argv0);
exits("usage");
}
void
-main(int argc, char **argv)
+threadmain(int argc, char **argv)
{
int n, t, mint;
char *i;
double f;
+ uchar u[4];
Chan *c;
Opl *o;
Trk *x, *minx;
@@ -519,6 +547,7 @@
ARGBEGIN{
case '2': opl2 = 1; ople = opl + 9; break;
case 'i': i = EARGF(usage()); break;
+ case 's': stream = 1; break;
default: usage();
}ARGEND
readinst(i);
@@ -538,6 +567,18 @@
tempo = 500000;
putcmd(Rwse, Mwse, 0);
putcmd(Rop3, 1, 0);
+ if(stream){
+ if(proccreate(tproc, nil, mainstacksize) < 0)
+ sysfatal("proccreate: %r");
+ if((echan = chancreate(sizeof u, 0)) == nil)
+ sysfatal("chancreate: %r");
+ for(;;){
+ if((n = Bread(ib, u, sizeof u)) != sizeof u)
+ break;
+ send(echan, u);
+ }
+ threadexitsall(n < 0 ? "read: %r" : nil);
+ }
for(;;){
minx = nil;
mint = 0;