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 / midifile / mfplay.c < prev    next >
C/C++ Source or Header  |  1991-08-27  |  9KB  |  547 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.  * mfplay - Convert a MIDI file to driver output.
  19.  * This code is derived from mftext.c distributed with Tim Thompson's
  20.  * midifile reader.
  21.  * Author: Steven McCanne (mccanne@ee.lbl.gov).
  22.  */
  23. #include <stdio.h>
  24. #include <ctype.h>
  25. #include <errno.h>
  26. #include <sys/file.h>
  27. #include <sys/types.h>
  28. #include <sys/ioctl.h>
  29. #include <sundev/midi.h>
  30. #include <signal.h>
  31. #include <varargs.h>
  32.  
  33. #include "midifile.h"
  34.  
  35. int Dflag;
  36.  
  37. static FILE *F;
  38.  
  39. filegetc()
  40. {
  41.     return getc(F);
  42. }
  43.  
  44. int transpose;
  45. double tempadj = 1;
  46.  
  47. FILE *efopen();
  48.  
  49. usage()
  50. {
  51.     fprintf(stderr, 
  52. "usage: mfplay [ -D -d device -t transposition -T tempo_scale ] [ file ]\n");
  53. }
  54.  
  55. main(argc, argv)
  56.     int argc;
  57.     char **argv;
  58. {
  59.     int c, port = 1;
  60.  
  61.     extern char *optarg;
  62.     extern int optind, opterr;
  63.     double atof();
  64.     
  65.     while ((c = getopt(argc, argv, "c:Dp:t:T:")) != -1) {
  66.         switch(c) {
  67.  
  68.         case 'c':
  69.             set_channel_table(optarg);
  70.             break;
  71.  
  72.         case 'D':
  73.             ++Dflag;
  74.             break;
  75.  
  76.         case 'm':
  77.             set_mute_table(optarg);
  78.             break;
  79.  
  80.         case 'p':
  81.             port = atoi(optarg);
  82.             break;
  83.  
  84.         case 't':
  85.             transpose = atoi(optarg);
  86.             break;
  87.  
  88.         case 'T':
  89.             tempadj = atof(optarg);
  90.             if (tempadj == 0)
  91.                 tempadj = 1;
  92.             break;
  93.  
  94.         case '?':
  95.             usage();
  96.             /* NOTREACHED */
  97.         }
  98.     }
  99.     if (argv[optind]) {
  100.         F = fopen(argv[optind], "r");
  101.         if (F == 0) {
  102.             perror(argv[optind]);
  103.             exit(1);
  104.         }
  105.     } else
  106.         F = stdin;
  107.     
  108.     initfuncs();
  109.     Mf_getc = filegetc;
  110.     /*
  111.      * Read the whole thing in, and then play it.
  112.      */
  113.     initmidi(port);
  114.     midifile();
  115.     fclose(F);
  116.     printf("\nPlaying file...\n\n");
  117.     play_it();
  118.     exit(0);
  119. }
  120.  
  121. /* VARARGS */
  122. void
  123. error(va_alist)
  124.     va_dcl
  125. {
  126.     register char *cp;
  127.     va_list ap;
  128.  
  129.     (void)fprintf(stderr, "mfplay: ");
  130.  
  131.     va_start(ap);
  132.     cp = va_arg(ap, char *);
  133.     (void)vfprintf(stderr, cp, ap);
  134.     va_end(ap);
  135.     if (*cp) {
  136.         cp += strlen(cp);
  137.         if (cp[-1] != '\n')
  138.             (void)fputc('\n', stderr);
  139.     }
  140.     exit(1);
  141.     /* NOTREACHED */
  142. }
  143.  
  144. struct event {
  145.     struct event *e_next;
  146.     struct midi_msg e_m;
  147. };
  148. #define E_TIME(ep) ((ep)->e_m.mm_time)
  149.  
  150. int midifd;
  151. struct event *events;
  152. struct event **eventp;
  153.  
  154. int Division = 48;
  155. int Tempo = 250000;
  156. u_int midirate;
  157.  
  158. midicleanup()
  159. {
  160.     int cc, i;
  161.     struct midi_msg m = { 0, { 0xb0, 123, 0 } };
  162.     
  163.     if (midifd < 0)
  164.         return;
  165.     
  166.     if (ioctl(midifd, BMDFLUSH, (char *)0) < 0) {
  167.         perror("BMDFLUSH");
  168.         exit(1);
  169.     }
  170.     i = 0;
  171.     /*
  172.      * Assume all output will go out since we just did a flush.
  173.      * (i.e., we don't check for cc == 0)
  174.      */
  175.     for (i = 0; i < 16; ++i) {
  176.         m.mm_cmd = 0xb0 | i;
  177.         cc = write(midifd, &m, sizeof(m));
  178.         if (cc < 0) {
  179.             perror("write");
  180.             exit(1);
  181.         }
  182.     }
  183.     close(midifd);
  184.     exit(0);
  185. }
  186.  
  187. int
  188. midi_open(flag, port)
  189.     int flag;
  190.     int port;
  191. {
  192.     int fd;
  193.     int n = 0;
  194.     char device[sizeof "/dev/midi000"];
  195.     /*
  196.      * Go through all the minors and find one that isn't in use.
  197.      */
  198.     do {
  199.         (void)sprintf(device, "/dev/midi%d", n++);
  200.         fd = open(device, flag);
  201.     } while (fd < 0 && errno == EBUSY);
  202.  
  203.     if (fd < 0) {
  204.         perror(device);
  205.         exit(1);
  206.     }
  207.     if (ioctl(fd, BMDATTACH, (char *)&port) < 0) {
  208.         perror("BMDATTACH");
  209.         exit(1);
  210.     }
  211.     return fd;
  212. }
  213.  
  214. initmidi(port)
  215.     int port;
  216. {
  217.     midifd = midi_open(O_WRONLY, port);
  218.  
  219.     /* get the internal clock rate */
  220.     midirate = 0;
  221.     if (ioctl(midifd, BMDRATE, (char *)&midirate) < 0) {
  222.         perror("BMDRATE");
  223.         exit(1);
  224.     }
  225.     signal(SIGINT, midicleanup);
  226.     signal(SIGHUP, midicleanup);
  227. }
  228.  
  229. write_event(p)
  230.     struct event *p;
  231. {
  232.     int cc;
  233.     struct midi_msg m = p->e_m;
  234.     
  235.     if ((m.mm_cmd & 0xf0) == 0x90 || 
  236.         (m.mm_cmd & 0xf0) == 0x80) {
  237.         m.mm_data[1] += transpose;
  238.         if (m.mm_data[1] >= 0x80)
  239.             m.mm_data[1] -= transpose;
  240.     }
  241.     cc = write(midifd, (char *)&m, sizeof m);
  242.     if (cc < 0) {
  243.         perror("write");
  244.         exit(1);
  245.     }
  246.     if (Dflag)
  247.         printf("%d %02x %02x %02x\n",
  248.                m.mm_time,
  249.                m.mm_data[0], 
  250.                m.mm_data[1], 
  251.                m.mm_data[2]);
  252.     
  253.     return cc == sizeof(m);
  254. }
  255.  
  256. midireset()
  257. {
  258.     u_long t = 0;
  259.     if (ioctl(midifd, BMDSTIME, (char *)&t) < 0) {
  260.         perror("BMDSTIME");
  261.         exit(1);
  262.     }
  263. }
  264.  
  265. miditime()
  266. {
  267.     u_long x;
  268.     
  269.     if (ioctl(midifd, BMDGTIME, &x) < 0) {
  270.         perror("BMDGTIME");
  271.         exit(1);
  272.     }
  273.     return x;
  274. }
  275.  
  276. play_it()
  277. {
  278.     struct event *p;
  279.  
  280.     midireset();
  281.     for (p = events; p != 0; p = p->e_next)
  282.         write_event(p);
  283. }
  284.  
  285. struct event *
  286. new_event(ts, cmd, d1, d2)
  287.     u_long ts;
  288. {
  289.     struct event *p;
  290.     
  291.     p = (struct event *)malloc(sizeof(*p));
  292.     p->e_m.mm_time = ts;
  293.     p->e_m.mm_cmd = cmd;
  294.     p->e_m.mm_data[1] = d1;
  295.     p->e_m.mm_data[2] = d2;
  296.     p->e_m.mm_data[3] = 0;
  297.     p->e_next = 0;
  298.     
  299.     return p;
  300. }
  301.  
  302. mfp_header(format,ntrks,division)
  303. {
  304.     printf("Header format=%d ntrks=%d division=%d\n",
  305.            format, ntrks, division);
  306.     Division = division;
  307. }
  308.  
  309. mfp_trackstart()
  310. {
  311.     eventp = &events;
  312. }
  313.  
  314. mfp_trackend()
  315. {
  316.     /* do nothing */
  317. }
  318.  
  319. insert_event(cmd, d1, d2)
  320. {
  321.     struct event **pp, *p;
  322.     u_long t = get_time();
  323.  
  324.     pp = eventp;
  325.     while (*pp && E_TIME(*pp) < t)
  326.         pp = &(*pp)->e_next;
  327.     p = new_event(t, cmd, d1, d2);
  328.     p->e_next = *pp;
  329.     *pp = p;
  330.     eventp = &p->e_next;
  331. }
  332.  
  333. int chan_tbl[16];
  334. int mute_tbl[16];
  335.  
  336. int
  337. xtod(c)
  338.     int c;
  339. {
  340.     if (isdigit(c))
  341.         return c - '0';
  342.     if (islower(c))
  343.         return c - 'a';
  344.     return c - 'A';
  345. }
  346.  
  347. set_channel_table(s)
  348.     char *s;
  349. {
  350.     int i;
  351.  
  352.     for (i = 0; i < 16 && *s; ++i)
  353.         chan_tbl[i] = xtod(*s++);
  354. }
  355.  
  356. set_mute_table(s)
  357.     char *s;
  358. {
  359.     while (*s) 
  360.         mute_tbl[xtod(*s++) & 0xf] = 1;
  361. }
  362.  
  363. mfp_event(cmd, chan, d1, d2)
  364. {
  365.     chan &= 0xf;
  366.     if (mute_tbl[chan])
  367.         return;
  368.  
  369.     insert_event(cmd | chan_tbl[chan & 0xf], d1, d2);
  370. }
  371.  
  372. mfp_noteon(chan, pitch, vol)
  373. {
  374.     mfp_event(0x90, chan, pitch, vol);
  375. }
  376.  
  377. mfp_noteoff(chan, pitch, vol)
  378. {
  379.     mfp_event(0x80, chan, pitch, vol);
  380. }
  381.  
  382. mfp_pressure(chan, pitch, press)
  383. {
  384.     mfp_event(0xa0, chan, pitch, press);
  385. }
  386.  
  387. mfp_parameter(chan, control, value)
  388. {
  389.     mfp_event(0xb0, chan, control, value);
  390. }
  391.  
  392. mfp_pitchbend(chan, msb, lsb)
  393. {
  394.     mfp_event(0xe0, chan, msb, lsb);
  395. }
  396.  
  397. mfp_program(chan, program)
  398. {
  399.     mfp_event(0xc0, chan, program, 0);
  400. }
  401.  
  402. mfp_chanpressure(chan, press)
  403. {
  404.     mfp_event(0xd0, chan, press, 0);
  405. }
  406.  
  407. mfp_sysex(leng,mess)
  408.     char *mess;
  409. {
  410.     printf("sysex ignored\n");
  411. }
  412.  
  413. mfp_metamisc(type, leng, mess)
  414.     char *mess;
  415. {
  416.     printf("Meta event, unrecognized, type=0x%02x leng=%d\n", type, leng);
  417. }
  418.  
  419. mfp_metaspecial(type,leng,mess)
  420.     char *mess;
  421. {
  422.     printf("Meta event, sequencer-specific, type=0x%02x leng=%d\n",
  423.         type, leng);
  424. }
  425.  
  426. mfp_metatext(type, leng, mess)
  427.     char *mess;
  428. {
  429.     static char *ttype[] = {
  430.         NULL,
  431.         "Text Event",        /* type=0x01 */
  432.         "Copyright Notice",    /* type=0x02 */
  433.         "Sequence/Track Name",
  434.         "Instrument Name",    /* ...       */
  435.         "Lyric",
  436.         "Marker",
  437.         "Cue Point",        /* type=0x07 */
  438.         "Unrecognized"
  439.         };
  440.     int unrecognized = (sizeof(ttype)/sizeof(char *)) - 1;
  441.     register int n, c;
  442.     register char *p = mess;
  443.     
  444.     if ( type < 1 || type > unrecognized )
  445.         type = unrecognized;
  446.     prtime();
  447.     printf("Meta Text, type=0x%02x (%s)  leng=%d\n",type,ttype[type],leng);
  448.     printf("     Text = <");
  449.     for (n = 0; n < leng; ++n) {
  450.         c = *p++;
  451.         printf((isprint(c) || isspace(c)) ? "%c" : "\\0x%02x" , c);
  452.     }
  453.     printf(">\n");
  454. }
  455.  
  456. mfp_metaseq(num)
  457. {
  458.     prtime();
  459.     printf("Meta event, sequence number = %d\n",num);
  460. }
  461.  
  462. mfp_metaeot()
  463. {
  464.     prtime();
  465.     printf("Meta event, end of track\n");
  466. }
  467.  
  468. mfp_keysig(sf,mi)
  469. {
  470.     prtime();
  471.     printf("Key signature, sharp/flats=%d  minor=%d\n",sf,mi);
  472. }
  473.  
  474. mfp_tempo(tempo)
  475.     long tempo;
  476. {
  477.     Tempo = tempo;
  478. }
  479.  
  480. mfp_timesig(nn,dd,cc,bb)
  481. {
  482.     int denom = 1;
  483.     while ( dd-- > 0 )
  484.         denom *= 2;
  485.     prtime();
  486.     printf(
  487. "Time signature=%d/%d  MIDI-clocks/click=%d  32nd-notes/24-MIDI-clocks=%d\n",
  488.            nn, denom, cc, bb);
  489. }
  490.  
  491. mfp_smpte(hr,mn,se,fr,ff)
  492. {
  493.     prtime();
  494.     printf("SMPTE, hour=%d minute=%d second=%d frame=%d fract-frame=%d\n",
  495.            hr, mn, se, fr, ff);
  496. }
  497.  
  498. mfp_arbitrary(leng,mess)
  499.     char *mess;
  500. {
  501.     prtime();
  502.     printf("Arbitrary bytes, leng=%d\n",leng);
  503. }
  504.  
  505. get_time(t)
  506. {
  507.     double d = Mf_currtime;
  508.     
  509.     d *= Tempo;
  510.     d /= Division;
  511.     d /= midirate;
  512.     d /= tempadj;
  513.     
  514.     return (int)(d + 0.5);
  515. }
  516.  
  517. prtime()
  518. {
  519.     printf("time=%d\n", get_time());
  520. }
  521.  
  522. initfuncs()
  523. {
  524.     Mf_error = (int (*)())error;
  525.     Mf_header =  mfp_header;
  526.     Mf_starttrack =  mfp_trackstart;
  527.     Mf_endtrack =  mfp_trackend;
  528.     Mf_on =  mfp_noteon;
  529.     Mf_off =  mfp_noteoff;
  530.     Mf_pressure =  mfp_pressure;
  531.     Mf_controller =  mfp_parameter;
  532.     Mf_pitchbend =  mfp_pitchbend;
  533.     Mf_program =  mfp_program;
  534.     Mf_chanpressure =  mfp_chanpressure;
  535.     Mf_sysex =  mfp_sysex;
  536.     Mf_metamisc =  mfp_metamisc;
  537.     Mf_seqnum =  mfp_metaseq;
  538.     Mf_eot =  mfp_metaeot;
  539.     Mf_timesig =  mfp_timesig;
  540.     Mf_smpte =  mfp_smpte;
  541.     Mf_tempo =  mfp_tempo;
  542.     Mf_keysig =  mfp_keysig;
  543.     Mf_sqspecific =  mfp_metaspecial;
  544.     Mf_text =  mfp_metatext;
  545.     Mf_arbitrary =  mfp_arbitrary;
  546. }
  547.