home *** CD-ROM | disk | FTP | other *** search
/ Sound Sensations! / sound_sensations.iso / miditool / midiex18 / midiex.c next >
C/C++ Source or Header  |  1989-12-07  |  13KB  |  430 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.  *
  31.  *  Updated by Mike W. Smith, 12/5/89
  32.  *  (No changes in the copyright either)
  33.  *  Complete rewrite of C and ASM code,
  34.  *  Now compiles in Turbo C.
  35.  *  Goes back to using standard C I/O and handles Control-Breaks and other
  36.  *   error conditions correctly,
  37.  *  Allows the MPU's port address and IRQ level and the size of the buffer to
  38.  *   be set with command line arguments,
  39.  *  Now handles the interrupt controller properly on AT's and 386's,
  40.  *
  41.  ***************************************************************************/
  42.  
  43. #if defined(__TURBOC__)
  44. #include <dir.h>        /* Turbo C */
  45. #else
  46. #include <direct.h>     /* Microsoft C/QuickC */
  47. #endif
  48.  
  49. #include <conio.h>
  50. #include <dos.h>
  51. #include <stdio.h>
  52. #include <stdlib.h>
  53. #include <string.h>
  54. #include "midiex.h"
  55.  
  56.  
  57. /* Function prototypes for this file    */
  58. int     _Cdecl  init_mpu(void);
  59. void    _Cdecl  instruct(void);
  60. void    _Cdecl  listfiles(void);
  61. void    _Cdecl  menu(void);
  62. void    _Cdecl  receivefile(void);
  63. void    _Cdecl  set_irq(int level);
  64. void    _Cdecl  set_address(long address);
  65. int     _Cdecl  set_buffer(int size);
  66. void    _Cdecl  transmitfile (void);
  67.  
  68.  
  69. /* Global data  */
  70. int buffer_size;
  71. int error;
  72.  
  73. /*--------------------------------------------------------------------------*/
  74.  
  75. /* Start of code */
  76.  
  77. void main(int argc,char **argv)
  78. {
  79.     char *stop_at;
  80.        int i;
  81.  
  82.     clrscr();
  83.     printf("MIDIEX patch exchange utility.\n");
  84.     printf("Copyright (C) 1986 by Cantus Corportaion.\n");
  85.     printf("Modifications (C) 1986 by Jim Bergsten.\n");
  86.     printf("Version 1.2, updated 1986 by Michael Geary.\n");
  87.     printf("Version 1.3, updated 1988 by David Hayes. \n");
  88.     printf("Version 1.8, updated 1989 by Mike W. Smith. \n");
  89.     printf("\nThis program allows you to send and receive MIDI System Exclusive\n" );
  90.     printf("data dumps between your PC and a synthesizer or other MIDI device.\n" );
  91.  
  92.     /* Get command line arguments and set the IRQ level and MPU address */
  93.     if(argc>1) {
  94.         if(!strcmp(argv[1],"?")) {
  95.             printf("\n\nTo set the size of the buffer, the IRQ level, and the MPU's address, use:\n");
  96.             printf("\n    MIDIEX /B:nnnn /I:n /A:nnn \n");
  97.             printf("\nwhere /B:nnnn is the size of the buffer,\n");
  98.             printf("      /I:n is the IRQ level,\n");
  99.             printf("      /A:nnn is the base address of the MPU-401\n");
  100.             printf("      (use 0xnnn to indicate hexidecimal numbering).\n\n");
  101.             printf("Defaults are /B:1024 /I:2 /A:0x330.\n");
  102.             return;
  103.         }
  104.         for(i=1;i<=argc;i++) {
  105.             if(!strnicmp(argv[i],"/B:",3)) if(!set_buffer(atoi(argv[i]+3))) {
  106.                 printf("\n\n        ERROR - not enough memory for buffer.\n\n");
  107.                 return;
  108.             }
  109.             if(!strnicmp(argv[i],"/I:",3)) set_irq(atoi(argv[i]+3));
  110.             if(!strnicmp(argv[i],"/A:",3)) set_address(strtol(argv[2]+3,&stop_at,0));
  111.         }
  112.     }
  113.  
  114.     if(!buffer_ptr) if(!set_buffer(1024)) {
  115.         printf("\n\n        ERROR - not enough memory for buffer.\n\n");
  116.         return;
  117.     }
  118.  
  119.     /* Set Ctrl-Break vector to avoid the possibility of exiting in the  */
  120.     /* middle of the program without resetting the MPU vectors.          */
  121.     set_ctrl_brk();
  122.  
  123.     /* Initialize the MPU   */
  124.     if(!init_mpu()) {
  125.         printf("\n\nThe MPU failed to initialize.  Turn off your computer to reset your MPU.\n\n" );
  126.         free((void *)buffer_ptr);
  127.         reset_ctrl_brk();
  128.         return;
  129.     }
  130.  
  131.     /* Display instructions */
  132.     instruct();
  133.  
  134.     menu();
  135.  
  136.     /* All done.  Reset everything. */
  137.     send_command(RESET);
  138.     reset_mpu_vector();
  139.     reset_ctrl_brk();
  140.     free((void *)buffer_ptr);
  141.  
  142.     /* If no error forced the exit, then clear screen.  */
  143.     if(!error) clrscr();
  144. }
  145.  
  146. /*---------------------------------------------------------------------------*/
  147.  
  148. /* Initializes the MPU and sets it to UART mode                              */
  149.  
  150. int init_mpu(void)
  151. {
  152.     set_mpu_vector();
  153.     /* Try reseting at least twice in case the MPU was in UART mode */
  154.     if(!send_command(RESET)) if(!send_command(RESET)) {
  155.         reset_mpu_vector();
  156.         return(FAIL);
  157.     }
  158.     if(!send_command(0xAC)) {   /* Does it return a version number? */
  159.         reset_mpu_vector();
  160.         return(FAIL);
  161.     }
  162.     if(!send_command(UART)) {
  163.         reset_mpu_vector();
  164.         return(FAIL);
  165.     }
  166.     return(SUCCESS);
  167. }
  168.  
  169. /*---------------------------------------------------------------------------*/
  170.  
  171. /* Display instructions for using MIDIEX                                     */
  172.  
  173. void instruct(void)
  174. {
  175.     printf("\nCommands are:\n" );
  176.     printf("  T (path\\)filename    to Transmit a data dump to your synthesizer.\n");
  177.     printf("  R (path\\)filename    to Receive a data dump from your synthesizer.\n");
  178.     printf("  F (path\\)filespec    to list files in the directory.\n\n");
  179.     printf("Press the Esc key at any time to exit.\n");
  180. }
  181.  
  182. /*---------------------------------------------------------------------------*/
  183.  
  184. /* Lists the specified files on screen                                       */
  185.  
  186. void list_files(void)
  187. {
  188.     struct ffblk fileinfo;
  189.     char filename[81];
  190.  
  191.     printf("\n\nFiles to display: ");
  192.     scanf("%s",filename);
  193.     if(!findfirst(filename,&fileinfo,0)) printf("\n%-16s",fileinfo.ff_name);
  194.     else {
  195.         printf("\n\nNo matching files.\n\n");
  196.         return;
  197.     }
  198.     while(!findnext(&fileinfo)) printf("%-16s",fileinfo.ff_name);
  199.     printf("\n");
  200. }
  201.  
  202. /*---------------------------------------------------------------------------*/
  203.  
  204. /* Displays the menu for MIDIEX                                              */
  205.  
  206. void menu(void)
  207. {
  208.     int i=0;
  209.  
  210.     while(i!=ESC) {
  211.         printf("\nCommand (T, R, F, Esc): " );
  212.  
  213.         switch(i=getch()) {
  214.  
  215.         case 'F':
  216.         case 'f':
  217.             list_files();
  218.             break;
  219.  
  220.         case 'T':
  221.         case 't':
  222.             error=0;
  223.             set_handler(no_op);
  224.             transmitfile();
  225.             break;
  226.  
  227.         case 'R':
  228.         case 'r':
  229.             error=0;
  230.             receivefile();
  231.             set_handler(no_op);
  232.             break;
  233.  
  234.         case ESC:
  235.             break;
  236.  
  237.         default:
  238.             error=0;
  239.             printf("\n");
  240.             instruct();
  241.             break;
  242.         }
  243.     }
  244. }
  245.  
  246. /*----------------------------------------------------------------------------*/
  247.  
  248. /* Writes received SYSEX data to a file                                       */
  249.  
  250. void receivefile(void)
  251. {
  252.     FILE *fptr;
  253.     struct ffblk fileinfo;
  254.     char filename[81];
  255.     int i;
  256.  
  257. start:
  258.     printf("\n\nFilename to save to: ");
  259.     scanf("%s",filename);
  260.     if(!findfirst(filename,&fileinfo,0)) {
  261.         printf("\nFile already exists.  Overwrite? ");
  262.         while(1) {
  263.             switch(getch()) {
  264.  
  265.             case 'Y':
  266.             case 'y':
  267.                 printf("\n");
  268.                 goto open_file;
  269.  
  270.             case 'N':
  271.             case 'n':
  272.                 goto start;
  273.  
  274.             default:
  275.                 continue;
  276.             }
  277.         }
  278.     }
  279.  
  280. open_file:
  281.     fptr=fopen(filename,"wb");
  282.     printf("\nSend your SYSEX data now.  (Hit ESC to abort).");
  283.     buffer_end=sysex_ended=0;
  284.     set_handler(receive_sysex);
  285.     while(!sysex_ended) {
  286.         if(kbhit()) {
  287.             i=getch();
  288.             if(((char)i==ESC)||((char)i==3)) {
  289.                 printf("\n\nUser break.  Action aborted.\n\n");
  290.                 fclose(fptr);
  291.                 remove(filename);
  292.                 error=1;
  293.                 return;
  294.             }
  295.         }
  296.     }
  297.     set_handler(no_op);
  298.     if(!buffer_end) {
  299.         printf("\n\nError receiving data.  Action aborted.\n\n");
  300.         fclose(fptr);
  301.         remove(filename);
  302.         error=1;
  303.         return;
  304.     }
  305.     for(i=0;i<buffer_end;i++) fputc(*(buffer_ptr+i),fptr);
  306.     printf("\n\nReceived %u bytes.  Writing to file %s.\n",buffer_end,filename);
  307.     fclose(fptr);
  308. }
  309.  
  310. /*----------------------------------------------------------------------------*/
  311.  
  312. /* Sets the data port and the command and status port addresses               */
  313.  
  314. void set_address(long address)
  315. {
  316.     if(((int)address>0x200)&&((int)address<0x400)) {
  317.         mpu_data_port   =   (int)address;
  318.         mpu_status_port =   (int)address+1;
  319.     }
  320.     else {
  321.         mpu_data_port   =   0x330;
  322.         mpu_status_port =   0x331;
  323.     }
  324. }
  325.  
  326. /*----------------------------------------------------------------------------*/
  327.  
  328. /* Sets the queue buffer for holding the incoming SYSEX data                  */
  329.  
  330. int set_buffer(int size)
  331. {
  332.     if(!size) size=1024;
  333.     if((buffer_ptr=(char *)malloc(buffer_size=size))==NULL) return(FAIL);
  334.     return(SUCCESS);
  335. }
  336.  
  337. /*---------------------------------------------------------------------------*/
  338.  
  339. /* Sets the IRQ variables   */
  340.  
  341. void set_irq(int level)
  342. {
  343.     /* If an IRQ level of 2 is declared on an AT or 386 computer, then  */
  344.     /* convert it to a 9.                                               */
  345.     if(second_8259()) if(level==2) level=9;
  346.  
  347.     switch(level) {
  348.     case 3:
  349.         mpu_irq =   0xB;
  350.         irq_mask=   8;
  351.         eoi     =   0x63;
  352.         break;
  353.  
  354.     case 4:
  355.         mpu_irq =   0xC;
  356.         irq_mask=   16;
  357.         eoi     =   0x64;
  358.         break;
  359.  
  360.     case 5:
  361.         mpu_irq =   0xD;
  362.         irq_mask=   32;
  363.         eoi     =   0x65;
  364.         break;
  365.  
  366.     case 6:
  367.         mpu_irq =   0xE;
  368.         irq_mask=   64;
  369.         eoi     =   0x66;
  370.         break;
  371.  
  372.     case 7:
  373.         mpu_irq =   0xF;
  374.         irq_mask=   128;
  375.         eoi     =   0x67;
  376.         break;
  377.  
  378.     case 9:
  379.         mpu_irq =   0x71;
  380.         irq_mask=   2;
  381.         eoi     =   0x6162;
  382.         break;
  383.  
  384.     default:
  385.         mpu_irq =   0xA;
  386.         irq_mask=   4;
  387.         eoi     =   0x62;
  388.     }
  389. }
  390.  
  391. /*----------------------------------------------------------------------------*/
  392.  
  393. /* Sends a SYSEX file                                                         */
  394.  
  395. void transmitfile (void)
  396. {
  397.     FILE *fptr;
  398.     char filename[81];
  399.     int i,j=0;
  400.  
  401.     printf("\n\nName of file to transmit: ");
  402.     scanf("%s",filename);
  403.     if((fptr=fopen(filename,"rb"))==NULL) {
  404.         printf("\n\nCouldn't find the file %s.\n\n",filename);
  405.         fclose(fptr);
  406.         error=1;
  407.         return;
  408.     }
  409.     printf("\nHit any key to transmit.");
  410.     i=getch();
  411.     if((i==BRK)||(i==ESC)) {
  412.         printf("\n\nTransmission aborted.\n");
  413.         fclose(fptr);
  414.         error=1;
  415.         return;
  416.     }
  417.     while((i=fgetc(fptr))!=EOF) {
  418.         if(!send_data(i)) {
  419.             printf("\n\nError sending the file.  Transmission aborted.\n\n");
  420.             fclose(fptr);
  421.             error=1;
  422.             return;
  423.         }
  424.         j++;
  425.     }
  426.  
  427.     printf("\n\nTransmission complete, %u bytes sent.\n",j);
  428.     fclose(fptr);
  429. }
  430.