[BACK]Return to midiplay.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / midiplay

Diff for /src/usr.bin/midiplay/Attic/midiplay.c between version 1.11 and 1.12

version 1.11, 2009/10/14 18:22:49 version 1.12, 2010/02/13 13:45:29
Line 32 
Line 32 
   
 #include <sys/types.h>  #include <sys/types.h>
 #include <sys/stat.h>  #include <sys/stat.h>
 #include <sys/ioctl.h>  #include <signal.h>
 #include <sys/midiio.h>  
   
 #include <stdio.h>  #include <stdio.h>
 #include <stdlib.h>  #include <stdlib.h>
 #include <limits.h>  #include <limits.h>
Line 42 
Line 40 
 #include <err.h>  #include <err.h>
 #include <unistd.h>  #include <unistd.h>
 #include <string.h>  #include <string.h>
   #include <sndio.h>
   
 #define DEVMUSIC "/dev/music"  
   
 struct track {  struct track {
         u_char *start, *end;          u_char *start, *end;
         u_long curtime;          u_long curtime;
Line 77 
Line 74 
 /* Number of bytes in a MIDI command */  /* Number of bytes in a MIDI command */
 #define MIDI_LENGTH(d) (midi_lengths[((d) >> 4) & 7])  #define MIDI_LENGTH(d) (midi_lengths[((d) >> 4) & 7])
   
   #define MIDI_IS_STATUS(d)       ((d) & 0x80)
   #define MIDI_IS_COMMON(d)       ((d) < 0xf0)
   #define MIDI_SYSEX_START        0xf0
   #define MIDI_SYSEX_STOP         0xf7
   
 void usage(void);  void usage(void);
 void send_event(seq_event_rec *);  void send_event(u_char, u_char *, u_int);
 void dometa(u_int, u_char *, u_int);  void dometa(u_int, u_char *, u_int);
 void midireset(void);  void midireset(void);
 void send_sysex(u_char *, u_int);  
 u_long getvar(struct track *);  u_long getvar(struct track *);
 void playfile(FILE *, char *);  void playfile(FILE *, char *);
 void playdata(u_char *, u_int, char *);  void playdata(u_char *, u_int, char *);
Line 126 
Line 127 
 usage(void)  usage(void)
 {  {
         printf("usage: "          printf("usage: "
                "%s [-glmqvx] [-d devno] [-f file] [-t tempo] [file ...]\n",                 "%s [-gmqvx] [-f device] [-t tempo] [file ...]\n",
                __progname);                 __progname);
         exit(1);          exit(1);
 }  }
   
 int showmeta = 0;  int showmeta = 0;
 int verbose = 0;  int verbose = 0;
 #define BASETEMPO 400000  u_int tempo = 60 * 1000000 / 100;       /* default tempo is 100bpm */
 u_int tempo = BASETEMPO;                /* microsec / quarter note */  
 u_int ttempo = 100;  
 int unit = 0;  
 int play = 1;  int play = 1;
 int fd;  struct mio_hdl *hdl;
   struct timespec ts, ts_last;
   
 void  void
 send_event(seq_event_rec *ev)  send_event(u_char status, u_char *data, u_int len)
 {  {
         /*          u_int i;
         printf("%02x %02x %02x %02x %02x %02x %02x %02x\n",  
                ev->arr[0], ev->arr[1], ev->arr[2], ev->arr[3],          if (verbose > 1) {
                ev->arr[4], ev->arr[5], ev->arr[6], ev->arr[7]);                  printf("MIDI %02x", status);
         */                  for (i = 0; i < len; i++)
         if (play)                          printf(" %02x", data[i]);
                 write(fd, ev, sizeof *ev);                  printf("\n");
           }
           if (play) {
                   mio_write(hdl, &status, 1);
                   mio_write(hdl, data, len);
           }
 }  }
   
 u_long  u_long
Line 213 
Line 217 
         /* General MIDI reset sequence */          /* General MIDI reset sequence */
         static u_char gm_reset[] = { 0x7e, 0x7f, 0x09, 0x01, 0xf7 };          static u_char gm_reset[] = { 0x7e, 0x7f, 0x09, 0x01, 0xf7 };
   
         send_sysex(gm_reset, sizeof gm_reset);          send_event(MIDI_SYSEX_START, gm_reset, sizeof gm_reset);
 }  }
   
 #define SYSEX_CHUNK 6  
 void  void
 send_sysex(u_char *p, u_int l)  
 {  
         seq_event_rec event;  
         u_int n;  
   
         event.arr[0] = SEQ_SYSEX;  
         event.arr[1] = unit;  
         do {  
                 n = SYSEX_CHUNK;  
                 if (l < n) {  
                         memset(&event.arr[2], 0xff, SYSEX_CHUNK);  
                         n = l;  
                 }  
                 memcpy(&event.arr[2], p, n);  
                 send_event(&event);  
                 l -= n;  
                 p += n;  
         } while (l > 0);  
 }  
   
 void  
 playfile(FILE *f, char *name)  playfile(FILE *f, char *name)
 {  {
         u_char *buf, *newbuf;          u_char *buf, *newbuf;
Line 275 
Line 257 
 }  }
   
 void  void
   sigalrm(int i)
   {
   }
   
   void
 playdata(u_char *buf, u_int tot, char *name)  playdata(u_char *buf, u_int tot, char *name)
 {  {
           long long delta_nsec = 0;
           u_int delta_ticks;
         int format, ntrks, divfmt, ticks, t, besttrk = 0;          int format, ntrks, divfmt, ticks, t, besttrk = 0;
         u_int len, mlen, status, chan;          u_int len, mlen;
         u_char *p, *end, byte, meta, *msg;          u_char *p, *end, byte, meta;
         struct track *tracks;          struct track *tracks;
         u_long bestcur, now;          u_long bestcur, now;
         struct track *tp;          struct track *tp;
         seq_event_rec event;  
   
         end = buf + tot;          end = buf + tot;
         if (verbose)          if (verbose)
Line 342 
Line 330 
          * curtime.  Execute the event, update the curtime and repeat.           * curtime.  Execute the event, update the curtime and repeat.
          */           */
   
         /*  
          * The ticks variable is the number of ticks that make up a quarter  
          * note and is used as a reference value for the delays between  
          * the MIDI events.  
          * The sequencer has two "knobs": the TIMEBASE and the TEMPO.  
          * The delay specified in TMR_WAIT_REL is specified in  
          * sequencer time units.  The length of a unit is  
          * 60*1000000 / (TIMEBASE * TEMPO).  
          * Set it to 1ms/unit (adjusted by user tempo changes).  
          */  
         t = 500 * ttempo / 100;  
         if (ioctl(fd, SEQUENCER_TMR_TIMEBASE, &t) < 0)  
                 err(1, "SEQUENCER_TMR_TIMEBASE");  
         t = 120;  
         if (ioctl(fd, SEQUENCER_TMR_TEMPO, &t) < 0)  
                 err(1, "SEQUENCER_TMR_TEMPO");  
         if (ioctl(fd, SEQUENCER_TMR_START, 0) < 0)  
                 err(1, "SEQUENCER_TMR_START");  
         now = 0;          now = 0;
           delta_nsec = 0;
           if (clock_gettime(CLOCK_MONOTONIC, &ts_last) < 0)
                   err(1, "clock_gettime");
         for (;;) {          for (;;) {
                 /* Locate lowest curtime */                  /* Locate lowest curtime */
                 bestcur = ~0;                  bestcur = ~0;
Line 376 
Line 349 
                         printf("DELAY %4ld TRACK %2d ", bestcur-now, besttrk);                          printf("DELAY %4ld TRACK %2d ", bestcur-now, besttrk);
                         fflush(stdout);                          fflush(stdout);
                 }                  }
                 if (now < bestcur) {                  while (now < bestcur) {
                         union {                          pause();
                                 u_int32_t i;                          if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0)
                                 u_int8_t b[4];                                  err(1, "clock_gettime");
                         } u;                          delta_nsec += 1000000000L * (ts.tv_sec - ts_last.tv_sec);
                         u_int32_t delta = bestcur - now;                          delta_nsec += ts.tv_nsec - ts_last.tv_nsec;
                         delta = (int)((double)delta * tempo / (1000.0*ticks));                          ts_last = ts;
                         u.i = delta;                          if (delta_nsec <= 0)
                         if (delta != 0) {                                  continue;
                                 event.arr[0] = SEQ_TIMING;                          delta_ticks = delta_nsec * ticks / (1000LL * tempo);
                                 event.arr[1] = TMR_WAIT_REL;                          delta_nsec -= 1000LL * delta_ticks * tempo / ticks;
                                 event.arr[4] = u.b[0];                          now += delta_ticks;
                                 event.arr[5] = u.b[1];  
                                 event.arr[6] = u.b[2];  
                                 event.arr[7] = u.b[3];  
                                 send_event(&event);  
                         }  
                 }                  }
                 now = bestcur;  
                 tp = &tracks[besttrk];                  tp = &tracks[besttrk];
                 byte = *tp->start++;                  byte = *tp->start++;
                 if (byte == MIDI_META) {                  if (byte == MIDI_META) {
Line 409 
Line 376 
                                 tp->status = byte;                                  tp->status = byte;
                         else                          else
                                 tp->start--;                                  tp->start--;
                         mlen = MIDI_LENGTH(tp->status);                          if (MIDI_IS_COMMON(tp->status)) {
                         msg = tp->start;                                  mlen = MIDI_LENGTH(tp->status);
                         if (verbose > 1) {                                  send_event(tp->status, tp->start, mlen);
                             if (mlen == 1)                          } else if (tp->status == MIDI_SYSEX_START) {
                                 printf("MIDI %02x (%d) %02x\n",  
                                        tp->status, mlen, msg[0]);  
                             else  
                                 printf("MIDI %02x (%d) %02x %02x\n",  
                                        tp->status, mlen, msg[0], msg[1]);  
                         }  
                         status = MIDI_GET_STATUS(tp->status);  
                         chan = MIDI_GET_CHAN(tp->status);  
                         switch (status) {  
                         case MIDI_NOTEOFF:  
                         case MIDI_NOTEON:  
                         case MIDI_KEY_PRESSURE:  
                                 SEQ_MK_CHN_VOICE(&event, unit, status, chan,  
                                                  msg[0], msg[1]);  
                                 send_event(&event);  
                                 break;  
                         case MIDI_CTL_CHANGE:  
                                 SEQ_MK_CHN_COMMON(&event, unit, status, chan,  
                                                   msg[0], 0, msg[1]);  
                                 send_event(&event);  
                                 break;  
                         case MIDI_PGM_CHANGE:  
                         case MIDI_CHN_PRESSURE:  
                                 SEQ_MK_CHN_COMMON(&event, unit, status, chan,  
                                                   msg[0], 0, 0);  
                                 send_event(&event);  
                                 break;  
                         case MIDI_PITCH_BEND:  
                                 SEQ_MK_CHN_COMMON(&event, unit, status, chan,  
                                                   0, 0,  
                                                   (msg[0] & 0x7f) |  
                                                   ((msg[1] & 0x7f) << 7));  
                                 send_event(&event);  
                                 break;  
                         case MIDI_SYSTEM_PREFIX:  
                                 mlen = getvar(tp);                                  mlen = getvar(tp);
                                 if (tp->status == MIDI_SYSEX_START)                                  send_event(MIDI_SYSEX_START, tp->start, mlen);
                                         send_sysex(tp->start, mlen);                          } else if (tp->status == MIDI_SYSEX_STOP) {
                                 else                                  mlen = getvar(tp);
                                         /* Sorry, can't do this yet */;                                  /* Sorry, can't do this yet */;
                                 break;                          } else {
                         default:  
                                 if (verbose)                                  if (verbose)
                                         printf("MIDI event 0x%02x ignored\n",                                          printf("MIDI event 0x%02x ignored\n",
                                                tp->status);                                                 tp->status);
Line 466 
Line 397 
                 else                  else
                         tp->curtime += getvar(tp);                          tp->curtime += getvar(tp);
         }          }
         if (ioctl(fd, SEQUENCER_SYNC, 0) < 0)  
                 err(1, "SEQUENCER_SYNC");  
   
  ret:   ret:
         free(tracks);          free(tracks);
 }  }
Line 477 
Line 405 
 main(int argc, char **argv)  main(int argc, char **argv)
 {  {
         int ch;          int ch;
         int listdevs = 0;  
         int example = 0;          int example = 0;
         int gmreset = 0;          int gmreset = 0;
         int nmidi;          char *file = NULL;
         char *file = DEVMUSIC;  
         struct synth_info info;  
         FILE *f;          FILE *f;
         const char *errstr;          const char *errstr;
           struct sigaction sa;
           struct itimerval it;
   
         while ((ch = getopt(argc, argv, "?d:f:glmqt:vx")) != -1) {          while ((ch = getopt(argc, argv, "?d:f:glmqt:vx")) != -1) {
                 switch (ch) {                  switch (ch) {
                 case 'd':  
                         unit = strtonum(optarg, 0, INT_MAX, &errstr);  
                         if (errstr)  
                                 errx(1, "unit is %s: %s", errstr, optarg);  
                         break;  
                 case 'f':                  case 'f':
                         file = optarg;                          file = optarg;
                         break;                          break;
                 case 'g':                  case 'g':
                         gmreset++;                          gmreset++;
                         break;                          break;
                 case 'l':  
                         listdevs++;  
                         break;  
                 case 'm':                  case 'm':
                         showmeta++;                          showmeta++;
                         break;                          break;
Line 509 
Line 428 
                         play = 0;                          play = 0;
                         break;                          break;
                 case 't':                  case 't':
                         ttempo = strtonum(optarg, 0, INT_MAX, &errstr);                          tempo = 60 * 1000000 /
                               strtonum(optarg, 40, 240, &errstr);
                         if (errstr)                          if (errstr)
                                 errx(1, "tempo is %s: %s", errstr, optarg);                                  errx(1, "tempo is %s: %s", errstr, optarg);
                         break;                          break;
Line 527 
Line 447 
         argc -= optind;          argc -= optind;
         argv += optind;          argv += optind;
   
         fd = open(file, O_WRONLY);          hdl = mio_open(file, MIO_OUT, 0);
         if (fd < 0)          if (hdl == NULL) {
                 err(1, "%s", file);                  fprintf(stderr, "failed to open MIDI output\n");
         if (ioctl(fd, SEQUENCER_NRMIDIS, &nmidi) < 0)                  exit(1);
                 err(1, "ioctl(SEQUENCER_NRMIDIS) failed, ");  
         if (nmidi == 0)  
                 errx(1, "Sorry, no MIDI devices available");  
         if (listdevs) {  
                 for (info.device = 0; info.device < nmidi; info.device++) {  
                         if (ioctl(fd, SEQUENCER_INFO, &info) < 0)  
                                 err(1, "ioctl(SEQUENCER_INFO) failed, ");  
                         printf("%d: %s\n", info.device, info.name);  
                 }  
                 exit(0);  
         }          }
         if (gmreset)          if (gmreset)
                 midireset();                  midireset();
   
           sa.sa_flags = SA_RESTART;
           sa.sa_handler = sigalrm;
           sigfillset(&sa.sa_mask);
           if (sigaction(SIGALRM, &sa, NULL) < 0)
                   err(1, "sigaction");
           it.it_interval.tv_sec = it.it_value.tv_sec = 0;
           it.it_interval.tv_usec = it.it_value.tv_usec = 1000;
           if (setitimer(ITIMER_REAL, &it, NULL) < 0)
                   err(1, "setitimer");
   
         if (example)          if (example)
                 playdata(sample, sizeof sample, "<Gubben Noa>");                  playdata(sample, sizeof sample, "<Gubben Noa>");
         else if (argc == 0)          else if (argc == 0)

Legend:
Removed from v.1.11  
changed lines
  Added in v.1.12