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 >
Wrap
C/C++ Source or Header
|
1991-08-27
|
9KB
|
547 lines
/*
* Copyright (c) 1990 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Lawrence Berkeley Laboratory,
* Berkeley, CA. The name of the University may not be used to
* endorse or promote products derived from this software without
* specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* mfplay - Convert a MIDI file to driver output.
* This code is derived from mftext.c distributed with Tim Thompson's
* midifile reader.
* Author: Steven McCanne (mccanne@ee.lbl.gov).
*/
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sundev/midi.h>
#include <signal.h>
#include <varargs.h>
#include "midifile.h"
int Dflag;
static FILE *F;
filegetc()
{
return getc(F);
}
int transpose;
double tempadj = 1;
FILE *efopen();
usage()
{
fprintf(stderr,
"usage: mfplay [ -D -d device -t transposition -T tempo_scale ] [ file ]\n");
}
main(argc, argv)
int argc;
char **argv;
{
int c, port = 1;
extern char *optarg;
extern int optind, opterr;
double atof();
while ((c = getopt(argc, argv, "c:Dp:t:T:")) != -1) {
switch(c) {
case 'c':
set_channel_table(optarg);
break;
case 'D':
++Dflag;
break;
case 'm':
set_mute_table(optarg);
break;
case 'p':
port = atoi(optarg);
break;
case 't':
transpose = atoi(optarg);
break;
case 'T':
tempadj = atof(optarg);
if (tempadj == 0)
tempadj = 1;
break;
case '?':
usage();
/* NOTREACHED */
}
}
if (argv[optind]) {
F = fopen(argv[optind], "r");
if (F == 0) {
perror(argv[optind]);
exit(1);
}
} else
F = stdin;
initfuncs();
Mf_getc = filegetc;
/*
* Read the whole thing in, and then play it.
*/
initmidi(port);
midifile();
fclose(F);
printf("\nPlaying file...\n\n");
play_it();
exit(0);
}
/* VARARGS */
void
error(va_alist)
va_dcl
{
register char *cp;
va_list ap;
(void)fprintf(stderr, "mfplay: ");
va_start(ap);
cp = va_arg(ap, char *);
(void)vfprintf(stderr, cp, ap);
va_end(ap);
if (*cp) {
cp += strlen(cp);
if (cp[-1] != '\n')
(void)fputc('\n', stderr);
}
exit(1);
/* NOTREACHED */
}
struct event {
struct event *e_next;
struct midi_msg e_m;
};
#define E_TIME(ep) ((ep)->e_m.mm_time)
int midifd;
struct event *events;
struct event **eventp;
int Division = 48;
int Tempo = 250000;
u_int midirate;
midicleanup()
{
int cc, i;
struct midi_msg m = { 0, { 0xb0, 123, 0 } };
if (midifd < 0)
return;
if (ioctl(midifd, BMDFLUSH, (char *)0) < 0) {
perror("BMDFLUSH");
exit(1);
}
i = 0;
/*
* Assume all output will go out since we just did a flush.
* (i.e., we don't check for cc == 0)
*/
for (i = 0; i < 16; ++i) {
m.mm_cmd = 0xb0 | i;
cc = write(midifd, &m, sizeof(m));
if (cc < 0) {
perror("write");
exit(1);
}
}
close(midifd);
exit(0);
}
int
midi_open(flag, port)
int flag;
int port;
{
int fd;
int n = 0;
char device[sizeof "/dev/midi000"];
/*
* Go through all the minors and find one that isn't in use.
*/
do {
(void)sprintf(device, "/dev/midi%d", n++);
fd = open(device, flag);
} while (fd < 0 && errno == EBUSY);
if (fd < 0) {
perror(device);
exit(1);
}
if (ioctl(fd, BMDATTACH, (char *)&port) < 0) {
perror("BMDATTACH");
exit(1);
}
return fd;
}
initmidi(port)
int port;
{
midifd = midi_open(O_WRONLY, port);
/* get the internal clock rate */
midirate = 0;
if (ioctl(midifd, BMDRATE, (char *)&midirate) < 0) {
perror("BMDRATE");
exit(1);
}
signal(SIGINT, midicleanup);
signal(SIGHUP, midicleanup);
}
write_event(p)
struct event *p;
{
int cc;
struct midi_msg m = p->e_m;
if ((m.mm_cmd & 0xf0) == 0x90 ||
(m.mm_cmd & 0xf0) == 0x80) {
m.mm_data[1] += transpose;
if (m.mm_data[1] >= 0x80)
m.mm_data[1] -= transpose;
}
cc = write(midifd, (char *)&m, sizeof m);
if (cc < 0) {
perror("write");
exit(1);
}
if (Dflag)
printf("%d %02x %02x %02x\n",
m.mm_time,
m.mm_data[0],
m.mm_data[1],
m.mm_data[2]);
return cc == sizeof(m);
}
midireset()
{
u_long t = 0;
if (ioctl(midifd, BMDSTIME, (char *)&t) < 0) {
perror("BMDSTIME");
exit(1);
}
}
miditime()
{
u_long x;
if (ioctl(midifd, BMDGTIME, &x) < 0) {
perror("BMDGTIME");
exit(1);
}
return x;
}
play_it()
{
struct event *p;
midireset();
for (p = events; p != 0; p = p->e_next)
write_event(p);
}
struct event *
new_event(ts, cmd, d1, d2)
u_long ts;
{
struct event *p;
p = (struct event *)malloc(sizeof(*p));
p->e_m.mm_time = ts;
p->e_m.mm_cmd = cmd;
p->e_m.mm_data[1] = d1;
p->e_m.mm_data[2] = d2;
p->e_m.mm_data[3] = 0;
p->e_next = 0;
return p;
}
mfp_header(format,ntrks,division)
{
printf("Header format=%d ntrks=%d division=%d\n",
format, ntrks, division);
Division = division;
}
mfp_trackstart()
{
eventp = &events;
}
mfp_trackend()
{
/* do nothing */
}
insert_event(cmd, d1, d2)
{
struct event **pp, *p;
u_long t = get_time();
pp = eventp;
while (*pp && E_TIME(*pp) < t)
pp = &(*pp)->e_next;
p = new_event(t, cmd, d1, d2);
p->e_next = *pp;
*pp = p;
eventp = &p->e_next;
}
int chan_tbl[16];
int mute_tbl[16];
int
xtod(c)
int c;
{
if (isdigit(c))
return c - '0';
if (islower(c))
return c - 'a';
return c - 'A';
}
set_channel_table(s)
char *s;
{
int i;
for (i = 0; i < 16 && *s; ++i)
chan_tbl[i] = xtod(*s++);
}
set_mute_table(s)
char *s;
{
while (*s)
mute_tbl[xtod(*s++) & 0xf] = 1;
}
mfp_event(cmd, chan, d1, d2)
{
chan &= 0xf;
if (mute_tbl[chan])
return;
insert_event(cmd | chan_tbl[chan & 0xf], d1, d2);
}
mfp_noteon(chan, pitch, vol)
{
mfp_event(0x90, chan, pitch, vol);
}
mfp_noteoff(chan, pitch, vol)
{
mfp_event(0x80, chan, pitch, vol);
}
mfp_pressure(chan, pitch, press)
{
mfp_event(0xa0, chan, pitch, press);
}
mfp_parameter(chan, control, value)
{
mfp_event(0xb0, chan, control, value);
}
mfp_pitchbend(chan, msb, lsb)
{
mfp_event(0xe0, chan, msb, lsb);
}
mfp_program(chan, program)
{
mfp_event(0xc0, chan, program, 0);
}
mfp_chanpressure(chan, press)
{
mfp_event(0xd0, chan, press, 0);
}
mfp_sysex(leng,mess)
char *mess;
{
printf("sysex ignored\n");
}
mfp_metamisc(type, leng, mess)
char *mess;
{
printf("Meta event, unrecognized, type=0x%02x leng=%d\n", type, leng);
}
mfp_metaspecial(type,leng,mess)
char *mess;
{
printf("Meta event, sequencer-specific, type=0x%02x leng=%d\n",
type, leng);
}
mfp_metatext(type, leng, mess)
char *mess;
{
static char *ttype[] = {
NULL,
"Text Event", /* type=0x01 */
"Copyright Notice", /* type=0x02 */
"Sequence/Track Name",
"Instrument Name", /* ... */
"Lyric",
"Marker",
"Cue Point", /* type=0x07 */
"Unrecognized"
};
int unrecognized = (sizeof(ttype)/sizeof(char *)) - 1;
register int n, c;
register char *p = mess;
if ( type < 1 || type > unrecognized )
type = unrecognized;
prtime();
printf("Meta Text, type=0x%02x (%s) leng=%d\n",type,ttype[type],leng);
printf(" Text = <");
for (n = 0; n < leng; ++n) {
c = *p++;
printf((isprint(c) || isspace(c)) ? "%c" : "\\0x%02x" , c);
}
printf(">\n");
}
mfp_metaseq(num)
{
prtime();
printf("Meta event, sequence number = %d\n",num);
}
mfp_metaeot()
{
prtime();
printf("Meta event, end of track\n");
}
mfp_keysig(sf,mi)
{
prtime();
printf("Key signature, sharp/flats=%d minor=%d\n",sf,mi);
}
mfp_tempo(tempo)
long tempo;
{
Tempo = tempo;
}
mfp_timesig(nn,dd,cc,bb)
{
int denom = 1;
while ( dd-- > 0 )
denom *= 2;
prtime();
printf(
"Time signature=%d/%d MIDI-clocks/click=%d 32nd-notes/24-MIDI-clocks=%d\n",
nn, denom, cc, bb);
}
mfp_smpte(hr,mn,se,fr,ff)
{
prtime();
printf("SMPTE, hour=%d minute=%d second=%d frame=%d fract-frame=%d\n",
hr, mn, se, fr, ff);
}
mfp_arbitrary(leng,mess)
char *mess;
{
prtime();
printf("Arbitrary bytes, leng=%d\n",leng);
}
get_time(t)
{
double d = Mf_currtime;
d *= Tempo;
d /= Division;
d /= midirate;
d /= tempadj;
return (int)(d + 0.5);
}
prtime()
{
printf("time=%d\n", get_time());
}
initfuncs()
{
Mf_error = (int (*)())error;
Mf_header = mfp_header;
Mf_starttrack = mfp_trackstart;
Mf_endtrack = mfp_trackend;
Mf_on = mfp_noteon;
Mf_off = mfp_noteoff;
Mf_pressure = mfp_pressure;
Mf_controller = mfp_parameter;
Mf_pitchbend = mfp_pitchbend;
Mf_program = mfp_program;
Mf_chanpressure = mfp_chanpressure;
Mf_sysex = mfp_sysex;
Mf_metamisc = mfp_metamisc;
Mf_seqnum = mfp_metaseq;
Mf_eot = mfp_metaeot;
Mf_timesig = mfp_timesig;
Mf_smpte = mfp_smpte;
Mf_tempo = mfp_tempo;
Mf_keysig = mfp_keysig;
Mf_sqspecific = mfp_metaspecial;
Mf_text = mfp_metatext;
Mf_arbitrary = mfp_arbitrary;
}