home *** CD-ROM | disk | FTP | other *** search
/ Audio Version 4.94 / audioversion4.94knowledgemediaresourcelibraryoctober1994.iso / msdos / midi / midiex / midiex.c next >
Text File  |  1989-01-10  |  14KB  |  592 lines

  1. /****************************************************************************
  2.  *  midiex.c   2/20/86      Copyright (C) 1986 John Bailin, Cantus Corportion
  3.  *
  4.  *  Patch exchange software for the IBM-PC using MPU-401 in dumb mode.
  5.  *
  6.  *  Modified 08/24/86 Jim Bergsten to run under Microsoft "C"
  7.  *  Changes copyright (C) 1986 Jim Bergsten
  8.  *     "creat" call changed to "open" calls.
  9.  *     Symbol "string" defined in routine "edit_space"
  10.  *     Missing open bracket in first "for" stmt. in routine "edit_space"
  11.  *     Some logic changed; some extensions, for example, created files
  12.  *     are now only as long as the system exclusive data received.
  13.  *     Error recovery added so operation can be retried without
  14.  *     restarting the program.
  15.  *     Other minor editorial changes...
  16.  *
  17.  *  Updated by Michael Geary, 11/14/86
  18.  *  These changes are not copyrighted!
  19.  *  (How many silly copyrights do you want to see on this thing?)
  20.  *    Fixed bugs:
  21.  *        Files were not closed on error.
  22.  *        You could ^C out and leave the IRQ2 (INT 0Ah) vector hooked -
  23.  *           now forces BREAK OFF and does all console I/O through BIOS.
  24.  *        Interrupt routine in .ASM file failed to chain to previous
  25.  *        interrupt handler when it wasn't ours.
  26.  *    Function templates and type checking added.
  27.  *    Streamlined the user interface
  28.  *    More and more editorial changes...
  29.  *
  30.  *  Updated by Dave Hayes, 1/22/88
  31.  *  These changes aren't copyrighted either. I concur with Michael!
  32.  *      Added support for GMR bulk dumps from Yamaha E! modified DX7
  33.  *      so the banks can be FULLY backed up. 
  34.  *
  35.  ***************************************************************************/
  36.  
  37. /*
  38.  *  The external data and code declarations are all publics in the 8086
  39.  *  assembler module MIDIINT.ASM.  This program was compiled with the Microsoft
  40.  *  C compiler.
  41.  */
  42.  
  43. /* Force library argument checking */
  44. #define LINT_ARGS
  45.  
  46. #include <ctype.h>
  47. #include <fcntl.h>
  48. #include <sys\types.h>
  49. #include <sys\stat.h>
  50. #include <io.h>
  51. #include <dos.h>
  52. #include <process.h>
  53.  
  54. /* Don't include stdio.h - so inadvertant printf's will be caught */
  55. int cdecl sprintf( char *, char *, ... );
  56.  
  57. typedef unsigned char    BYTE;
  58. typedef unsigned int    WORD;
  59. typedef unsigned long    DWORD;
  60. typedef int        BOOL;
  61.  
  62. #define TRUE        1
  63. #define FALSE        0
  64.  
  65. /* Changing BUFMAX requires that you change the same value in MIDIINT.ASM! */
  66. #define BUFMAX        16834
  67. #define CR        13
  68. #define ESC        27
  69. #define LINE        80
  70.  
  71. /*
  72.  * MIDI equates
  73.  */
  74.  
  75. #define SYSEX        0xF0
  76. #define EOX        0xF7
  77.  
  78.  
  79. /*
  80.  * MPU-401 equates
  81.  */
  82.  
  83. #define UART        0x3F
  84. #define RESET        0xFF
  85.  
  86. /*
  87.  * global declarations
  88.  */
  89.  
  90. extern int recv_data_count;
  91. extern BYTE recv_buf[ ];
  92. extern int  recv_buf_ptr;
  93.  
  94. extern BYTE wait_char;
  95.  
  96. BYTE dump_buf[BUFMAX];
  97. BOOL breakstate;
  98.  
  99. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  100.  
  101. /*
  102.  * Functions in this C file
  103.  */
  104.  
  105. void check_keys( void );
  106. BOOL file_exists( char * );
  107. BOOL get_filename( char *, char * );
  108. char *getstring( char * );
  109. void getword( char * *, char * );
  110. BOOL initialize( void );
  111. void instruct( void );
  112. void main( void );
  113. void menu( void );
  114. void print( char * );
  115. void quit( int );
  116. int  read_dump( char * );
  117. int  receive_dump( void );
  118. int  gmr_receive_dump( void );
  119. BOOL send_dump( int );
  120. BOOL setbreak( BOOL );
  121. BOOL write_dump( char *, int );
  122. BYTE get_a_digit( void );
  123.  
  124. /*
  125.  * Functions in MIDIINT.ASM
  126.  */
  127.  
  128. WORD fetch_mpu_data( void );
  129. int  get_char( int );
  130. void int10( WORD, WORD, WORD, WORD );
  131. void reset_mpu_vector( void );
  132. BOOL set_mpu_vector( void );
  133. BOOL write_mpu_command( int );
  134. BOOL write_mpu_data( int );
  135.  
  136. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  137.  
  138. void main()
  139. {
  140.     print( "\n\nMIDIEX patch exchange utility.\n" );
  141.     print( "Copyright (C) 1986 by Cantus Corportaion.\n" );
  142.     print( "Modifications (C) 1986 by Jim Bergsten.\n" );
  143.     print( "Version 1.2, updated by Michael Geary.\n" );
  144.     print( "Version 1.3, updated by Dave Hayes.\n" );
  145.     if( ! initialize() ) {
  146.     print( "\nYour MPU isn't responding within MIDIEX's timeout period.\n" );
  147.     print( "Try rebooting your system and starting over.\n" );
  148.     quit( 1 );
  149.     }
  150.     print( "\nThis program allows you to send and receive MIDI System Exclusive\n" );
  151.     print( "data dumps between your PC and a synthesizer or other MIDI device.\n" );
  152.     instruct();
  153.  
  154.     while( TRUE ) menu();
  155.  
  156.     quit( 0 );
  157. }
  158.  
  159. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  160.  
  161. BOOL file_exists( name )
  162.     char *name;
  163. {
  164.     register int f;
  165.  
  166.     if( ( f = open( name, (int)(O_RDONLY|O_BINARY) ) ) < 0 )  return FALSE;
  167.  
  168.     close( f );
  169.     return TRUE;
  170. }
  171.  
  172. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  173.  
  174. BOOL get_filename( prompt, name )
  175.     char *prompt, *name;
  176. {
  177.     char response[LINE];
  178.     char *resp;
  179.  
  180.     if( name[0] )  return TRUE;
  181.  
  182.     print( "\nEnter filename to " );
  183.     print( prompt );
  184.     print( ": " );
  185.     resp = getstring( response );
  186.     getword( &resp, name );
  187.  
  188.     return name[0] != 0;
  189. }
  190.  
  191. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  192.  
  193. BOOL initialize()
  194. {
  195.     breakstate = setbreak( 0 );
  196.     if( ! set_mpu_vector() )  return FALSE;
  197.     write_mpu_command( RESET );
  198.     write_mpu_command( UART );
  199.     return TRUE;
  200. }
  201.  
  202. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  203.  
  204. void instruct()
  205. {
  206.     print( "\nCommands are:\n" );
  207.     print( "  S pathname    to Send a data dump to your synthesizer.\n" );
  208.     print( "  R pathname    to Receive a data dump from your synthesizer.\n" );
  209.     print( "  G pathname    to Receive a GMR data dump from your Yamaha.\n\n" );
  210.     print( "Press the Esc key at any time to exit.\n" );
  211. }
  212.  
  213. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  214.  
  215. void menu()
  216. {
  217.     char response[LINE];
  218.     char *resp;
  219.     char name[LINE];
  220.     int  size;
  221.  
  222. prompt:
  223.     print( "\nCommand (S, R, G, Esc): " );
  224.     resp = getstring( response );
  225.     getword( &resp, name );
  226.  
  227.     switch( name[0] ) {
  228.  
  229.     case 'S':
  230.         getword( &resp, name );
  231.         if( ! get_filename( "send", name ) )  break;
  232.         if( size = read_dump( name ) )  send_dump( size );
  233.         print( "\n" );
  234.         break;
  235.  
  236.     case 'R':
  237.         getword( &resp, name );
  238.         if( ! get_filename( "receive", name ) )  break;
  239.         if( file_exists( name ) ) {
  240.         print( "File already exists, OK to overwrite (Y/N)? " );
  241.         getstring( response );
  242.         if( response[0] != 'Y' )  break;
  243.         }
  244.         if( size = receive_dump() )  write_dump( name, size );
  245.         print( "\n" );
  246.         break;
  247.  
  248.     case 'G':
  249.         getword( &resp, name );
  250.         if( ! get_filename( "receive", name ) )  break;
  251.         if( file_exists( name ) ) {
  252.         print( "File already exists, OK to overwrite (Y/N)? " );
  253.         getstring( response );
  254.         if( response[0] != 'Y' )  break;
  255.         }
  256.             if( size = gmr_receive_dump() )  write_dump( name, size );
  257.         print( "\n" );
  258.         break;
  259.  
  260.     default:
  261.         instruct();
  262.         goto prompt;
  263.     }
  264. }
  265.  
  266. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  267.  
  268. void quit( exitvalue )
  269.     int exitvalue;
  270. {
  271.     print( "\n\n" );
  272.     write_mpu_command( RESET );
  273.     reset_mpu_vector();
  274.     setbreak( breakstate );
  275.     _exit( exitvalue );
  276. }
  277.  
  278. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  279.  
  280. int read_dump( name )
  281.     char *name;
  282. {
  283.     register int f, size;
  284.  
  285.     if( ( f = open( name, (int)(O_RDONLY|O_BINARY) ) ) < 0 ) {
  286.     print( "\nUnable to open input file " );
  287.     print( name );
  288.     return FALSE;
  289.     }
  290.  
  291.     if( ( size = read( f, dump_buf, BUFMAX ) ) <= 0 ) {
  292.     close( f );
  293.     print( "\nTrouble reading input file " );
  294.     print( name );
  295.     return FALSE;
  296.     }
  297.  
  298.     close( f );
  299.     return size;
  300. }
  301.  
  302. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  303.  
  304. int receive_dump()
  305. {
  306.     register int i, j, k;
  307.     char printbuf[40];
  308.  
  309.     /* Set character to wait for */
  310.     wait_char = EOX;
  311.  
  312.     print( "\nSend the MIDI data now...\n" );
  313.     while( wait_char )    check_keys();
  314.  
  315. /*  The following dumps the received data in hexadecimal.
  316.     remove the comments around it if you want this display. */
  317.  
  318. /*  print( "MIDI data received...\n" );
  319.     j = 0;
  320.     for( i = 0;  i < recv_buf_ptr;  ++i ) {
  321.     sprintf( printbuf, " %2.2X", recv_buf[i] );
  322.     print( printbuf );
  323.     if( j++ == 15 ) {
  324.         print( "\n" );
  325.         j = 0;
  326.      }
  327.     }
  328.     if( j )  print( "\n" );
  329. */
  330.  
  331.     /* search backwards for start of dump */
  332.     i = recv_buf_ptr;
  333.  
  334.     for( k = 1;  k <= BUFMAX;  k++ ) {
  335.     if( --i < 0 )  i = BUFMAX;
  336.     if ( recv_buf[i] == SYSEX )  break ;
  337.     }
  338.  
  339.     if( k >= BUFMAX ) {
  340.     print( "Start of MIDI dump not found\n" );
  341.     return 0;
  342.     }
  343.  
  344.     sprintf( printbuf, "Size of dump is %d\n", k );
  345.     print( printbuf );
  346.  
  347.     for ( j = 0;  j < k;  j++ ) {
  348.     if( i == BUFMAX )  i = 0;
  349.     dump_buf[ j ] = recv_buf[ i++ ];
  350.     }
  351.  
  352.     return k;
  353. }
  354.  
  355. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  356.  
  357. #define GMR_BANK 4
  358. int gmr_receive_dump()
  359. {
  360.     register int i, j, k;
  361.     char printbuf[40];
  362.     static BYTE gmr_msg[] = { 0xF0, 0x12, 0x00, 0x00, 0x00,
  363.                               0x00, 0x11, 0xF7, 0x00 };
  364.     static int gmr_size = 8;
  365.  
  366.     /* Alright...get the frigging bank number*/
  367.     print("\nWhich bank (0 thru 9): ");    
  368.     gmr_msg[GMR_BANK] = get_a_digit();
  369.  
  370.     /* Send the GMR dump request */    
  371.     print( "\nStrike any key when ready to get GMR MIDI data...\n" );
  372.     get_char( 0 );
  373.     print( "\nSending dump request...\n" );
  374.     for (k =  0; k < gmr_size; k++) {
  375.     if( ! write_mpu_data( gmr_msg[k] ) ) {
  376.         print( "MIDI interface timed out\n" );
  377.         return FALSE;
  378.     }
  379.     check_keys();
  380.     if( gmr_msg[k] == EOX )  break;
  381.     }
  382.     print( "\nDone! Waiting for response..." );
  383.  
  384.     /* Set character to wait for */
  385.     wait_char = EOX;
  386.  
  387.     while( wait_char )    check_keys();
  388.  
  389. /*  The following dumps the received data in hexadecimal.
  390.     remove the comments around it if you want this display. */
  391.  
  392. /*  print( "MIDI data received...\n" );
  393.     j = 0;
  394.     for( i = 0;  i < recv_buf_ptr;  ++i ) {
  395.     sprintf( printbuf, " %2.2X", recv_buf[i] );
  396.     print( printbuf );
  397.     if( j++ == 15 ) {
  398.         print( "\n" );
  399.         j = 0;
  400.      }
  401.     }
  402.     if( j )  print( "\n" );
  403. */
  404.  
  405.     /* search backwards for start of dump */
  406.     i = recv_buf_ptr;
  407.  
  408.     for( k = 1;  k <= BUFMAX;  k++ ) {
  409.     if( --i < 0 )  i = BUFMAX;
  410.     if ( recv_buf[i] == SYSEX )  break ;
  411.     }
  412.  
  413.     if( k >= BUFMAX ) {
  414.     print( "Start of MIDI dump not found\n" );
  415.     return 0;
  416.     }
  417.  
  418.     sprintf( printbuf, "Size of dump is %d\n", k );
  419.     print( printbuf );
  420.  
  421.     for ( j = 0;  j < k;  j++ ) {
  422.     if( i == BUFMAX )  i = 0;
  423.     dump_buf[ j ] = recv_buf[ i++ ];
  424.     }
  425.  
  426.     return k;
  427. }
  428.  
  429. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  430.  
  431. BOOL send_dump( size )
  432.     int size;
  433. {
  434.     register int i;
  435.  
  436.     print( "\nStrike any key when ready to send MIDI data...\n" );
  437.     get_char( 0 );
  438.     print( "\nSending MIDI data...\n" );
  439.     for (i =  0; i <= size; i++) {
  440.     if( ! write_mpu_data( dump_buf[i] ) ) {
  441.         print( "MIDI interface timed out\n" );
  442.         return FALSE;
  443.     }
  444.     check_keys();
  445.     if( dump_buf[i] == EOX )  break;
  446.     }
  447.     print( "\nDone!" );
  448.     return TRUE;
  449. }
  450.  
  451. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  452.  
  453. BOOL setbreak( newstate )
  454.     BOOL newstate;
  455. /*
  456.  *  Sets DOS Ctrl-Break checking to newstate and returns previous state.
  457.  */
  458. {
  459.     BOOL oldstate;
  460.     union REGS regs;
  461.  
  462.     regs.x.ax = 0x3300;
  463.     intdos( ®s, ®s );
  464.     oldstate = (BOOL)regs.h.dl;
  465.  
  466.     regs.x.ax = 0x3301;
  467.     regs.h.dl = (unsigned char)newstate;
  468.     intdos( ®s, ®s );
  469.  
  470.     return oldstate;
  471. }
  472.  
  473. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  474.  
  475. BOOL write_dump( name, size )
  476.     register char *name;
  477.     int size;
  478. {
  479.     register int f;
  480.  
  481.     if( ( f = open( name, (int)(O_CREAT|O_TRUNC|O_WRONLY|O_BINARY), S_IWRITE ) ) < 0 ) {
  482.     print( "\nUnable to open output file " );
  483.     print( name );
  484.     return FALSE;
  485.     }
  486.  
  487.     if( write( f, dump_buf, size ) != size ) {
  488.     close( f );
  489.     print( "\nTrouble writing to output file " );
  490.     print( name );
  491.     return FALSE;
  492.     }
  493.  
  494.     close( f );
  495.     print( "\nDone!" );
  496.     return TRUE;
  497. }
  498.  
  499. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  500.  
  501. /*
  502.  *
  503.  * lower level editing routines
  504.  *
  505.  */
  506.  
  507. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  508.  
  509. BYTE get_a_digit()
  510. {
  511.     register char c;
  512.     char pbuf[40];
  513.  
  514. getdigit:
  515.     while ( get_char( 1 ) != 1 ) ;
  516.     c = (char)( get_char( 0 ) & 0xFF );
  517.     if( c == ESC ) quit( 0 );
  518.     if (c < '0' || c > '9') goto getdigit;    
  519.  
  520.     sprintf(pbuf,"%c",c);
  521.     print(pbuf);
  522.     return ((BYTE) (c - '0'));
  523. }
  524.  
  525. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  526.  
  527. void check_keys()
  528. {
  529.     register char c;
  530.  
  531.     if( get_char( 1 ) == 1 ) {
  532.     c = (char)( get_char( 0 ) & 0xFF );
  533.     if( c == ESC )    quit( 0 );
  534.     }
  535. }
  536.  
  537. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  538.  
  539. char *getstring( string )
  540.     char *string;
  541. {
  542.     register int x = 0;
  543.     register char c;
  544.  
  545.     while( TRUE ) {
  546.     c = (char)( get_char( 0 ) & 0xFF );
  547.     if( c == ESC )    quit( 0 );
  548.     if( c == CR ) {
  549.         print( "\n" );
  550.         string[x] = '\0';
  551.         return string;
  552.     }
  553.     if( ( c >= 32 && c < 127 ) || c == CR ) {
  554.         string[ x++ ] = toupper( c );
  555.         int10( 0x0E00 | c, 0, 0, 0 );
  556.     } else if( c == 8  &&  x > 0 ) {
  557.         int10( 0x0E00 | c, 0, 0, 0 );
  558.         int10( 0x0A00 | ' ', 7, 1, 0 );
  559.         --x;
  560.     }
  561.     }
  562. }
  563.  
  564. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  565.  
  566. void getword( strpp, word )
  567.     char **strpp;
  568.     char *word;
  569. {
  570.     char *wordp;
  571.  
  572.     wordp = word;
  573.     while( isspace( **strpp ) ) (*strpp)++;
  574.     while( **strpp && ! isspace( **strpp ) )  *wordp++ = *(*strpp)++;
  575.     *wordp = 0;
  576. }
  577.  
  578. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  579.  
  580. void print( string )
  581.     register char *string;
  582. {
  583.     register char c;
  584.  
  585.     while( c = *string++ ) {
  586.     if( c == '\n' )  int10( 0x0E00 | '\r', 0, 0, 0 );
  587.     int10( 0x0E00 | c, 0, 0, 0 );
  588.     }
  589. }
  590.  
  591. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  592.