]> git.lizzy.rs Git - plan9front.git/commitdiff
dmid: add support for midi streams
authorqwx <devnull@localhost>
Fri, 31 Aug 2018 16:01:21 +0000 (18:01 +0200)
committerqwx <devnull@localhost>
Fri, 31 Aug 2018 16:01:21 +0000 (18:01 +0200)
tested with a usb midi keyboard and a midi->usb adaptor

sys/man/1/dmid
sys/src/games/dmid.c

index df4f72dd5817489a10fc58f578ba5c94de95a3d3..c04cb6a54e99c72c1805d86d8f3d8efc0d38801a 100644 (file)
@@ -4,7 +4,7 @@ dmid \- MIDI to OPL3 converter using GENMIDI-type instrument banks
 .SH SYNOPSIS
 .B dmid
 [
-.B -2
+.B -2s
 ] [
 .B -i
 .I bank
@@ -33,6 +33,13 @@ This may be overridden with the
 .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 @@ file:
 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 @@ createfile SW18_7: file already exists
 .IR mus (1) ,
 .IR opl3 (1) ,
 .IR audio (3) ,
+.IR usb (3) ,
 .IR wadfs (4)
 .SH HISTORY
 .I Dmid
index a7da7ea0e0937d17a2ecfdc1e0e28b7a0f75e240..254d42df9f688f4047c08f5535951541f23f6125 100644 (file)
@@ -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 @@ struct Trk{
 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 *
@@ -435,6 +437,29 @@ ev(Trk *x)
        }
 }
 
+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)
 {
@@ -475,6 +500,8 @@ readmid(char *file)
        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 @@ readmid(char *file)
 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 @@ main(int argc, char **argv)
        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 @@ main(int argc, char **argv)
        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;