allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (05/15/89)
Posting-number: Volume 6, Issue 107 Submitted-by: lee@uhccux.uhcc.Hawaii.Edu (Greg Lee ) Archive-name: glib/part06 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 6 (of 15)." # Contents: PORTING k1multi.mnu pc-ints.asm pc-mach.c # Wrapped by lee@uhccux on Sun May 7 00:40:13 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'PORTING' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'PORTING'\" else echo shar: Extracting \"'PORTING'\" \(12157 characters\) sed "s/^X//" >'PORTING' <<'END_OF_FILE' X$Id: PORTING,v 1.6 89/05/06 17:13:07 lee Exp $ X[Lee:] X XThe C source code for the various synth modules is generated by Xa program 'menutoc'. Although C source for 'menutoc' is included, Xrevising the program would require flex, the freely distributed "fast Xlex" to compile. But if you happen not to have flex, lex will serve -- Xsee the note in the Makefile and notes at the beginning of file Xmakemenu.l. X X --------------------------------- X[Kesti:] X XIn order to adapt it to the D-10's rather large data set, I have used glib's Xability to service multiple synths to instead service sub-sections of a single XD-10. These subsections are: X X Performance mode patches X Multi-timbral mode timbres X X Tone waveform generators X Tone time variant filters X Tone time variant amplifiers X X Rhythm setup X Rhythm patterns X Rhythm track X XBecause the memory requirement of a single program to service this much data Xis large enough to be cumbersome, I have broken the subsections into three Xseparate programs. These are d10patch, d10tone, and d10drum. X XThe tone services also require a separate program because, unlike all other Xservices, they must operate on a single common data set. This required Xchanges to the data memory allocation and other functions in glib.c. When Xcompiling d10tone, be sure to #define SINGLEDATA in glib.c to enable these Xchanges. X XI believe that I have maintained glib's ability to be compiled for Un*x X(using SysV curses), DOS, and the Atari ST. The sources supplied have Xbeen succesfully compiled and run on an AT&T 3b1, running v3.51 software; Xand an AT&T 6300 (with a V30 in the cpu socket), running AT&T's version of XDOS v3.20. Borland Turbo C v1.0 was used to produce the executables and the Xmachine was fitted with a CMS-401 interface. X XThe Makefile provided was used on the 3b1, and produces a single executable Xnamed glib that combines all services, but does not tie the tone data Xtogether as discussed above. This is presumably no problem, as the Un*x Xversion is intended to be for demo purposes. If your Un*x machine has a Xmidi interface, I'd like hear from you! X XThe Turbo C project files (*.prj) are used by the integrated environment to Xproduce glib.exe, d10patch.exe, d10tone.exe, and d10drum.exe. Be sure to Xuse the large memory model. It is not recommended that glib.exe be used, as Xit requires almost all the available memory of a 640K machine, and again, Xwould not tie the tone data together (SINGLEDATA should not be #defined Xwhen compiling for glib.exe.). X X[Lee:] X XI did not include the .prj files mentioned above. So many files Xalready! But below are the contents of those files. The file machdep.c Xis a copy of pc-mach.c (and pc-mach.h should be copied to machdep.h); Xthe d10*.c files except d10ton.c) must be constructed from the Xcorresponding d10*.mnu files by the menutoc program; and the files Xlistdrum.c, listpat.c, and listton.c are the same as file list.c, but Xwith '#defines' removed for the unused modules. That is to say, for the XD10 '#defines', keep only X #define D10urp X #define D10rsu X #define D10tra Xfor listdrum.c, keep only X #define D10pat X #define D10tim Xfor listpat.c, and keep only X #define D10wfg X #define D10tvf X #define D10tva Xfor listton.c. X:::::::::::::: Xcontents of file d10drum.prj X:::::::::::::: Xd10urp.c Xd10rsu.c Xd10tra.c Xglib.c Xlistdrum.c Xvis.c Xmachdep.c X:::::::::::::: Xcontents of file d10patch.prj X:::::::::::::: Xd10pat.c Xd10tim.c Xglib.c Xlistpat.c Xvis.c Xmachdep.c X:::::::::::::: Xcontents of file d10tone.prj X:::::::::::::: Xd10ton.c Xd10wfg.c Xd10tvf.c Xd10tva.c Xglib.c Xlisttone.c Xvis.c Xmachdep.c X:::::::::::::: Xcontents of file glib.prj X:::::::::::::: Xd10pat.c Xd10tim.c Xd10wfg.c Xd10ton.c Xd10tvf.c Xd10tva.c Xd10urp.c Xd10rsu.c Xd10tra.c Xglib.c Xlist.c Xvis.c Xmachdep.c X---------------------- X X X[Thompson:] X XCompiling X--------- Xmachdep.c and machdep.h are machine-dependent parts. The *-mach.h and X*-mach.c files are the versions of these files for different machines, Xe.g. unix-mach.[ch] is for UNIX, st-mach.[ch] is for the Atari ST. XCopy the proper files to machdep.c and machdep.h before compiling Xfor a particular machine. For example, on UNIX, do the following: X X cp unix-mach.c machdep.c X cp unix-mach.h machdep.h X make glib X XThe contents of list.c control which synths are supported; modify Xthe defines at the beginning of that file appropriately. When Xcompiling, you need to include glib.c and the appropriate synth Xfiles (e.g. if you define DW8000 in list.c, then you need to compile Xwith dw8000.c). A single version of glib can support as many synths Xas you want, although some compilers may have size limitations or Xoverlay schemes that get in the way. X X XHacking glib - Internals X------------------------ XThe program is written so that support for a new synth can be added by Xadding an entry to the array in list.c, describing the various attributes Xof the synthesizer and the C functions to be called to control it. And, of Xcourse, you have to write those C functions. Adding a new synth, for a Xreasonable C programmer, might be described as mostly straightforward but Xtedious. People other than the original author HAVE done it, with no help. XGlib allows you to re-use the front-end interface of the librarian and Xeditor, but it does not relieve you of having to write C code which Xinteracts with the synth (which, depending on the synth, can of course be Xeasy or maddening) and with the raw data formats. Naturally, using one of Xthe existing synth files as an example of how to do things is the best way Xto start on a new one. X XThe 'E' array in list.c has the following structure: X Xstruct editinfo { X char *ed_name; /* Synth name */ X struct paraminfo *ed_params; /* list of parameters */ X struct labelinfo *ed_labels; /* screen labels in edit mode */ X int ed_nvoices; /* number of voices */ X int ed_vsize; /* size of each voice data, in bytes */ X int ed_nsize; /* name size */ X int ed_dataid; /* data ID */ X int (*ed_din)(); /* copy voice data into paraminfo array */ X int (*ed_dout)(); /* copy voice data out of paraminfo array */ X int (*ed_sedit)(); /* send 1 voice to synth edit buffer */ X int (*ed_sone)(); /* send 1 voice to a synth (permanent) patch*/ X int (*ed_sbulk)(); /* send bulk voice data */ X int (*ed_gbulk)(); /* get bulk voice data */ X char *(*ed_nof)(); /* get name of a voice out of data */ X int (*ed_snof)(); /* set name of a voice in data */ X char *(*ed_numof)(); /* convert voice number to on-screen text */ X int (*ed_cvtnum)(); /* convert visable voice number to std. format */ X}; X XIn glib, there are several relatively independent representations of the Xsynth voice data. First, there is the data that is stored in the Xlibrary and synth banks (ie. the data used and manipulated via the Xlibrarian screen). This is the format of the data that is written to Xand read from files (a single byte, given as 'ed_dataid' above, is added Xto the beginning of the file, to identify it). The size of a single Xvoice in this data is 'ed_vsize'. The number of voices in a bank is X'ed_nvoices', so the amount of space taken up by a library bank is Xed_vsize * ed_nvoices. X XWhen a voice is edited, the voice data is copied into the parameter Xarray (see below), in p_val. The 'ed_din' function is called to do this. XAfter a voice is edited, 'ed_dout' takes the updated parameter values Xand puts them back into the original data format. Note that this means Xthat the bytes in the 'raw' voice data and the values in the parameter Xarray (ie. the values manipulated by the editor) need not be the same. XThere are utility functions 'getval' and 'setval' which should be used Xfor getting and setting the values in the parameter array. See dx100.c Xfor usage. X XThe ed_sedit, ed_sone, ed_sbulk, and ed_gbulk functions are called to Xsend voices to and get voices from the synthesizer. Only one of ed_sone Xand ed_sbulk need be defined, although ed_sone should be preferred. X(I had trouble getting the DX100 to accept a single permanent voice Xchange, so it always does a bulk voice transfer.) The data passed to Xthese functions is in the library bank format. The ed_gbulk function is Xoptional, so that write-only MIDI devices (like the DEP-5) are allowed. X XThe ed_nof function is called to pull the voice name out of the raw Xvoice data (as stored in the library banks), and it should return a XC string containing the name. The ed_snof function is called to Xstick a voice name into the raw voice data. Note that the 'raw' Xlibrary bank voice data does NOT have to match the data that is Xreally sent to the synthesizer (by the ed_sedit and ed_sone functions). XFor example, the DEP-5 does not have names as part of the voice data, Xbut that does not prevent glib from maintaining and storing (in the files) Xvoice names. This holds for the DW-8000 as well. X XThe ed_numof function is called to convert the voice number to the Xtext that is displayed on the librarian screen. This can handle Xthe odd numbering convention of the DW-8000. If ed_numof==NULL, the Xnumber is used as-is. Otherwise, ed_numof is called with the voice Xnumber MINUS 1 (i.e. 0-based); ed_numof should return a string Xcontaining the desired display. Likewise, the ed_cvtnum function is Xused to convert user input from an odd numbering system to the standard Xsequential internal representation (0 to whatever). X XThe editor screen is controlled by two arrays, ed_labels and ed_params. Xed_labels contains arbitrary screen labels, in the following structure: X Xstruct labelinfo { X int l_row; /* 0-based */ X int l_col; /* 0-based */ X char *l_text; X}; X XThe ed_params array is used to specify the parameters that the user can peruse Xand change in the edit screen, and looks like this (one for each parameter): X Xstruct paraminfo { X char *p_name; /* the parameter name */ X char *p_label; /* on-screen label (possibly NULL) */ X int p_lrow; /* position for printing label */ X int p_lcol; X int p_vrow; /* position for printing value */ X int p_vcol; X char *((*p_tovis)()); /* function converts value to on-screen text*/ X int p_min; /* minimum parameter value */ X int p_max; /* maximum parameter value */ X int p_val; /* parameter value */ X int p_flags; /* flag to enable/disable parameter */ X}; X XThe editor calls p_tovis with a parameter value, and expects that function Xto pass back a string which contains what should be displayed on the Xscreen for that value. Often, this is just an 'sprintf' of the value, Xor perhaps the value offset by something. Or, it could be some text Xthat represents the value (e.g. "on" for 1 and "off" for 0). Or, it could Xbe something more interesting, e.g. a picture of the voice algorithm. XThe parameter value strings can make use of cursor motion, by including the Xsequences ~d,~u,~l,~r to go down,up,left,right. The dx100 and dep5 editors Xuse this to handle the display of the algorithm drawings. X XA parameter can be 'disabled' by setting p_flags to non-zero. The p_tovis Xfunction can set the external variable 'Redraw' to 1 if it wants to force Xthe entire editor screen to be redrawn (e.g. after a parameter has been Xdisabled). X XSupport for a mouse has been added, although it is currently disabled Xfor the Atari, since I was having various hassles getting it under control. XIt did work, but had various quirks. X XMouse support for the Amiga was added, and appears to work after fixing Xa few problems in glib.c, so it may be possible to enable the Atari mouse Xsupport now. X X ...Tim Thompson...twitch!glimmer!tjt... X X[notes from Ed Wilts, ewilts%Janus.MtRoyal.AB.CA@Ucnet.UCalgary.CA, X on the Amiga version for the D-10] X X... The problem I had in getting it Xgoing was more in the execution than the compilation. Without a sufficiently Xlarge stack, you will get highly intermittent results, and depending on the Xstate of the moon and the time of day, gurus. I was getting frequent timeouts Xreading from the D-10 and sometimes the data would be all read but not in the Xproper order. I was getting quite frustrated for a while... X XMy stack was originally 4000 - the default. I boosted it to 8192 with no Xgreater results, and finally went to 32768 and now it seems to work. At least XI can read from the D-10 consistently. ... END_OF_FILE if test 12157 -ne `wc -c <'PORTING'`; then echo shar: \"'PORTING'\" unpacked with wrong size! fi # end of 'PORTING' fi if test -f 'k1multi.mnu' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'k1multi.mnu'\" else echo shar: Extracting \"'k1multi.mnu'\" \(10993 characters\) sed "s/^X//" >'k1multi.mnu' <<'END_OF_FILE' X/* $Id: k1multi.mnu,v 1.6 89/05/06 17:13:27 lee Exp $ X * GLIB - a Generic LIBrarian and editor for synths X * X * K1 Patch Librarian X * X * Adapted for K1 from Kesti's D10 version by Greg Lee X * $Log: k1multi.mnu,v $ X * Revision 1.6 89/05/06 17:13:27 lee X * rel. to comp.sources.misc X * X */ X X#include "glib.h" X#include "k1vis.h" X X#define K1MULTISIZE 75 X#define K1SINGLESIZE 87 X#define RESERVESIZE 0 X Xextern char sngnames[64][11]; X X/* This array contains arbitrary screen labels */ Xstruct labelinfo Lk1m[] = { X X#MENU for multi X volume % X X X X X A......... B................ C............. D..................... X single zn lo zn hi vel sw poly mode rcvch trnsps tune level output X |-------------|-----|-----|------|----|----|-----|------|----|-----|------| X X1 % % % % % % % % % % % X2 % % % % % % % % % % % X3 % % % % % % % % % % % X4 % % % % % % % % % % % X5 % % % % % % % % % % % X6 % % % % % % % % % % % X7 % % % % % % % % % % % X8 % % % % % % % % % % % X X X X X X Press SPACE BAR to sound note % at volume % for duration % on channel % . X#END X X-1,-1,NULL X}; X Xchar *vismltnum(); X Xstruct paraminfo Pk1m[] = { X X/*NAME TYPE POS MAX OFFSET MASK SHIFT ADHOC*/ X X#O volume pnum %% 99 10 X X#O single1 mltnum %% 63 11 X#O zonelo1 cpitch %% 127 19 X#O zonehi1 cpitch %% 127 27 X#O velosw1 velosw %% 2 43 0x30 4 X#O poly1 poly %% 9 35 0x0F X#O modem1 mode %% 2 35 0x40 6 *1 X/* 2nd bit below goes above */ X#O moden1 num -- 1 43 0x40 6 *2 X#O rcvch1 pnum %% 15 43 0x0F X#O trnsps1 keyshift %% 48 51 X#O tune1 finetune %% 100 59 X#O level1 num %% 100 67 X#O output1 pan %% 2 35 0x30 4 X X#O single2 mltnum %% 63 12 X#O zonelo2 cpitch %% 127 20 X#O zonehi2 cpitch %% 127 28 X#O velosw2 velosw %% 2 44 0x30 4 X#O poly2 poly %% 9 36 0x0F X#O modem2 mode %% 2 36 0x40 6 *1 X#O moden2 num -- 1 44 0x40 6 *2 X#O rcvch2 pnum %% 15 44 0x0F X#O trnsps2 keyshift %% 48 52 X#O tune2 finetune %% 100 60 X#O level2 num %% 100 68 X#O output2 pan %% 2 36 0x30 4 X X#O single3 mltnum %% 63 13 X#O zonelo3 cpitch %% 127 21 X#O zonehi3 cpitch %% 127 29 X#O velosw3 velosw %% 2 45 0x30 4 X#O poly3 poly %% 9 37 0x0F X#O modem3 mode %% 2 37 0x40 6 *1 X#O moden3 num -- 1 45 0x40 6 *2 X#O rcvch3 pnum %% 15 45 0x0F X#O trnsps3 keyshift %% 48 53 X#O tune3 finetune %% 100 61 X#O level3 num %% 100 69 X#O output3 pan %% 2 37 0x30 4 X X#O single4 mltnum %% 63 14 X#O zonelo4 cpitch %% 127 22 X#O zonehi4 cpitch %% 127 30 X#O velosw4 velosw %% 2 46 0x30 4 X#O poly4 poly %% 9 38 0x0F X#O modem4 mode %% 2 38 0x40 6 *1 X#O moden4 num -- 1 46 0x40 6 *2 X#O rcvch4 pnum %% 15 46 0x0F X#O trnsps4 keyshift %% 48 54 X#O tune4 finetune %% 100 62 X#O level4 num %% 100 70 X#O output4 pan %% 2 38 0x30 4 X X#O single5 mltnum %% 63 15 X#O zonelo5 cpitch %% 127 23 X#O zonehi5 cpitch %% 127 31 X#O velosw5 velosw %% 2 47 0x30 4 X#O poly5 poly %% 9 39 0x0F X#O modem5 mode %% 2 39 0x40 6 *1 X#O moden5 num -- 1 47 0x40 6 *2 X#O rcvch5 pnum %% 15 47 0x0F X#O trnsps5 keyshift %% 48 55 X#O tune5 finetune %% 100 63 X#O level5 num %% 100 71 X#O output5 pan %% 2 39 0x30 4 X X#O single6 mltnum %% 63 16 X#O zonelo6 cpitch %% 127 24 X#O zonehi6 cpitch %% 127 32 X#O velosw6 velosw %% 2 48 0x30 4 X#O poly6 poly %% 9 40 0x0F X#O modem6 mode %% 2 40 0x40 6 *1 X#O moden6 num -- 1 48 0x40 6 *2 X#O rcvch6 pnum %% 15 48 0x0F X#O trnsps6 keyshift %% 48 56 X#O tune6 finetune %% 100 64 X#O level6 num %% 100 72 X#O output6 pan %% 2 40 0x30 4 X X#O single7 mltnum %% 63 17 X#O zonelo7 cpitch %% 127 25 X#O zonehi7 cpitch %% 127 33 X#O velosw7 velosw %% 2 49 0x30 4 X#O poly7 poly %% 9 41 0x0F X#O modem7 mode %% 2 41 0x40 6 *1 X#O moden7 num -- 1 49 0x40 6 *2 X#O rcvch7 pnum %% 15 49 0x0F X#O trnsps7 keyshift %% 48 57 X#O tune7 finetune %% 100 65 X#O level7 num %% 100 73 X#O output7 pan %% 2 41 0x30 4 X X#O single8 mltnum %% 63 18 X#O zonelo8 cpitch %% 127 26 X#O zonehi8 cpitch %% 127 34 X#O velosw8 velosw %% 2 50 0x30 4 X#O poly8 poly %% 9 42 0x0F X#O modem8 mode %% 2 42 0x40 6 *1 X#O moden8 num -- 1 50 0x40 6 *2 X#O rcvch8 pnum %% 15 50 0x0F X#O trnsps8 keyshift %% 48 58 X#O tune8 finetune %% 100 66 X#O level8 num %% 100 74 X#O output8 pan %% 2 42 0x30 4 X X"autopitch", NULL, -1,-1, %%, visnum, 0, 127, 60, 0, X"autovol", NULL, -1,-1, %%, visnum, 0, 127, 63, 0, X"autodur", NULL, -1,-1, %%, visnum, 1, 20, 5, 0, X"autochan", NULL, -1,-1, %%, visnum, 1, 16, 1, 0, X XNULL, NULL, -1,-1, -1, -1, visnum, 0, 0, 0, 0 X}; X X/* X * k1mnum X * X * Convert a voice number (0 to 127) to the string displayed in the X * librarian (ie. A1 to D8 for multi, to d8 for singles). X */ X Xchar * Xk1mnum(n) X{ X static char v[4]; X X if ( n < 0 || n > 63 ) X return("???"); X X v[0] = 'A' + (n >> 3); X if (v[0] > 'D') v[0] += ' ' - 4; X X (void)sprintf(v+1, "%d", (n % 8) + 1); X X return(v); X} X Xchar * Xvismltnum(n) X{ static char numnam[15]; X X strcpy(numnam, k1mnum(n)); X if (sngnames[n][0] > ' ') { X strcat(numnam, " "); X strcat(numnam, sngnames[n]); X } X return(numnam); X} X X/* X * k1nummlt X * X * Convert a display-style voice number (A1 to d8) to internal X * format (0 to 127). X */ X Xk1nummlt(s) Xchar *s; X{ X X int ld, rd; X X rd = s[0] - 'A'; X if (rd > 3) rd -= ' ' - 4; X if (rd < 0 || rd > 7) return(-1); X X (void)sscanf(s+1, "%d", &ld); X if (ld < 1 || ld > 8) return(-1); X X return((rd << 3) + ld - 1); X X} X X/* X * k1mdin X * X * Take library bank 'data' and stuff values in the P array, by using X * the setval function. X */ X Xk1mdin(data) Xchar *data; X{ X /* The first RESERVESIZE bytes are reserved (arbitrarily) for the voice name */ X#SETVAL X} X X/* X * k1mdout X * X * Take (possibly changed) parameters values out of the P array and X * put them back into the library bank 'data'. X */ X Xk1mdout(data) Xchar *data; X{ X#GETVAL X} X Xk1send1(function, voice) X{ X if (Nvoices == 32) voice += 64; X X sendmidi(0xf0); X sendmidi(0x40); /* Kawai id */ X sendmidi(Channel - 1); /* channel = 1 to 16 */ X sendmidi(function); /* function */ X sendmidi(0x00); /* group */ X sendmidi(0x03); /* machine id number of K1 */ X sendmidi(0x00); /* subcommand 1 = internal */ X sendmidi(voice); /* subcommand 2 = voice 1 */ X} X X/* X * k1msedit X * X * Send a single voice to the edit buffer of the K1. This will be whatever X * voice is currently selected. X * (So far as I know, one can't do this; this is here pro forma. -- gl) X */ X Xk1msedit(data) Xchar *data; X{ X/* X int cksum; X int n, dumpsize; X X k1send1(0x20, 0); X cksum = 0xa5; X X if (Nvoices == 32) dumpsize = K1MULTISIZE; X else dumpsize = K1SINGLESIZE; X X for(n = 0; n < dumpsize; n++) { X sendmidi(data[n] & 0x7f); X cksum += data[n] & 0x7f; X } X sendmidi(cksum & 0x7f); X sendmidi(EOX); X*/ X} X X/* X * k1mnof X * X * Return a pointer to the voice name buried in library bank data. X */ Xchar * Xk1mnof(data) Xchar *data; X{ X static char currbuff[11]; X char *p; X int m; X X p = currbuff; X for ( m = 0 ; m < 10 ; m++ ) X *p++ = data[m]; X *p = '\0'; X return(currbuff); X} X X/* X * k1msnof X * X * Set the voice name buried in data to name. X */ Xk1msnof(data,name) Xchar *data; Xchar *name; X{ X char *p; X int m; X X for ( p = name, m = 0 ; *p != '\0' && m < 10 ; p++, m++ ) X data[m] = *p; X for ( ; m < 10 ; m++ ) X data[m] = ' '; X} X X/* k1msone - send a single voice to the K1 */ Xk1msone(iv, data) Xint iv; Xchar *data; X{ X int cksum; X int n, dumpsize; X X k1send1(0x20, iv); X cksum = 0xa5; X X if (Nvoices == 32) dumpsize = K1MULTISIZE; X else dumpsize = K1SINGLESIZE; X X for(n = 0; n < dumpsize; n++) { X sendmidi(data[n] & 0x7f); X cksum += data[n] & 0x7f; X } X sendmidi(cksum & 0x7f); /* checksum */ X sendmidi(EOX); X X return(0); X} X X/* k1mgbulk - Request and read a bulk dump from the K1 */ Xk1mgbulk(data) Xchar *data; X{ X static char Buff[BUFSIZ]; X int n, v, b2, ret = 1; X long begin, toolong; X int dumpsize; X X (void)sprintf(Buff,"\nA: "); X windstr(Buff); X X if (Nvoices == 32) dumpsize = K1MULTISIZE; X else dumpsize = K1SINGLESIZE; X X for(v = 0; v < Nvoices; v++) { X X flushmidi(); X X if(v == 64) { X (void)sprintf(Buff,"\nB: "); X windstr(Buff); X } X if((((v > 63) ? (v - 64) : v) % 10) != 0) { X (void)sprintf(Buff, "."); X } else { X (void)sprintf(Buff,"%d", (((v > 63) ? (v - 64) : v) / 10)); X } X windstr(Buff); X X /* request the dump */ X if (!synthinfileflag) { X k1send1(0, v); X sendmidi(EOX); X } X X /* set up timeout */ X begin = milliclock(); X toolong = begin + (1000 * TIMEOUT); X X /* read header */ X for(n = 0; n < 8; ) { X if ( STATMIDI ) { X b2 = (getmidi() & 0xff); X /* burn active sensing and timing clock */ X if((b2 != 0xfe) && (b2 != 0xf8)) X n++; X } else { X if ( milliclock() > toolong ) { X Reason = "Timeout waiting for header"; X goto getout; X } X } X } X X /* read data */ X for(n = 0; n < dumpsize; ) { X if ( STATMIDI ) { X b2 = (getmidi() & 0xff); X /* burn active sensing and timing clock */ X if((b2 != 0xfe) && (b2 != 0xf8)) { X VOICEBYTE(data,v,n) = b2; X n++; X } X } else { X if ( milliclock() > toolong ) { X Reason = "Timeout reading data"; X goto timeout; X } X } X } X X timeout: X if ( n != dumpsize ) { X Reason = "Timeout reading data!"; X goto getout; X } X X /* read checksum */ X for(n = 0; n < 1; ) { X if ( STATMIDI ) { X b2 = (getmidi() & 0xff); X /* burn active sensing and timing clock */ X if((b2 != 0xfe) && (b2 != 0xf8)) X n++; X } else { X if ( milliclock() > toolong ) { X Reason = "Timeout reading checksum"; X goto getout; X } X } X } X X /* read EOX */ X for(n = 0; n < 1; ) { X if ( STATMIDI ) { X b2 = (getmidi() & 0xff); X /* burn active sensing and timing clock */ X if((b2 != 0xfe) && (b2 != 0xf8)) X if ( b2 != EOX ) { X (void)sprintf(Buff,"EOX not received (%X)\n", b2); X Reason = Buff; X goto getout; X } X n++; X } else { X if ( milliclock() > toolong ) { X Reason = "Timeout reading EOX"; X goto getout; X } X } X } X X } /* go back for another voice */ X X Reason = ""; X ret = 0; /* all's well */ X Xgetout: X return(ret); X} X X/* k1msbulk - send a bulk dump to the K1 */ Xk1msbulk(data) Xchar *data; X{ X static char Buff[BUFSIZ]; X int v, n, databyte, curoff, dumpsize; X int cksum; X X (void)sprintf(Buff,"\nA: "); X windstr(Buff); X X if (Nvoices == 32) dumpsize = K1MULTISIZE; X else dumpsize = K1SINGLESIZE; X X curoff = 0; X for(v = 0; v < Nvoices ; v++) { X if(v == 64) { X (void)sprintf(Buff,"\nB: "); X windstr(Buff); X } X if((((v > 63) ? (v - 64) : v) % 10) != 0) { X (void)sprintf(Buff, "."); X } else { X (void)sprintf(Buff,"%d", (((v > 63) ? (v - 64) : v) / 10)); X } X X windstr(Buff); X k1send1(0x20, v); X cksum = 0xa5; X X for(n = 0; n < dumpsize; n++) { X databyte = data[n + curoff] & 0x7f; X sendmidi(databyte); X cksum += databyte; X } X sendmidi(cksum & 0x7f); /* checksum */ X sendmidi(EOX); X curoff += Voicesize; X } X return(0); X} X X/* end */ END_OF_FILE if test 10993 -ne `wc -c <'k1multi.mnu'`; then echo shar: \"'k1multi.mnu'\" unpacked with wrong size! fi # end of 'k1multi.mnu' fi if test -f 'pc-ints.asm' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'pc-ints.asm'\" else echo shar: Extracting \"'pc-ints.asm'\" \(12452 characters\) sed "s/^X//" >'pc-ints.asm' <<'END_OF_FILE' X@ab equ 6 ;use big model X; $Id: pc-ints.asm,v 1.6 89/05/06 17:13:38 lee Exp $ X; X; the following constants are hardware specific to the MPU401 & OP4000 X; MIDI interface controllers X; $Log: pc-ints.asm,v $ X; Revision 1.6 89/05/06 17:13:38 lee X; rel. to comp.sources.misc X; X; X; XBASE_ADDRESS_MPU equ 330h XSTATUS_PORT_MPU equ BASE_ADDRESS_MPU + 1 XCOMMAND_PORT_MPU equ BASE_ADDRESS_MPU + 1 XDATA_PORT_MPU equ BASE_ADDRESS_MPU + 0 XTx_EMT equ 40h ;midi transmitter ready for more data XRx_NEMT equ 80h ;midi receiver has data ready XMPU_INT equ 2 XMPU_INT_MASK equ 4 X; X; the remaining constants are for the AT&T PC6300 and compatible PC's X; XTIMER_INT equ 0 XTIMER_INT_MASK equ 1 XHW_INT_MASK equ MPU_INT_MASK OR TIMER_INT_MASK XINT_CTLR_PORT equ 20h ;port to send EOI command to XINT_CTLR_IMR equ 21h ;port to mask interrupts XEOI_CODE equ 20h ;EOI command XT_55MS equ 0000h ; 8253 value for 55 ms XT_5MS equ 174dh ; 8253 value for 5 ms XTIC_55MS equ 11 ; Number of timer tics to equal 55 ms XPIT_MODE equ 36h ; 8253 mode: 00 11 011 0 -> cntr0,LSB/MSB,mode 3,binary XPIT_CNT0 equ 40h ; Counter 0 port for 8253 PIT XPIT_CTRL equ 43h ; Control port for 8253 PIT XUSER_TMR equ 1ch ; User Timer (55 ms) Int. Vector X; X X;******************** X;** macros ** X;******************** X; Xc_in macro ;this macro sets up a stack frame X push bp ;must save bp reg for 'c' progs X mov bp, sp ;set up frame pointer X push di X push si ;save register vars X endm X; Xc_out macro ;This macro cleans up for return to 'C' X pop si X pop di X mov sp, bp X pop bp ;restore caller's frame pointer X cld ;clear direction flag X ret ;and return X endm X; Xpush_all_regs macro X push es X push ds X push dx X push cx X push bx X push si X push di X push ax X push bp X endm X; Xpop_all_regs macro X pop bp X pop ax X pop di X pop si X pop bx X pop cx X pop dx X pop ds X pop es X endm X; Xenable_IMR macro num ;this macro clears (enables) X ;interrupts in the interrupt mask reg X in al, INT_CTLR_IMR ;read in current int mask X and al, 0ffh - num ;clear the requested IMR bit X out INT_CTLR_IMR, al ;and write it back out X endm X; Xdisable_IMR macro num ;disable interrupts in the IMR X in al, INT_CTLR_IMR ;read in current int mask X or al, num ;set the requested IMR bit X out INT_CTLR_IMR, al ;and write it out X endm X; Xack_int macro ;this macro sends non-specific EOI X ;to the int controller chip in the PC X mov al, EOI_CODE X out INT_CTLR_PORT, al X sti X endm X; X X;************************************************************ X;** ** X;** DATA GROUP DECLARATION ** X;** ** X;************************************************************ X; X Xdgroup group data Xdata segment word public 'data' X assume ds:dgroup X; X; --- The following vars are used to manage a very small stack X; that is used for interrupt enable/disable stacking X; XINT_STACK_SIZE equ 8 * 1 Xint_stack db (INT_STACK_SIZE/8) dup ('intstack') Xint_stack_pointer dw 0 X; X; --- The following provide a circular character buffer used to X; store data received from the MIDI interface X; XBUFFER_SIZE equ 512 X_wrt_index dw 0 X_rd_index dw 0 X_midi_buffer db BUFFER_SIZE dup (0) Xpublic _wrt_index Xpublic _rd_index Xpublic _midi_buffer X; X; --- The following vars are used to keep a running tally of the X; programmable timer ticks. X; X_hzcount dd 0 Xint_cnt dw 0 Xpublic _hzcount X; Xdata ends X; X X;************************************************************ X;** ** X;** CODE SEGMENT ** X;** ** X;** ** X;************************************************************ X; X; X extrn _fatal_dos_handler:far ;'C' routine to handle DOS errors X extrn _bye:far ; exit routine for Ctl-brk X X_code segment byte public 'code' X assume cs:_code X public _ctl_brk X public _asm_fatal_dos_handler X public _disable_ints X public _enable_ints X public _init_enable_MPU X public _init_enable_TIMER X public _reset_TIMER X public _write_data_MPU X public _read_MPU X public _midi_isr X public _tick_isr X X; X;************************************************************ X;** ** X;** INTERRUPT HANDLERS ** X;** ** X;** ** X;************************************************************ X_ctl_brk proc far X; X; Control-Break Interrupt Service Routine X; Xctl_st: cli ; make sure no interrupts X mov ax,ds X mov ss,ax ; ss = ds :: so chkstk() doesn't fail in quit() X mov sp,0fffeh ; and sp = hi mem X mov ax,1 ; exit code X sti ; turn interrupts back on X push ax X call _bye X pop bp ; not needed, never returns here X iret ; or here X_ctl_brk endp X; X; Fatal Dos Error Interrupt Service Routine X; X_asm_fatal_dos_handler proc far X push_all_regs ;save machine state X push di X push ax ;push args for function X mov ax, dgroup X mov ds, ax ;address data segment X mov es, ax ;and extra segmant X call _fatal_dos_handler ;handler(ax, di) X pop ax X pop ax X pop_all_regs X mov al,0 ;tell DOS to ignore error X iret X_asm_fatal_dos_handler endp X; X; X;************************************************************ X;** MIDI_ISR ** X;** This is the MPU int service routine ** X;** It reads data from MPU data port until there is no more** X;** and stores in a circular buffer ** X;************************************************************ X; X_midi_isr proc far X push_all_regs ;save machine state X mov ax, dgroup X mov ds, ax X disable_IMR MPU_INT_MASK X sti Xdo_another: X mov dx, DATA_PORT_MPU X in al, dx ;read in the interrupt data from MPU X X inc _wrt_index ;bump up write pointer X cmp _wrt_index, 01ffh ;is index at top of buff? X jle wrt_index_ok X mov _wrt_index, 0 ;if yes, wraparound to bottom Xwrt_index_ok: ;of buffer X mov bx, _wrt_index X mov _midi_buffer[bx], al ;move data into buffer X X mov dx, STATUS_PORT_MPU ;DX = &status port X in al, dx ;read status port X and al, Rx_NEMT ;is there data to read? X jz do_another ;go back if so X;isr return X cli ;turn off system ints X enable_IMR MPU_INT_MASK X ack_int ;and acknowlege interrupt X pop_all_regs ;restore machine state X iret ;and leave X_midi_isr endp X; X;******************************************************************** X;* TICK_ISR X;* The interrupt service routine for the programmable timer. X;* Timer is currently set at 5 ms. intervals. X;******************************************************************** X; X_tick_isr proc far X; Xtmr_st: push ds X push ax X mov ax, dgroup X mov ds, ax ;must have our data segment X disable_IMR TIMER_INT_MASK X sti X add word ptr _hzcount, 1 X adc word ptr _hzcount + 2, 0 X inc int_cnt X cmp int_cnt,TIC_55MS X jge tm1 X cli X enable_IMR TIMER_INT_MASK X ack_int X pop ax X pop ds X iret X Xtm1: mov int_cnt,0 X int USER_TMR X cli X enable_IMR TIMER_INT_MASK X ack_int X pop ax X pop ds X iret X_tick_isr endp X X X; X;************************************************************ X;** DISABLE_INTS() ** X;** Called to disable interrupts. stacks old int ** X;** status before disabling, so that nesting is ** X;** preserved. ** X;************************************************************ X; X_disable_ints proc far X cli X in al, INT_CTLR_IMR ;read in current int mask X mov dl, al ;move it to dl X and dl, HW_INT_MASK ;extract the bit for MPU ints X mov bx, int_stack_pointer ;get current stack pointer X mov int_stack[bx], dl ;store out int status there X inc bx X mov int_stack_pointer, bx ;write back new stack pointer value X or al, HW_INT_MASK ;mask off int X out INT_CTLR_IMR, al ;and write it out X sti X ret X_disable_ints endp X; X;************************************************************ X;** ENABLE_INTS() ** X;** Restores whatever the int status was before ** X;** DISABLE_INTS() was called. ** X;** Note that calls to enable and disable must be matched ** X;** or chaos will occur ** X;************************************************************ X; X_enable_ints proc far X cli X in al, INT_CTLR_IMR ;read in current int mask X and al, 0ffh - HW_INT_MASK ; get all the bits except the ones X ; for out ints X mov bx, int_stack_pointer ;get int stack pointer X dec bx ;move it down X mov int_stack_pointer, bx ;store it X or al, int_stack[bx] ;or in int status with old one X out INT_CTLR_IMR, al ;and write it out X sti ;turn ints on now X ret X_enable_ints endp X; X;************************************************************ X;** INIT_ENABLE_MPU() ** X;** Starts up the MPU ints. ** X;** ** X;************************************************************ X; X_init_enable_MPU proc far X cli X enable_IMR MPU_INT_MASK X sti X ret X_init_enable_MPU endp X;; X;************************************************************ X;** INIT_ENABLE_TIMER() ** X;** Starts up the TIMER ints. ** X;** ** X;************************************************************ X; X_init_enable_TIMER proc far X cli X; Set 8253 PIT for different timing X; X mov al,PIT_MODE X out PIT_CTRL,al ; Set 8253 mode X mov ax,T_5MS X out PIT_CNT0,al X mov al,ah X out PIT_CNT0,al ; Set new timing X enable_IMR TIMER_INT_MASK X sti X ret X_init_enable_TIMER endp X; X; X;************************************************************ X;** RESET_TIMER() ** X;** Sets timer values back to what they were ** X;** ** X;************************************************************ X_reset_TIMER proc far X X disable_IMR TIMER_INT_MASK X mov al,PIT_MODE X out PIT_CTRL,al ; Set 8253 mode X mov ax,T_55MS X out PIT_CNT0,al X mov al,ah X out PIT_CNT0,al ; Reset timing X enable_IMR TIMER_INT_MASK X ret X_reset_TIMER endp X; X X;************************************************************ X;** WRITE_DATA_MPU(DATA) ** X;** sends a byte to the MPU data port ** X;** waits for handshake ** X;** ** X;************************************************************ X; X; X_write_data_MPU proc far X c_in X mov bx, @ab[bp] ;get data byte in bl reg X call write_sub ;and call fast sub X c_out ;leave X_write_data_MPU endp X; X;************************************************************ X;** ** X;** write_sub ** X;** Writes data to MPU. on entry, byte in bl ** X;** ax, cx, cx destroyed ** X;************************************************************ X; Xwrite_sub proc near X mov dx, STATUS_PORT_MPU ;set up pointer to MPU port Xwrite_clear_loop: X in al, dx X and al, Tx_EMT X jnz write_clear_loop X dec dx ;point to data reg X mov al, bl X out dx, al ;send out the data X ret Xwrite_sub endp X; X;************************************************************ X;** read_MPU() ** X;** reads a byte from the MPU eata port ** X;** waits for handshake ** X;** ** X;************************************************************ X; X_read_MPU proc far X c_in Xread_clear_loop: X mov dx, STATUS_PORT_MPU ;DX = &status port X in al, dx X and al, Rx_NEMT X jnz read_clear_loop X dec dx ;point to data reg X in al, dx X xor ah, ah X c_out X_read_MPU endp X X; X X_code ends X end X END_OF_FILE if test 12452 -ne `wc -c <'pc-ints.asm'`; then echo shar: \"'pc-ints.asm'\" unpacked with wrong size! fi # end of 'pc-ints.asm' fi if test -f 'pc-mach.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'pc-mach.c'\" else echo shar: Extracting \"'pc-mach.c'\" \(11518 characters\) sed "s/^X//" >'pc-mach.c' <<'END_OF_FILE' X/* $Id: pc-mach.c,v 1.6 89/05/06 17:13:39 lee Exp $ X * X * Glib - Generic LIBrarian and editor X * X * Machine dependent stuff for MIDI programs. X * Time Thompson X * X * This is for MS-DOS machines. The screen operations should X * work okay, but the MIDI I/O needs to be worked on. It may X * or may not be fast enough on some machines. X * $Log: pc-mach.c,v $ X * Revision 1.6 89/05/06 17:13:39 lee X * rel. to comp.sources.misc X * X */ X X#include "glib.h" X Xint Rows = 24; Xint Cols = 80; X Xchar * Xalloc(n) X{ X char *p; X X if ( (p=malloc((unsigned)n)) == (char *)NULL ) { X printf("*** Whoops *** alloc has failed?!? No more memory!\n"); X fflush(stdout); X bye(); X } X return(p); X} X Xflushmidi() X{ X while ( STATMIDI ) X getmidi(); X} X X/* getmouse - get currect row and column of mouse */ Xgetmouse(amr,amc) Xint *amr; Xint *amc; X{ X *amr = -1; X *amc = -1; X} X X/* statmouse - return mouse button state (0=nothing pressed,1=left,2=right) */ Xstatmouse() X{ X return(-1); X} X X/* Return when either a console key or mouse button is pressed. */ Xmouseorkey() X{ X return(getconsole()); X} X X#ifdef C86 Xgetch() X{ X struct regval sreg, rreg; X sreg.ax = 0x0000; X sysint(0x16, &sreg, &rreg); X return(rreg.ax & 0x7f); X} X#endif X Xwindinit() X{ X} X Xwindgoto(r,c) Xint r,c; X{ X#ifdef C86 X struct regval sreg, rreg; X sreg.ax = 0x200; X sreg.bx = 0; X sreg.dx = (r<<8) | c ; X sysint(0x10, &sreg, &rreg); X#endif X#ifdef TURBOC X gotoxy(1+c,1+r); X#endif X} X Xwinderaserow(r) X{ X#ifdef C86 X struct regval sreg, rreg; X sreg.ax = 0x0600; X sreg.bx = 0; X sreg.cx = (r<<8); /* urow, lcol */ X sreg.dx = (r<<8) | 79; X sysint(0x10, &sreg, &rreg); X#endif X#ifdef TURBOC X gotoxy(1,r+1); X clreol(); X#endif X} X Xwindexit() X{ X /* windgoto(23,0); X windrefresh(); X nocbreak(); X nl(); X echo(); X endwin(); */ X} X Xwindclear() X{ X#ifdef C86 X struct regval sreg, rreg; X sreg.ax = 0x0600; X sreg.bx = 0; X sreg.cx = 0; /* urow, lcol */ X sreg.dx = (24<<8) | 79; X sysint(0x10, &sreg, &rreg); X#endif X#ifdef TURBOC X clrscr(); X#endif X} X X/* windgets - get a line of input from the console, handling backspaces */ Xwindgets(s) Xchar *s; X{ X char *origs = s; X int c; X X while ( (c=getconsole()) != '\n' && c!='\r' && c!= EOF ) { X if ( c == '\b' ) { X if ( s > origs ) { X windstr("\b \b"); X s--; X } X } X else { X windputc(c); X *s++ = c; X } X windrefresh(); X } X *s = '\0'; X} X Xwindstr(s) Xchar *s; X{ X int c; X X while ( (c=(*s++)) != '\0' ) X windputc(c); X} X Xwindputc(c) Xint c; X{ X putchar(c); X} X Xwindrefresh() X{ X} X Xbeep() X{ X putchar('\007'); X} X Xwindhigh() X{ X} X Xwindnorm() X{ X} X X/**************** X * openls(), nextls(), and closels() are used to scan the current directory. X ***************/ X Xint first = 1; Xopenls() X{ X first = 1; X} Xchar * Xnextls() X{ X static struct ffblk ffblk; X int n; X X if ( first ) { X n = findfirst("*.*",&ffblk,0); X first = 0; X } X else X n = findnext(&ffblk); X X if ( n == 0 ) X return(ffblk.ff_name); X else X return((char *)NULL); X} Xclosels() X{ X} X X#ifdef OLDSTUFF X/* X * The following MPU code has been provided by Steve Frysinger (moss!spf). X */ X X#define STATUS_PORT 0x0331 X#define COMMAND_PORT 0x0331 X#define DATA_PORT 0x0330 X#define DATA_READY_MASK 0x40 X#define DATA_AVAIL_MASK 0x80 X Xint send_command_4001(val) /* Patterned after Voyetra's reset_4001() */ Xunsigned val; X{ X unsigned x = 0; X int flag; X int ack_count,time_count; X int retval=1; /* Assume success */ X inportb(DATA_PORT); X for (time_count=5000,flag=1;time_count&&flag;time_count--) X { X if (!(inportb(STATUS_PORT)&DATA_READY_MASK)) flag=0; X } X if (flag) X { X fprintf(stderr,"Command timeout waiting for port!\n"); X retval = -1; X } X else X { X outportb(COMMAND_PORT,val); X for (time_count=10000,ack_count=5,flag=0;!flag;) X { X if ((inportb(STATUS_PORT)&DATA_AVAIL_MASK)) X { X time_count--; X if (!time_count) X { X flag++; X fprintf(stderr,"Command timeout waiting for ACK.\n"); X retval = -1; X } X } X else X { X x = (unsigned)inportb(DATA_PORT); X if (x == 0xfe) X { X flag++; X fprintf(stderr,"Got command acknowledgement\n"); X } X else X { X ack_count--; X if (!ack_count) X { X printf("Too many data bytes without ACK\n"); X retval = -1; X } X } X } X } X } X return(retval); X} /* send_command_4001 */ X#endif X X/* X * Acknowledgements to John Helton for additions to support ATT PC6300 w/ X * MPU401 and OP4000 MIDI Interface Controllers. X * PC6300 support uses Borland TurboC 'C' compiler, large model X * X */ X#define QUIT 1 X#define NOQUIT 0 X Xvoid interrupt (*oldint0)(); Xvoid interrupt (*oldint2)(); Xvoid interrupt (*oldint1b)(); Xvoid interrupt (*oldint23)(); Xvoid interrupt (*oldint24)(); Xvoid interrupt ctr_brk_handler(); Xvoid interrupt fatal_err_hndlr(); X Xvoid interrupt far tick_isr(); Xvoid interrupt far midi_isr(); Xextern unsigned long hzcount; Xextern char midi_buffer[]; Xextern int wrt_index, rd_index; X Xextern unsigned _stklen; /* Turbo C specific */ X Xint Nextpcchar = EOF; Xint Fakemidi = 0; Xint (*Intfunc)() = NULL; X Xhello() X{ X _stklen = 50000; X hzcount = 0L; /* init timer & buffer globals */ X wrt_index = rd_index = 0; X if (!setup_MIC()) /* Set up the Midi Interface Ctrl */ X { X if ( fisatty(stdout) ) X printf("Can't initialize midi interface\n"); X Fakemidi = 1; X reset_ints(NOQUIT); /* restore interrupts to a suitable X condition to keep running without X the Midi Interface (for testing) */ X return; X } X send_msg(UART, COMMAND_MSG); /* run the MIC in dumb mode */ X return; X} X Xrtend() X{ X reset_MIC(); X} X Xbye() X{ X system_exit(); X} X Xflushconsole() X{ return; } X Xgetconsole() X{ X int c; X X if ( Nextpcchar != EOF ) { X c = Nextpcchar; X Nextpcchar = EOF; X } X else { X c = getch(); X } X return(c); X} X Xputconsole(c) X{ X putch(c); X} X X/* getmidi reads data out of the circular midi buffer */ Xgetmidi() X{ X static char mbuff[1]; X unsigned char *p; X X while ( wrt_index == rd_index) X ; X rd_index++; X if (rd_index > 511) rd_index = 0; X mbuff[0] = midi_buffer[rd_index]; X return (mbuff[0] & 0xff); X} X Xsendmidi(val) Xint val; X{ X unsigned char p[1]; X p[0] = val; X putnmidi(1,p); X} X Xputnmidi(n,p) Xchar *p; X{ X while ( n-- > 0 ) { X int c = (*p++) & 0xff; X if ( Fakemidi ) X printf("putmidi(d=%d x=%x o=%o)\n",c,c,c); X else X write_data_MPU(c); X } X} X Xresetclock() X{ X hzcount = 0L; X} X Xlong Xmilliclock() X{ X return (hzcount*5L); X} X X/* filetime - Return the modification time of a file in seconds. */ Xlong Xfiletime(fn) Xchar *fn; /* file name */ X{ X struct stat s; X X if ( stat(fn,&s) == -1 ) X return(-1); X return(s.st_mtime); X} X X/* currtime - Return current time in seconds (consistent with filetime()) */ Xlong Xcurrtime() X{ X long time(); X return ( time((long *)0) ); X} X Xfisatty(f) XFILE* f; X{ X return(isatty(fileno(f))); X} X X/* X * send_msg(COM, TYPE, PTR, LENGTH) X * will send command to Midi Interface Controller (MIC) Command port, X * then either return, wait for data or send data X */ X Xsend_msg(com, type, ptr, length) Xint com, type, length; Xchar *ptr; X{ X int acked; X int x; X X while ( NOT_READY_FOR_DATA_MIC()); X disable_ints(); X COMMAND_OUT_MIC((char) com); /* send the command to the MIC */ X for(acked=0; !acked; ) { /* wait until our command is acked */ X x = read_MPU(); /* get a byte back from the MIC */ X if (x == ACK) acked++; /* done if ACK received */ X else write_rcv_buff(x); /* deal with this input stream first */ X } X if (type == WRITE_MSG) /* if write request... */ X for (; length; ptr++, length--) write_data_MPU(*ptr); X /* write all the bytes to the MIC */ X enable_ints(); /* ints restored to where they were X before we shut them off */ X} X X X/* WRITE_RCV_BUFF(INPUT) X * part of the command handshake sequence. Input read from the X * midi data port is saved in wraparound FIFO X*/ X Xwrite_rcv_buff(val) Xint val; X{ X wrt_index++; X if (wrt_index > 511) wrt_index = 0; X midi_buffer[wrt_index] = (char) val; X} X X/* X * SETUP_MIC() X * resets MIC, sets up int vectors and enables int system X * Returns - true if MIC set ok X */ X Xstatic setup_MIC() X{ X int retval; X X set_ints(); /* set the new interrupt vectors */ X init_enable_MPU(); /* turn on interrupt system for first time */ X retval = reset_MIC(); /* try to reset MIC */ X if (!retval) retval = reset_MIC(); /* if no good, try again */ X init_enable_TIMER(); /* turn on timer interrupt if reset ok*/ X return(retval); X} X X/* X * RESET_MIC() X * attempts to do a low level software reset on the MIC X * returns - true if success X */ X Xreset_MIC() X{ X unsigned x = 0; X int flag; X int ack_count, time_count; X int retval=1; /* assume success */ X X disable_ints(); /* disable interrupts */ X READ_DATA_MIC(); /* Clear out any data in receiver */ X /* Here we will loop until ready for data, or we give up */ X for (time_count=5000, flag=1; time_count && flag; time_count--) { X /* if MIC ready for data, we can quit loop */ X if (!(NOT_READY_FOR_DATA_MIC())) flag=0; X } X /* if timed out before we got ready for data, return flag couldn't reset */ X if (flag){ X retval = 0; X } X else { X COMMAND_OUT_MIC(RESET); /* Send the reset command */ X /* loop here till time out, or ack recvd */ X for (time_count=10000, ack_count=5, flag=0; !flag;) { X if ((NOT_DATA_AVAILABLE_MIC())) { /* if no data from MIC */ X time_count--; /* count one more wait */ X if (!time_count) { XBAD_RESET: X flag++; /* if time out, note it */ X retval=0; /* and note failure */ X } X } X else { /* If there is data coming back form MIC */ X x = (unsigned) READ_DATA_MIC(); /* ...read it */ X if (x == ACK) { /* If data is the ACK message */ X flag++; /* note we are done, and no failure */ X } X else { /* if data back from MIC wasn't ack */ X ack_count--;/* note that we got something that isn't ack */ X if (!ack_count) goto BAD_RESET; X /* If we get too many data bytes back from X MIC with no ack, give up */ X } X } X } X } X enable_ints(); /* turn ints back on */ X return(retval); X} X X/* X * SYSTEM_EXIT() X * called to leave program. resets ints and exits X */ Xsystem_exit() X{ X reset_MIC(); X disable_ints(); X reset_ints(QUIT); /* put all the int vectors back where they were */ X reset_TIMER(); X enable_ints(); X windexit(0); X exit(); X} X X/* X * hi level interrupt routines X */ X Xvoid interrupt Xctr_brk_handler() X{ X if ( Intfunc != NULL ) X (*Intfunc)(); X printf("interrupts reset; BYE!\n"); X system_exit(); X} X Xvoid interrupt Xfatal_err_hndlr() X{ X fatal_dos_handler(); X} X Xfatal_dos_handler() /* called by fatal error handler ISR */ X{ X printf("got fatal error; BYE!\n"); X system_exit(); X} X Xset_ints() X{ X oldint0 = getvect(0x08); /* timer interrupt on irq0 */ X setvect(0x08, tick_isr); X oldint2 = getvect(0x0a); /* midi interrupt on irq2 */ X setvect(0x0a, midi_isr); X oldint1b = getvect(0x1b); /* the rest of these are dos & bios ints */ X setvect(0x1b, ctr_brk_handler); X oldint23 = getvect(0x23); X setvect(0x23, ctr_brk_handler); X oldint24 = getvect(0x24); X setvect(0x24, fatal_err_hndlr); X} X Xreset_ints(reset_type) X{ X if (reset_type == QUIT) { X setvect(0x08, oldint0); X setvect(0x1b, oldint1b); X setvect(0x23, oldint23); X setvect(0x24, oldint24); X } X setvect(0x0a, oldint2); /* only need to reset one hardware interrupt X if we're not going to quit */ X} X Xsignal(type,func) Xint (*func)(); X{ X if ( type == SIGINT ) { X if ( func == SIG_IGN ) X Intfunc = NULL; X else X Intfunc = func; X } X} END_OF_FILE if test 11518 -ne `wc -c <'pc-mach.c'`; then echo shar: \"'pc-mach.c'\" unpacked with wrong size! fi # end of 'pc-mach.c' fi echo shar: End of archive 6 \(of 15\). cp /dev/null ark6isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 15 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0