/* * Glib - Generic LIBrarian and editor * * Machine dependent stuff for MIDI programs. * * This is for MS-DOS machines. The screen operations should * work okay, but the MIDI I/O needs to be worked on. It may * or may not be fast enough on some machines. */ #include "glib.h" int Rows = 24; int Cols = 80; char * alloc(n) { char *p; if ( (p=malloc((unsigned)n)) == (char *)NULL ) { printf("*** Whoops *** alloc has failed?!? No more memory!\n"); fflush(stdout); bye(); } return(p); } flushmidi() { while ( STATMIDI ) getmidi(); } /* getmouse - get currect row and column of mouse */ getmouse(amr,amc) int *amr; int *amc; { *amr = -1; *amc = -1; } /* statmouse - return mouse button state (0=nothing pressed,1=left,2=right) */ statmouse() { return(-1); } /* Return when either a console key or mouse button is pressed. */ mouseorkey() { return(getconsole()); } #ifdef C86 getch() { struct regval sreg, rreg; sreg.ax = 0x0000; sysint(0x16, &sreg, &rreg); return(rreg.ax & 0x7f); } #endif windinit() { } windgoto(r,c) int r,c; { #ifdef C86 struct regval sreg, rreg; sreg.ax = 0x200; sreg.bx = 0; sreg.dx = (r<<8) | c ; sysint(0x10, &sreg, &rreg); #endif #ifdef TURBOC gotoxy(1+c,1+r); #endif } winderaserow(r) { #ifdef C86 struct regval sreg, rreg; sreg.ax = 0x0600; sreg.bx = 0; sreg.cx = (r<<8); /* urow, lcol */ sreg.dx = (r<<8) | 79; sysint(0x10, &sreg, &rreg); #endif #ifdef TURBOC gotoxy(1,r+1); clreol(); #endif } windexit() { /* windgoto(23,0); windrefresh(); nocbreak(); nl(); echo(); endwin(); */ } windclear() { #ifdef C86 struct regval sreg, rreg; sreg.ax = 0x0600; sreg.bx = 0; sreg.cx = 0; /* urow, lcol */ sreg.dx = (24<<8) | 79; sysint(0x10, &sreg, &rreg); #endif #ifdef TURBOC clrscr(); #endif } /* windgets - get a line of input from the console, handling backspaces */ windgets(s) char *s; { char *origs = s; int c; while ( (c=getconsole()) != '\n' && c!='\r' && c!= EOF ) { if ( c == '\b' ) { if ( s > origs ) { windstr("\b \b"); s--; } } else { windputc(c); *s++ = c; } windrefresh(); } *s = '\0'; } windstr(s) char *s; { int c; while ( (c=(*s++)) != '\0' ) windputc(c); } windputc(c) int c; { putchar(c); } windrefresh() { } beep() { putchar('\007'); } windhigh() { } windnorm() { } /**************** * openls(), nextls(), and closels() are used to scan the current directory. ***************/ int first = 1; openls() { first = 1; } char * nextls() { static struct ffblk ffblk; int n; if ( first ) { n = findfirst("*.*",&ffblk,0); first = 0; } else n = findnext(&ffblk); if ( n == 0 ) return(ffblk.ff_name); else return((char *)NULL); } closels() { } #ifdef OLDSTUFF /* * The following MPU code has been provided by Steve Frysinger (moss!spf). */ #define STATUS_PORT 0x0331 #define COMMAND_PORT 0x0331 #define DATA_PORT 0x0330 #define DATA_READY_MASK 0x40 #define DATA_AVAIL_MASK 0x80 int send_command_4001(val) /* Patterned after Voyetra's reset_4001() */ unsigned val; { unsigned x = 0; int flag; int ack_count,time_count; int retval=1; /* Assume success */ inportb(DATA_PORT); for (time_count=5000,flag=1;time_count&&flag;time_count--) { if (!(inportb(STATUS_PORT)&DATA_READY_MASK)) flag=0; } if (flag) { fprintf(stderr,"Command timeout waiting for port!\n"); retval = -1; } else { outportb(COMMAND_PORT,val); for (time_count=10000,ack_count=5,flag=0;!flag;) { if ((inportb(STATUS_PORT)&DATA_AVAIL_MASK)) { time_count--; if (!time_count) { flag++; fprintf(stderr,"Command timeout waiting for ACK.\n"); retval = -1; } } else { x = (unsigned)inportb(DATA_PORT); if (x == 0xfe) { flag++; fprintf(stderr,"Got command acknowledgement\n"); } else { ack_count--; if (!ack_count) { printf("Too many data bytes without ACK\n"); retval = -1; } } } } } return(retval); } /* send_command_4001 */ #endif /* * Acknowledgements to John Helton for additions to support ATT PC6300 w/ * MPU401 and OP4000 MIDI Interface Controllers. * PC6300 support uses Borland TurboC 'C' compiler, large model * */ #define QUIT 1 #define NOQUIT 0 void interrupt (*oldint0)(); void interrupt (*oldint2)(); void interrupt (*oldint1b)(); void interrupt (*oldint23)(); void interrupt (*oldint24)(); void interrupt ctr_brk_handler(); void interrupt fatal_err_hndlr(); void interrupt far tick_isr(); void interrupt far midi_isr(); extern unsigned long hzcount; extern char midi_buffer[]; extern int wrt_index, rd_index; extern unsigned _stklen; /* Turbo C specific */ int Nextpcchar = EOF; int Fakemidi = 0; int (*Intfunc)() = NULL; hello() { _stklen = 50000; hzcount = 0L; /* init timer & buffer globals */ wrt_index = rd_index = 0; if (!setup_MIC()) /* Set up the Midi Interface Ctrl */ { if ( fisatty(stdout) ) printf("Can't initialize midi interface\n"); Fakemidi = 1; reset_ints(NOQUIT); /* restore interrupts to a suitable condition to keep running without the Midi Interface (for testing) */ return; } send_msg(UART, COMMAND_MSG); /* run the MIC in dumb mode */ return; } rtend() { reset_MIC(); } bye() { system_exit(); } flushconsole() { return; } getconsole() { int c; if ( Nextpcchar != EOF ) { c = Nextpcchar; Nextpcchar = EOF; } else { c = getch(); } return(c); } putconsole(c) { putch(c); } /* getmidi reads data out of the circular midi buffer */ getmidi() { static char mbuff[1]; unsigned char *p; while ( wrt_index == rd_index) ; rd_index++; if (rd_index > 511) rd_index = 0; mbuff[0] = midi_buffer[rd_index]; return (mbuff[0] & 0xff); } sendmidi(val) int val; { unsigned char p[1]; p[0] = val; putnmidi(1,p); } putnmidi(n,p) char *p; { while ( n-- > 0 ) { int c = (*p++) & 0xff; if ( Fakemidi ) printf("putmidi(d=%d x=%x o=%o)\n",c,c,c); else write_data_MPU(c); } } resetclock() { hzcount = 0L; } long milliclock() { return (hzcount*5L); } /* filetime - Return the modification time of a file in seconds. */ long filetime(fn) char *fn; /* file name */ { struct stat s; if ( stat(fn,&s) == -1 ) return(-1); return(s.st_mtime); } /* currtime - Return current time in seconds (consistent with filetime()) */ long currtime() { long time(); return ( time((long *)0) ); } fisatty(f) FILE* f; { return(isatty(fileno(f))); } /* * send_msg(COM, TYPE, PTR, LENGTH) * will send command to Midi Interface Controller (MIC) Command port, * then either return, wait for data or send data */ send_msg(com, type, ptr, length) int com, type, length; char *ptr; { int acked; int x; while ( NOT_READY_FOR_DATA_MIC()); disable_ints(); COMMAND_OUT_MIC((char) com); /* send the command to the MIC */ for(acked=0; !acked; ) { /* wait until our command is acked */ x = read_MPU(); /* get a byte back from the MIC */ if (x == ACK) acked++; /* done if ACK received */ else write_rcv_buff(x); /* deal with this input stream first */ } if (type == WRITE_MSG) /* if write request... */ for (; length; ptr++, length--) write_data_MPU(*ptr); /* write all the bytes to the MIC */ enable_ints(); /* ints restored to where they were before we shut them off */ } /* WRITE_RCV_BUFF(INPUT) * part of the command handshake sequence. Input read from the * midi data port is saved in wraparound FIFO */ write_rcv_buff(val) int val; { wrt_index++; if (wrt_index > 511) wrt_index = 0; midi_buffer[wrt_index] = (char) val; } /* * SETUP_MIC() * resets MIC, sets up int vectors and enables int system * Returns - true if MIC set ok */ static setup_MIC() { int retval; set_ints(); /* set the new interrupt vectors */ init_enable_MPU(); /* turn on interrupt system for first time */ retval = reset_MIC(); /* try to reset MIC */ if (!retval) retval = reset_MIC(); /* if no good, try again */ init_enable_TIMER(); /* turn on timer interrupt if reset ok*/ return(retval); } /* * RESET_MIC() * attempts to do a low level software reset on the MIC * returns - true if success */ reset_MIC() { unsigned x = 0; int flag; int ack_count, time_count; int retval=1; /* assume success */ disable_ints(); /* disable interrupts */ READ_DATA_MIC(); /* Clear out any data in receiver */ /* Here we will loop until ready for data, or we give up */ for (time_count=5000, flag=1; time_count && flag; time_count--) { /* if MIC ready for data, we can quit loop */ if (!(NOT_READY_FOR_DATA_MIC())) flag=0; } /* if timed out before we got ready for data, return flag couldn't reset */ if (flag){ retval = 0; } else { COMMAND_OUT_MIC(RESET); /* Send the reset command */ /* loop here till time out, or ack recvd */ for (time_count=10000, ack_count=5, flag=0; !flag;) { if ((NOT_DATA_AVAILABLE_MIC())) { /* if no data from MIC */ time_count--; /* count one more wait */ if (!time_count) { BAD_RESET: flag++; /* if time out, note it */ retval=0; /* and note failure */ } } else { /* If there is data coming back form MIC */ x = (unsigned) READ_DATA_MIC(); /* ...read it */ if (x == ACK) { /* If data is the ACK message */ flag++; /* note we are done, and no failure */ } else { /* if data back from MIC wasn't ack */ ack_count--;/* note that we got something that isn't ack */ if (!ack_count) goto BAD_RESET; /* If we get too many data bytes back from MIC with no ack, give up */ } } } } enable_ints(); /* turn ints back on */ return(retval); } /* * SYSTEM_EXIT() * called to leave program. resets ints and exits */ system_exit() { reset_MIC(); disable_ints(); reset_ints(QUIT); /* put all the int vectors back where they were */ reset_TIMER(); enable_ints(); windexit(0); exit(); } /* * hi level interrupt routines */ void interrupt ctr_brk_handler() { if ( Intfunc != NULL ) (*Intfunc)(); printf("interrupts reset; BYE!\n"); system_exit(); } void interrupt fatal_err_hndlr() { fatal_dos_handler(); } fatal_dos_handler() /* called by fatal error handler ISR */ { printf("got fatal error; BYE!\n"); system_exit(); } set_ints() { oldint0 = getvect(0x08); /* timer interrupt on irq0 */ setvect(0x08, tick_isr); oldint2 = getvect(0x0a); /* midi interrupt on irq2 */ setvect(0x0a, midi_isr); oldint1b = getvect(0x1b); /* the rest of these are dos & bios ints */ setvect(0x1b, ctr_brk_handler); oldint23 = getvect(0x23); setvect(0x23, ctr_brk_handler); oldint24 = getvect(0x24); setvect(0x24, fatal_err_hndlr); } reset_ints(reset_type) { if (reset_type == QUIT) { setvect(0x08, oldint0); setvect(0x1b, oldint1b); setvect(0x23, oldint23); setvect(0x24, oldint24); } setvect(0x0a, oldint2); /* only need to reset one hardware interrupt if we're not going to quit */ } signal(type,func) int (*func)(); { if ( type == SIGINT ) { if ( func == SIG_IGN ) Intfunc = NULL; else Intfunc = func; } }