Path: utzoo!mnetor!uunet!husc6!rutgers!iuvax!pur-ee!j.cc.purdue.edu!ain From: ain@j.cc.purdue.edu (Patrick White) Newsgroups: comp.sources.amiga Subject: midi library (example code) Message-ID: <6773@j.cc.purdue.edu> Date: 25 Mar 88 04:28:10 GMT Organization: PUCC Land, USA Lines: 788 Keywords: midi, library, docs Approved: ain@j.cc.purdue.edu (Pat White) Program Name: midi library (example code) Submitted By: Pete Yadlowsky Summary: This is a midi library Poster Boy: Pat White (ain@j.cc.purdue.edu) Untested. NOTES: Not much we could do to test this, so we didn't bother. I reshar'ed it to separate docs, etc. example source -- Pat White (co-moderator comp.sources/binaries.amiga) UUCP: j.cc.purdue.edu!ain BITNET: PATWHITE@PURCCVM PHONE: (317) 743-8421 U.S. Mail: 320 Brown St. apt. 406, West Lafayette, IN 47906 ======================================== # This is a shell archive. # Remove everything above and including the cut line. # Then run the rest of the file through sh. #----cut here-----cut here-----cut here-----cut here----# #!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # hr.c # ht.c # makefile # r.c # rsx.c # tsx.c # This archive created: Sun Mar 20 16:42:58 1988 # By: Patrick White (PUCC Land, USA) echo shar: extracting hr.c '(2589 characters)' cat << \SHAR_EOF > hr.c /* hex receive from midi.library */ /* display incoming MIDI messages in Hex to the console. Shows proper method of waiting for, receiving, processing, and disposing of MIDI messages. */ #include #include #include #include #include void *MidiBase; struct MDest *dest; struct MRoute *route; UBYTE *msg; /* buffer this in case we get shut down before freeing the current message */ main(argc,argv) char **argv; { char *sname = "MidiIn"; static struct MRouteInfo routeinfo = { -1, -1 }; /* route spec's: receive all */ printf ("MIDI Hex Display\n"); if (argc > 1 && *argv[1] == '?') { printf ("usage: hr [source]\n"); exit (1); } if (!(MidiBase = OpenLibrary (MIDINAME,MIDIVERSION))) { printf ("can't open midi.library\n"); goto clean; } if (argc > 1) { /* if there's an argument, use it as an alt. source name */ sname = argv[1]; } /* create out dest node (private) */ if (!(dest = CreateMDest (NULL,NULL))) { printf ("can't create Dest\n"); goto clean; } /* create out route to MidiIn or whatever the user specified */ if (!(route = MRouteDest (sname, dest, &routeinfo))) { printf ("can't create Route (can't find source \"%s\"?)\n",sname); goto clean; } process(dest); /* process until shutdown */ clean: cleanup(); } _abort() /* abort routine called when CTRL-C is hit (Aztec) */ { fflush(stdout); cleanup(); exit (1); } cleanup() { if (msg) FreeMidiMsg (msg); if (route) DeleteMRoute (route); if (dest) DeleteMDest (dest); if (MidiBase) CloseLibrary (MidiBase); } process (dest) struct MDest *dest; { ULONG flags = SIGBREAKF_CTRL_C | (1L << dest->DestPort->mp_SigBit); while (!(Wait(flags) & SIGBREAKF_CTRL_C)) { /* wait until we get a message or CTRL-C is hit, quit on CTRL-C */ while (msg = GetMidiMsg (dest)) { /* get a message */ dumpmsg (msg); /* print it */ FreeMidiMsg (msg); /* free it */ } } } dumpmsg (msg) UBYTE *msg; { long len = MidiMsgLength (msg); /* find out how long the message is */ if (*msg == MS_SYSEX) { /* if it's a System Exclusive message... */ dump (msg,MIN(len,8)); /* only print the first 8 bytes */ printf ("... (%ld bytes)\n",len); } else { /* otherwise */ dump (msg,MidiMsgLength(msg)); /* print the whole message */ printf ("\n"); } } dump (s,len) /* print len bytes in hex */ UBYTE *s; long len; { while (len--) printf ("%02x ",*s++); } SHAR_EOF if test 2589 -ne "`wc -c hr.c`" then echo shar: error transmitting hr.c '(should have been 2589 characters)' fi echo shar: extracting ht.c '(1784 characters)' cat << \SHAR_EOF > ht.c /* simplified Hex Transmit to midi */ /* Shows usage of PutMidiStream() when buffer size is known and of managable size. */ #include #include void *MidiBase; main (argc,argv) char **argv; { struct MSource *source=0; struct MRoute *route=0; static struct MRouteInfo routeinfo = { -1, -1 }; /* route spec's: transmit all */ char buf[128]; /* buffer used for midi transfer */ long len; extern int Enable_Abort; Enable_Abort = 0; /* disable auto CTRL-C termination */ if (argc < 2) { printf ("MIDI Hex Transmit\n"); printf ("usage: ht ...\n"); exit (1); } if (!(MidiBase = OpenLibrary (MIDINAME,MIDIVERSION))) { printf ("can't open midi.library\n"); goto clean; } /* create our Source node (private) */ if (!(source = CreateMSource (NULL,NULL))) { printf ("can't create Source\n"); goto clean; } /* create out Route to MidiOut */ if (!(route = MRouteSource (source,"MidiOut",&routeinfo))) { printf ("can't create Route (can't find MidiOut?)\n"); goto clean; } /* parse the command line for hex bytes, make into an array */ len = makestream (buf,argc-1,argv+1); /* convert array to midi messages and send */ PutMidiStream (source,NULL,buf,len,len); clean: /* clean up */ if (route) DeleteMRoute (route); if (source) DeleteMSource (source); if (MidiBase) CloseLibrary (MidiBase); } makestream (buf,argc,argv) /* convert args into an array of bytes, return length */ char *buf; char **argv; { int len=0; while (argc--) { *buf++ = atox(*argv++); len++; } return len; } atox(cp) /* like atoi() but read string as hex rather than decimal */ char *cp; { int x; sscanf (cp,"%x",&x); return x; } SHAR_EOF if test 1784 -ne "`wc -c ht.c`" then echo shar: error transmitting ht.c '(should have been 1784 characters)' fi echo shar: extracting makefile '(190 characters)' cat << \SHAR_EOF > makefile all: ht hr rsx tsx r ht: ht.o ln +q ht.o -lmidi -lc hr: hr.o ln +q hr.o -lmidi -lc rsx: rsx.o ln +q rsx.o -lmidi -lc tsx: tsx.o ln +q tsx.o -lmidi -lc r: r.o ln +q r.o -lmidi -lc SHAR_EOF if test 190 -ne "`wc -c makefile`" then echo shar: error transmitting makefile '(should have been 190 characters)' fi echo shar: extracting r.c '(7600 characters)' cat << \SHAR_EOF > r.c /* simple MIDI router */ /* This is considered an example even though it's included with the utility set. It shows methods for scanning public node lists and managing routes to public nodes. This might be used as the skeleton for a graphics-based route manager. */ #include #include #include #include #define DeclareMinList(list)\ struct MinList list = { (void *)&list.mlh_Tail, NULL, (void *)&list.mlh_Head } struct MidiBase *MidiBase; DeclareMinList(routelist); /* list or MRoutePtr's for maintaining routes that we create */ main() { char b[128]; extern int Enable_Abort; Enable_Abort = 0; /* disable CTRL-C */ if (!(MidiBase = (void *)OpenLibrary (MIDINAME,MIDIVERSION))) { printf ("can't open midi.library\n"); goto clean; } printf ("MIDI Router (type ? for help)\n"); /* process commands */ for (;;) { printf ("route> "); if (gets(b) && !parse(b)) break; } clean: if (MidiBase) CloseLibrary (MidiBase); } parse(s) char *s; { switch (tolower(*s++)) { case 'x': /* quit */ case 'q': zaproutelist(); return 0; case 'l': /* list */ list(); break; case 'a': /* add */ addroute(s); break; case 'm': /* modify */ modroute(s); break; case 'r': /* remove */ remroute(s); break; case 'h': /* help */ case '?': help(); break; } return 1; } help() { printf ("\n"); printf ("Simple MIDI Router\n"); printf (" ? - help\n"); printf (" a - add a route\n"); printf (" m - modify a route\n"); printf (" r - rem a route\n"); printf (" l - list\n"); printf (" q - quit\n"); printf ("\n"); } list() { /* list public sources */ printf ("\nSources:\n"); listnames (&MidiBase->SourceList); /* list public dests */ printf ("\nDests:\n"); listnames (&MidiBase->DestList); /* list our routes */ printf ("\nRoutes:\n"); listroutes(); printf ("\n"); } /* Lists names in a specified list (like MidiBase->SourceList or MidiBase->DestList). This requires locking the lists to prevent changes while scanning them. Ideally, if a similar routine is going to take any large amount of time or can be halted by the user in mid-stream, it should take a snapshot of all the data it wishes to handle rather than locking the lists for the whole process. Locking the lists prevents anyone else from Creating or Deleting a node or Finding a node. */ listnames(list) struct List *list; { struct Node *node; LockMidiBase(); for (node = list->lh_Head; node->ln_Succ; node=node->ln_Succ) { printf (" %s\n",node->ln_Name); } UnlockMidiBase(); } /* Displays our route list. */ listroutes() { struct MinNode *node; int i; for (i=0,node = routelist.mlh_Head; node->mln_Succ; i++,node=node->mln_Succ) { prtroute (i,node); } } /* Displays info about one of our routes. In order to display the node names, we need to lock the lists to ensure validity of the nodes. This one is done correctly: it locks the lists, copies the names of the nodes if present, unlocks the lists, and THEN prints. */ prtroute (i,rp) struct MRoutePtr *rp; { struct MRoute *route = rp->Route; struct MRouteInfo *ri = &route->RouteInfo; struct MSource *source; struct MDest *dest; char sname[64], dname[64]; LockMidiBase(); /* lock node lists */ if (source = route->Source) { /* if the source still exists */ if (source->Node.ln_Name) /* and it has a name (public, for this program this should always be true) */ sprintf (sname,"\"%s\"",source->Node.ln_Name); /* copy the name */ else strcpy (sname,"(private)"); } else { strcpy (sname,"(removed)"); } if (dest = route->Dest) { /* do the same for the dest */ if (dest->Node.ln_Name) sprintf (dname,"\"%s\"",dest->Node.ln_Name); else strcpy (dname,"(private)"); } else { strcpy (dname,"(removed)"); } UnlockMidiBase(); /* unlock the lists */ /* print */ printf (" %2d: %08lxH %s->%s %04x %04x %d %d\n", i, route, sname, dname, ri->MsgFlags, ri->ChanFlags, ri->ChanOffset, ri->NoteOffset); } /* delete all routes in our route list, used on exit */ zaproutelist() { struct MRoutePtr *rp; while (rp = (struct MRoutePtr *)RemHead(&routelist)) { DeleteMRoute(rp->Route); free (rp); } } /* adds a new route based on the command line in s */ addroute(s) char *s; { char sname[64],dname[64]; struct MRouteInfo ri; struct MRoutePtr *rp=NULL; struct MRoute *route=NULL; int chanoffset,noteoffset; void *calloc(); setmem (&ri,sizeof ri,0); if (sscanf (s,"%s%s%x%x%d%d",sname,dname,&ri.MsgFlags,&ri.ChanFlags,&chanoffset,¬eoffset) != 6) { printf ("syntax error\n"); goto clean; } ri.ChanOffset = chanoffset; ri.NoteOffset = noteoffset; /* allocate a RoutePtr to hold ptr to our route */ if (!(rp = calloc(1,sizeof *rp))) { printf ("out of memory\n"); goto clean; } /* try to create the route */ if (!(route = MRoutePublic(sname,dname,&ri))) { printf ("error creating route\n"); goto clean; } rp->Route = route; /* set route pointer in our list */ AddTail (&routelist,rp); /* add to our list */ printf (" Route %d added.\n",findpos (&routelist,rp)); return 0; clean: if (route) DeleteMRoute (route); if (rp) free (rp); return -1; } /* modifies a existing route based on the command line in s */ modroute(s) char *s; { int num; struct MRouteInfo ri; struct MRoutePtr *rp; struct Node *findnode(); int chanoffset,noteoffset; setmem (&ri,sizeof ri,0); if (sscanf (s,"%d%x%x%d%d",&num,&ri.MsgFlags,&ri.ChanFlags,&chanoffset,¬eoffset) != 5) { printf ("syntax error\n"); goto clean; } ri.ChanOffset = chanoffset; ri.NoteOffset = noteoffset; /* find our routeptr by position */ if (!(rp = (struct MRoutePtr *)findnode(&routelist,num))) { printf ("can't find route\n"); goto clean; } /* modify the route */ ModifyMRoute (rp->Route,&ri); printf (" Route %d modified.\n",num); return 0; clean: return -1; } /* removes the route specifed in the command line s */ remroute(s) char *s; { int num; struct MRoutePtr *rp; struct Node *findnode(); if (sscanf (s,"%d",&num) != 1) { printf ("syntax error\n"); goto clean; } /* find our route ptr by number */ if (!(rp = (struct MRoutePtr *)findnode(&routelist,num))) { printf ("can't find route\n"); goto clean; } /* remove from our list */ Remove (rp); DeleteMRoute (rp->Route); /* delete the route */ free (rp); /* free our route ptr */ printf (" Route %d removed.\n",num); return 0; clean: return -1; } /* finds a node by number */ struct Node *findnode (list,num) struct List *list; { struct Node *node; for (node = list->lh_Head; node->ln_Succ; node=node->ln_Succ) { if (!num--) return node; } return 0; } /* returns the ordinal position of a node within a list */ findpos (list,match) struct List *list; struct Node *match; { struct Node *node; int num; for (num=0,node = list->lh_Head; node->ln_Succ; num++,node=node->ln_Succ) { if (node==match) return num; } return -1; } SHAR_EOF if test 7600 -ne "`wc -c r.c`" then echo shar: error transmitting r.c '(should have been 7600 characters)' fi echo shar: extracting rsx.c '(2377 characters)' cat << \SHAR_EOF > rsx.c /* simplified receive system exclusive */ /* receives next sys/ex message and save it to a named file */ /* shows usage of GetMidiMsg(), MidiMsgLength(), FreeMidiMsg() and msg filtering with routes. */ #include #include #include #include void *MidiBase; main(argc,argv) char **argv; { extern int Enable_Abort; int fo; /* output file descriptor */ UBYTE *msg=0, *getmsg(); struct MDest *dest=0; struct MRoute *route=0; static struct MRouteInfo routeinfo = { MMF_SYSEX }; /* receive only sys/ex msg's */ char *fname; printf ("Receive Sys/Ex\n"); Enable_Abort = 0; /* disable auto CTRL-C handling */ if (argc < 2) { printf ("usage: rsx \n"); exit (1); } fname = argv[1]; /* get file name */ if (!(MidiBase = OpenLibrary (MIDINAME,MIDIVERSION))) { printf ("can't open midi.library\n"); goto clean; } /* create our dest node (private) */ if (!(dest = CreateMDest (NULL,NULL))) { printf ("can't create Dest\n"); goto clean; } /* create our route to MidiIn */ if (!(route = MRouteDest ("MidiIn", dest, &routeinfo))) { printf ("can't create Route (can't find MidiIn?)\n"); goto clean; } /* create our output file */ if ( (fo=creat(fname,0666)) == -1) { printf ("can't open %s\n",fname); goto clean; } /* wait for the next message, save it or skip if terminated */ if (msg = getmsg(dest)) { long len = MidiMsgLength(msg); /* get message length */ if (write (fo,msg,(int)len) != len || /* won't work for msg's bigger than 64K */ close(fo) == -1) { printf ("error writing file.\n"); } printf ("sys/ex file \"%s\" saved. (%ld bytes)\n",fname,len); } else { printf ("save aborted.\n"); close(fo); unlink(fname); } clean: if (msg) FreeMidiMsg (msg); if (route) DeleteMRoute (route); if (dest) DeleteMDest (dest); if (MidiBase) CloseLibrary (MidiBase); } /* waits for next msg (will be sys/ex because that's all that our route lets through). Returns pointer to message. If CTRL-C is hit before a message arrives, returns NULL */ UBYTE *getmsg (dest) struct MDest *dest; { ULONG flags = SIGBREAKF_CTRL_C | (1L << dest->DestPort->mp_SigBit); if (Wait(flags) & SIGBREAKF_CTRL_C) return 0; return GetMidiMsg (dest); } SHAR_EOF if test 2377 -ne "`wc -c rsx.c`" then echo shar: error transmitting rsx.c '(should have been 2377 characters)' fi echo shar: extracting tsx.c '(1879 characters)' cat << \SHAR_EOF > tsx.c /* simplified transmit sys/ex file */ /* actually transmits entire contents of file, not just sys/ex */ /* describes usage of PutMidiStream() limited buffer size and unknown stream length. */ #include #include #include void *MidiBase; static int fi; /* input file descriptor */ UBYTE buf[512]; /* buffer used for transfer */ main(argc,argv) char **argv; { struct MSource *source=0; struct MRoute *route=0; static struct MRouteInfo routeinfo = { -1, -1 }; /* support all msg's */ extern short Enable_Abort; char *fname; long fillbuffer(); printf ("Transmit Sys/Ex\n"); Enable_Abort = 0; /* disable auto CTRL-C handling */ if (argc < 2) { printf ("usage: tsx \n"); exit (1); } fname = argv[1]; /* get file name */ if (!(MidiBase = OpenLibrary (MIDINAME,MIDIVERSION))) { printf ("can't open midi.library\n"); goto clean; } /* create our source node (private) */ if (!(source = CreateMSource (NULL,NULL))) { printf ("can't create Source\n"); goto clean; } /* create our route to MidiOut */ if (!(route = MRouteSource (source,"MidiOut",&routeinfo))) { printf ("can't create Route (can't find MidiOut?)\n"); goto clean; } /* open input file */ if ( (fi=open(fname,O_RDONLY)) == -1) { printf ("can't open %s\n",fname); goto clean; } /* convert file to midi messages */ PutMidiStream (source,fillbuffer,buf,(long)sizeof buf,0L); clean: if (route) DeleteMRoute (route); if (source) DeleteMSource (source); if (MidiBase) CloseLibrary (MidiBase); } /* fill our buffer with data from the file, called by PutMidiStream() */ static long fillbuffer() { register long len; geta4(); /* Aztec small data model */ return (len = read(fi,buf,sizeof buf)) == -1 ? 0 : len; } SHAR_EOF if test 1879 -ne "`wc -c tsx.c`" then echo shar: error transmitting tsx.c '(should have been 1879 characters)' fi # End of shell archive exit 0