home *** CD-ROM | disk | FTP | other *** search
/ ftp.ee.lbl.gov / 2014.05.ftp.ee.lbl.gov.tar / ftp.ee.lbl.gov / bmd-1.0beta.tar.Z / bmd-1.0beta.tar / bmd-1.0beta / app / omtd / midi.c < prev    next >
C/C++ Source or Header  |  1991-08-21  |  7KB  |  363 lines

  1. /*
  2.  * Copyright (c) 1990 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that the above copyright notice and this paragraph are
  7.  * duplicated in all such forms and that any documentation,
  8.  * advertising materials, and other materials related to such
  9.  * distribution and use acknowledge that the software was developed
  10.  * by the University of California, Lawrence Berkeley Laboratory,
  11.  * Berkeley, CA.  The name of the University may not be used to
  12.  * endorse or promote products derived from this software without
  13.  * specific prior written permission.
  14.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  15.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  16.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  17.  */
  18. /*
  19.  * The midi hooks for mtd.  We handle all communication with the driver.
  20.  * We are at a fairly low level here.  All time stamps are unwarped, driver
  21.  * times, and all events are raw (i.e., note events are separate note on
  22.  * note off pairs).
  23.  */
  24.  
  25. #include <errno.h>
  26. #include <sys/file.h>
  27. #include <sys/types.h>
  28. #include <sys/ioctl.h>
  29. #include <sys/time.h>
  30. #include <sundev/midi.h>
  31. #include <signal.h>
  32.  
  33.  
  34. #include "setting.h"
  35. #include "event.h"
  36.  
  37. #ifndef MAX
  38. #define MAX(a,b) ((a)>(b)?(a):(b))
  39. #endif
  40.  
  41. static int midifd = -1;
  42. static u_long midirate;
  43.  
  44. static void
  45. midi_prune(pp, start, end)
  46.     struct event **pp;
  47.     u_long start;
  48.     u_long end;
  49. {
  50.     struct event *next;
  51.  
  52.     /* XXX This can be more efficient. */
  53.     while (*pp) {
  54.         if ((*pp)->m.mm_time < start || (*pp)->m.mm_time > end) {
  55.             next = (*pp)->next;
  56.             efree(*pp);
  57.             *pp = next;
  58.         } else
  59.             pp = &(*pp)->next;
  60.     }
  61. }
  62.  
  63. static void
  64. miditotv(mt, p)
  65.     u_long mt;
  66.     struct timeval *p;
  67. {
  68.     u_long usec = midirate * mt;
  69.  
  70.     p->tv_usec = usec % 1000000;
  71.     p->tv_sec = usec / 1000000;
  72. }
  73.  
  74. /*
  75.  * Read pending input into the input track.
  76.  * Events are unprocessed; when input track is merged into
  77.  * a play track, we will unwarp the timestamps and turn
  78.  * note_on/note_off pairs into "single note with duration" events.
  79.  */
  80. struct event **
  81. midi_read(pp, icnt, stop)
  82.     struct event **pp;
  83.     int *icnt;
  84.     u_long stop;
  85. {
  86.     register int cc;
  87.     register struct midi_msg *mp;
  88.     struct midi_msg buf[512];
  89.  
  90.     cc = read(midifd, (char *)buf, sizeof buf);
  91.     if (cc < 0) {
  92.         perror("read");
  93.         exit(1);
  94.     }
  95.     *icnt += cc / sizeof(*mp);
  96.     for (mp = buf; cc > 0; cc -= sizeof(*mp)) {
  97.         *pp = ealloc();
  98.         (*pp)->m = *mp++;
  99.         pp = &(*pp)->next;
  100.     }
  101.     *pp = 0;
  102.     return pp;
  103. }
  104.  
  105. /*
  106.  * Called knowing that a write will not block.
  107.  */
  108. struct event *
  109. midi_write(workahead, front, click)
  110.     u_long workahead;
  111.     struct event *front;
  112.     struct event *click;
  113. {
  114.     struct event **pp, *tmp;
  115. #define NMSG 64
  116.     struct midi_msg msgbuf[NMSG], *mp;
  117.     int maxmsg, nmsg, cc;
  118.  
  119.     pp = &front;
  120.  
  121.     if (ioctl(midifd, BMDNWRITE, (char *)&maxmsg) < 0) {
  122.         perror("BMDNWRITE");
  123.         exit(1);
  124.     }
  125.     if (maxmsg == 0)
  126.         abort();
  127.     if (maxmsg > NMSG)
  128.         maxmsg = NMSG;
  129.  
  130.     mp = msgbuf;
  131.     for (nmsg = 0; nmsg < maxmsg; ++nmsg) {
  132.         if (click && click->m.mm_time <= workahead &&
  133.             (*pp == 0 || click->m.mm_time <= (*pp)->m.mm_time)) {
  134.             *mp++ = click->m;
  135.             advance_click(click);
  136.         } else if (*pp != 0 && (*pp)->m.mm_time <= workahead) {
  137.             *mp++ = (*pp)->m;
  138.             pp = &(*pp)->next;
  139.         } else
  140.             break;
  141.     }
  142.     if (nmsg > 0) {
  143.         cc = write(midifd, (char *)msgbuf,
  144.                nmsg * sizeof(struct midi_msg));
  145.         if (cc < 0) {
  146.             perror("write");
  147.             exit(1);
  148.         }
  149.         if (cc != nmsg * sizeof(struct midi_msg)) {
  150.             /* 
  151.              * This shouldn't happen.
  152.              */
  153.             error("midi_write: driver did a partial write");
  154.             exit(1);
  155.         }
  156.     }
  157.     /*
  158.      * Free the amount we wrote, and return the rest.
  159.      */
  160.     tmp = *pp;
  161.     *pp = 0;
  162.     efreel(front);
  163.  
  164.     return tmp;
  165. #undef NMSG
  166. }
  167.  
  168. static int interrupted;
  169.  
  170. static void
  171. midiintr()
  172. {
  173.     interrupted = 1;
  174. }
  175.  
  176. #define WORKAHEAD 3000
  177. /*
  178.  * Start up output.  Enable record.
  179.  */
  180. struct event *
  181. midi_run(time_start, time_end, output, click)
  182.     u_long time_start;
  183.     u_long time_end;
  184.     struct event *output;
  185.     struct event *click;
  186. {
  187.     struct event *input, **intail;
  188.     void (*oldfn)();
  189.     fd_set wset, rset;
  190.     int wfd, width;
  191.     struct timeval tv;
  192.     u_long t;
  193.     int icnt = 0;
  194.  
  195.     tv.tv_sec = WORKAHEAD / 1000;
  196.     tv.tv_usec = 0;
  197.     interrupted = 0;
  198.     oldfn = signal(SIGINT, midiintr);
  199.     midiflush();
  200.     midireset(time_start); /* XXX */
  201.     intail = &input;
  202.     wfd = dup(midifd);
  203.     if (wfd < 0) {
  204.         perror("dup");
  205.         exit(1);
  206.     }
  207.     width = MAX(wfd, midifd) + 1;
  208.     while (!interrupted && (t = miditime()) <= time_end) {
  209.         FD_ZERO(&wset);
  210.         if (output && output->m.mm_time < t + WORKAHEAD)
  211.             FD_SET(wfd, &wset);
  212.         FD_ZERO(&rset);
  213.         FD_SET(midifd, &rset);
  214.         if (select(width, &rset, &wset, 0, &tv) < 0) {
  215.             if (errno == EINTR)
  216.                 continue;
  217.             perror("select");
  218.             exit(1);
  219.         }
  220.         if (FD_ISSET(wfd, &wset))
  221.             output = midi_write(t + WORKAHEAD, output, click);
  222.         if (FD_ISSET(midifd, &rset))
  223.             intail = midi_read(intail, &icnt);
  224.     }
  225.     intail = midi_read(intail, &icnt);
  226.     *intail = 0;
  227.     midi_prune(&input, time_start, time_end);
  228.     /* Free any remaining output. */
  229.     efreel(output);
  230.     midishutup();
  231.  
  232.     close(wfd);
  233.     printf("Read %d events\n", icnt);
  234.  
  235.     (void)signal(SIGINT, oldfn);
  236.  
  237.     return input;
  238. }
  239.  
  240. midiflush()
  241. {
  242.     if (ioctl(midifd, BMDFLUSH, (char *)0) < 0) {
  243.         perror("BMDFLUSH");
  244.         exit(1);
  245.     }
  246. }
  247.  
  248. midi_open(flag, port)
  249.     int flag;
  250.     int port;
  251. {
  252.     int fd;
  253.     int n = 0;
  254.     char device[sizeof "/dev/midi000"];
  255.     /*
  256.      * Go through all the minors and find one that isn't in use.
  257.      */
  258.     do {
  259.         (void)sprintf(device, "/dev/midi%d", n++);
  260.         fd = open(device, flag);
  261.     } while (fd < 0 && errno == EBUSY);
  262.  
  263.     if (fd < 0) {
  264.         perror(device);
  265.         exit(1);
  266.     }
  267.     if (ioctl(fd, BMDATTACH, (char *)&port) < 0) {
  268.         perror("BMDATTACH");
  269.         exit(1);
  270.     }
  271.     return fd;
  272. }
  273.  
  274. initmidi()
  275. {
  276.     u_long filter;
  277.     midifd = midi_open(O_RDWR, 1);
  278.  
  279.     midirate = 0;
  280.     if (ioctl(midifd, BMDRATE, &midirate) < 0 || midirate == 0) {
  281.         perror("MIDIRATE");
  282.         exit(1);
  283.     }
  284.     s.ticks_per_beat = (60.0 / BASETEMPO) * 1e6 / midirate;
  285.     /* XXX */
  286.     s.beats_per_bar = 4;
  287.  
  288.     filter = MIDIMASK(0xf0)|MIDIMASK(0xfe);
  289.     if (ioctl(midifd, BMDFILTER, &filter) < 0) {
  290.         perror("BMDFILTER");
  291.         exit(1);
  292.     }
  293.     if (fcntl(midifd, F_SETFL, FNDELAY) < 0) {
  294.         perror("F_SETFL");
  295.         exit(1);
  296.     }
  297. #ifdef notdef
  298.     if (ioctl(midifd, FIONBIO, 0) < 0) {
  299.         perror("FNBIO");
  300.         exit(1);
  301.     }
  302. #endif
  303. }
  304.  
  305. midishutup()
  306. {
  307.     int cc, i;
  308.     /* All notes off message. */
  309.     struct midi_msg m = { 0, { 0xb0, 123, 0 } };
  310.  
  311.     if (midifd < 0)
  312.         return;
  313.  
  314.     if (ioctl(midifd, BMDFLUSH, (char *)0) < 0) {
  315.         perror("BMDFLUSH");
  316.         exit(1);
  317.     }
  318.     i = 0;
  319.     /*
  320.      * Assume all output will make it since we just did a flush.
  321.      * (i.e., we don't check for cc == 0)
  322.      */
  323.     for (i = 0; i < 16; ++i) {
  324.         m.mm_data[0] = 0xb0 | i;
  325.         cc = write(midifd, &m, sizeof(m));
  326.         if (cc < 0) {
  327.             perror("write");
  328.             exit(1);
  329.         }
  330.     }
  331. }
  332.  
  333. miditime()
  334. {
  335.     u_long x;
  336.  
  337.     if (ioctl(midifd, BMDGTIME, &x) < 0) {
  338.         perror("BMDGTIME");
  339.         exit(1);
  340.     }
  341.     return x;
  342. }
  343.     
  344. midireset(time)
  345.     u_long time;
  346. {
  347.     if (ioctl(midifd, BMDSTIME, (char *)&time) < 0) {
  348.         perror("BMDSTIME");
  349.         exit(1);
  350.     }
  351. }
  352.  
  353. midiecho(chan)
  354.     int chan;
  355. {
  356.     u_int uchan = chan;
  357.  
  358.     if (ioctl(midifd, BMDECHO, (char *)&uchan) < 0) {
  359.         perror("BMDECHO");
  360.         exit(1);
  361.     }
  362. }
  363.