/**************************************************************************** * midiex.c 2/20/86 Copyright (C) 1986 John Bailin, Cantus Corportion * * Patch exchange software for the IBM-PC using MPU-401 in dumb mode. * * Modified 08/24/86 Jim Bergsten to run under Microsoft "C" * Changes copyright (C) 1986 Jim Bergsten * "creat" call changed to "open" calls. * Symbol "string" defined in routine "edit_space" * Missing open bracket in first "for" stmt. in routine "edit_space" * Some logic changed; some extensions, for example, created files * are now only as long as the system exclusive data received. * Error recovery added so operation can be retried without * restarting the program. * Other minor editorial changes... * * Updated by Michael Geary, 11/14/86 * These changes are not copyrighted! * (How many silly copyrights do you want to see on this thing?) * Fixed bugs: * Files were not closed on error. * You could ^C out and leave the IRQ2 (INT 0Ah) vector hooked - * now forces BREAK OFF and does all console I/O through BIOS. * Interrupt routine in .ASM file failed to chain to previous * interrupt handler when it wasn't ours. * Function templates and type checking added. * Streamlined the user interface * More and more editorial changes... * ***************************************************************************/ /* * The external data and code declarations are all publics in the 8086 * assembler module MIDIINT.ASM. This program was compiled with the Microsoft * C compiler. */ /* Force library argument checking */ #define LINT_ARGS #include #include #include #include #include #include #include /* Don't include stdio.h - so inadvertant printf's will be caught */ int cdecl sprintf( char *, char *, ... ); typedef unsigned char BYTE; typedef unsigned int WORD; typedef unsigned long DWORD; typedef int BOOL; #define TRUE 1 #define FALSE 0 #define BUFMAX 8192 #define CR 13 #define ESC 27 #define LINE 80 /* * MIDI equates */ #define SYSEX 0xF0 #define EOX 0xF7 /* * MPU-401 equates */ #define UART 0x3F #define RESET 0xFF /* * global declarations */ extern int recv_data_count; extern BYTE recv_buf[ ]; extern int recv_buf_ptr; extern BYTE wait_char; BYTE dump_buf[BUFMAX]; BOOL breakstate; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* * Functions in this C file */ void check_keys( void ); BOOL file_exists( char * ); BOOL get_filename( char *, char * ); char *getstring( char * ); void getword( char * *, char * ); BOOL initialize( void ); void instruct( void ); void main( void ); void menu( void ); void print( char * ); void quit( int ); int read_dump( char * ); int receive_dump( void ); BOOL send_dump( int ); BOOL setbreak( BOOL ); BOOL write_dump( char *, int ); /* * Functions in MIDIINT.ASM */ WORD fetch_mpu_data( void ); int get_char( int ); void int10( WORD, WORD, WORD, WORD ); void reset_mpu_vector( void ); BOOL set_mpu_vector( void ); BOOL write_mpu_command( int ); BOOL write_mpu_data( int ); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ void main() { print( "\n\nMIDIEX patch exchange utility.\n" ); print( "Copyright (C) 1986 by Cantus Corportaion.\n" ); print( "Modifications (C) 1986 by Jim Bergsten.\n" ); print( "Version 1.2, updated by Michael Geary.\n" ); if( ! initialize() ) { print( "\nYour MPU isn't responding within MIDIEX's timeout period.\n" ); print( "Try rebooting your system and starting over.\n" ); quit( 1 ); } print( "\nThis program allows you to send and receive MIDI System Exclusive\n" ); print( "data dumps between your PC and a synthesizer or other MIDI device.\n" ); instruct(); while( TRUE ) menu(); quit( 0 ); } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ BOOL file_exists( name ) char *name; { register int f; if( ( f = open( name, (int)(O_RDONLY|O_BINARY) ) ) < 0 ) return FALSE; close( f ); return TRUE; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ BOOL get_filename( prompt, name ) char *prompt, *name; { char response[LINE]; char *resp; if( name[0] ) return TRUE; print( "\nEnter filename to " ); print( prompt ); print( ": " ); resp = getstring( response ); getword( &resp, name ); return name[0] != 0; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ BOOL initialize() { breakstate = setbreak( 0 ); if( ! set_mpu_vector() ) return FALSE; write_mpu_command( RESET ); write_mpu_command( UART ); return TRUE; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ void instruct() { print( "\nCommands are:\n" ); print( " S pathname to Send a data dump to your synthesizer.\n" ); print( " R pathname to Receive a data dump from your synthesizer.\n\n" ); print( "Press the Esc key at any time to exit.\n" ); } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ void menu() { char response[LINE]; char *resp; char name[LINE]; int size; prompt: print( "\nCommand (S, R, Esc): " ); resp = getstring( response ); getword( &resp, name ); switch( name[0] ) { case 'S': getword( &resp, name ); if( ! get_filename( "send", name ) ) break; if( size = read_dump( name ) ) send_dump( size ); print( "\n" ); break; case 'R': getword( &resp, name ); if( ! get_filename( "receive", name ) ) break; if( file_exists( name ) ) { print( "File already exists, OK to overwrite (Y/N)? " ); getstring( response ); if( response[0] != 'Y' ) break; } if( size = receive_dump() ) write_dump( name, size ); print( "\n" ); break; default: instruct(); goto prompt; } } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ void quit( exitvalue ) int exitvalue; { print( "\n\n" ); write_mpu_command( RESET ); reset_mpu_vector(); setbreak( breakstate ); _exit( exitvalue ); } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ int read_dump( name ) char *name; { register int f, size; if( ( f = open( name, (int)(O_RDONLY|O_BINARY) ) ) < 0 ) { print( "\nUnable to open input file " ); print( name ); return FALSE; } if( ( size = read( f, dump_buf, BUFMAX ) ) <= 0 ) { close( f ); print( "\nTrouble reading input file " ); print( name ); return FALSE; } close( f ); return size; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ int receive_dump() { register int i, j, k; char printbuf[40]; /* Set character to wait for */ wait_char = EOX; print( "\nSend the MIDI data now...\n" ); while( wait_char ) check_keys(); /* The following dumps the received data in hexadecimal. remove the comments around it if you want this display. */ /* print( "MIDI data received...\n" ); j = 0; for( i = 0; i < recv_buf_ptr; ++i ) { sprintf( printbuf, " %2.2X", recv_buf[i] ); print( printbuf ); if( j++ == 15 ) { print( "\n" ); j = 0; } } if( j ) print( "\n" ); */ /* search backwards for start of dump */ i = recv_buf_ptr; for( k = 1; k <= BUFMAX; k++ ) { if( --i < 0 ) i = BUFMAX; if ( recv_buf[i] == SYSEX ) break ; } if( k >= BUFMAX ) { print( "Start of MIDI dump not found\n" ); return 0; } sprintf( printbuf, "Size of dump is %d\n", k ); print( printbuf ); for ( j = 0; j < k; j++ ) { if( i == BUFMAX ) i = 0; dump_buf[ j ] = recv_buf[ i++ ]; } return k; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ BOOL send_dump( size ) int size; { register int i; print( "\nStrike any key when ready to send MIDI data...\n" ); get_char( 0 ); print( "\nSending MIDI data...\n" ); for (i = 0; i <= size; i++) { if( ! write_mpu_data( dump_buf[i] ) ) { print( "MIDI interface timed out\n" ); return FALSE; } check_keys(); if( dump_buf[i] == EOX ) break; } print( "\nDone!" ); return TRUE; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ BOOL setbreak( newstate ) BOOL newstate; /* * Sets DOS Ctrl-Break checking to newstate and returns previous state. */ { BOOL oldstate; union REGS regs; regs.x.ax = 0x3300; intdos( ®s, ®s ); oldstate = (BOOL)regs.h.dl; regs.x.ax = 0x3301; regs.h.dl = (unsigned char)newstate; intdos( ®s, ®s ); return oldstate; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ BOOL write_dump( name, size ) register char *name; int size; { register int f; if( ( f = open( name, (int)(O_CREAT|O_TRUNC|O_WRONLY|O_BINARY), S_IWRITE ) ) < 0 ) { print( "\nUnable to open output file " ); print( name ); return FALSE; } if( write( f, dump_buf, size ) != size ) { close( f ); print( "\nTrouble writing to output file " ); print( name ); return FALSE; } close( f ); print( "\nDone!" ); return TRUE; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* * * lower level editing routines * */ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ void check_keys() { register char c; if( get_char( 1 ) == 1 ) { c = (char)( get_char( 0 ) & 0xFF ); if( c == ESC ) quit( 0 ); } } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ char *getstring( string ) char *string; { register int x = 0; register char c; while( TRUE ) { c = (char)( get_char( 0 ) & 0xFF ); if( c == ESC ) quit( 0 ); if( c == CR ) { print( "\n" ); string[x] = '\0'; return string; } if( ( c >= 32 && c < 127 ) || c == CR ) { string[ x++ ] = toupper( c ); int10( 0x0E00 | c, 0, 0, 0 ); } else if( c == 8 && x > 0 ) { int10( 0x0E00 | c, 0, 0, 0 ); int10( 0x0A00 | ' ', 7, 1, 0 ); --x; } } } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ void getword( strpp, word ) char **strpp; char *word; { char *wordp; wordp = word; while( isspace( **strpp ) ) (*strpp)++; while( **strpp && ! isspace( **strpp ) ) *wordp++ = *(*strpp)++; *wordp = 0; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ void print( string ) register char *string; { register char c; while( c = *string++ ) { if( c == '\n' ) int10( 0x0E00 | '\r', 0, 0, 0 ); int10( 0x0E00 | c, 0, 0, 0 ); } } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */