home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Sound Sensations!
/
sound_sensations.iso
/
miditool
/
midiex18
/
midiex.c
next >
Wrap
C/C++ Source or Header
|
1989-12-07
|
13KB
|
430 lines
/****************************************************************************
* 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...
*
*
* Updated by Mike W. Smith, 12/5/89
* (No changes in the copyright either)
* Complete rewrite of C and ASM code,
* Now compiles in Turbo C.
* Goes back to using standard C I/O and handles Control-Breaks and other
* error conditions correctly,
* Allows the MPU's port address and IRQ level and the size of the buffer to
* be set with command line arguments,
* Now handles the interrupt controller properly on AT's and 386's,
*
***************************************************************************/
#if defined(__TURBOC__)
#include <dir.h> /* Turbo C */
#else
#include <direct.h> /* Microsoft C/QuickC */
#endif
#include <conio.h>
#include <dos.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "midiex.h"
/* Function prototypes for this file */
int _Cdecl init_mpu(void);
void _Cdecl instruct(void);
void _Cdecl listfiles(void);
void _Cdecl menu(void);
void _Cdecl receivefile(void);
void _Cdecl set_irq(int level);
void _Cdecl set_address(long address);
int _Cdecl set_buffer(int size);
void _Cdecl transmitfile (void);
/* Global data */
int buffer_size;
int error;
/*--------------------------------------------------------------------------*/
/* Start of code */
void main(int argc,char **argv)
{
char *stop_at;
int i;
clrscr();
printf("MIDIEX patch exchange utility.\n");
printf("Copyright (C) 1986 by Cantus Corportaion.\n");
printf("Modifications (C) 1986 by Jim Bergsten.\n");
printf("Version 1.2, updated 1986 by Michael Geary.\n");
printf("Version 1.3, updated 1988 by David Hayes. \n");
printf("Version 1.8, updated 1989 by Mike W. Smith. \n");
printf("\nThis program allows you to send and receive MIDI System Exclusive\n" );
printf("data dumps between your PC and a synthesizer or other MIDI device.\n" );
/* Get command line arguments and set the IRQ level and MPU address */
if(argc>1) {
if(!strcmp(argv[1],"?")) {
printf("\n\nTo set the size of the buffer, the IRQ level, and the MPU's address, use:\n");
printf("\n MIDIEX /B:nnnn /I:n /A:nnn \n");
printf("\nwhere /B:nnnn is the size of the buffer,\n");
printf(" /I:n is the IRQ level,\n");
printf(" /A:nnn is the base address of the MPU-401\n");
printf(" (use 0xnnn to indicate hexidecimal numbering).\n\n");
printf("Defaults are /B:1024 /I:2 /A:0x330.\n");
return;
}
for(i=1;i<=argc;i++) {
if(!strnicmp(argv[i],"/B:",3)) if(!set_buffer(atoi(argv[i]+3))) {
printf("\n\n ERROR - not enough memory for buffer.\n\n");
return;
}
if(!strnicmp(argv[i],"/I:",3)) set_irq(atoi(argv[i]+3));
if(!strnicmp(argv[i],"/A:",3)) set_address(strtol(argv[2]+3,&stop_at,0));
}
}
if(!buffer_ptr) if(!set_buffer(1024)) {
printf("\n\n ERROR - not enough memory for buffer.\n\n");
return;
}
/* Set Ctrl-Break vector to avoid the possibility of exiting in the */
/* middle of the program without resetting the MPU vectors. */
set_ctrl_brk();
/* Initialize the MPU */
if(!init_mpu()) {
printf("\n\nThe MPU failed to initialize. Turn off your computer to reset your MPU.\n\n" );
free((void *)buffer_ptr);
reset_ctrl_brk();
return;
}
/* Display instructions */
instruct();
menu();
/* All done. Reset everything. */
send_command(RESET);
reset_mpu_vector();
reset_ctrl_brk();
free((void *)buffer_ptr);
/* If no error forced the exit, then clear screen. */
if(!error) clrscr();
}
/*---------------------------------------------------------------------------*/
/* Initializes the MPU and sets it to UART mode */
int init_mpu(void)
{
set_mpu_vector();
/* Try reseting at least twice in case the MPU was in UART mode */
if(!send_command(RESET)) if(!send_command(RESET)) {
reset_mpu_vector();
return(FAIL);
}
if(!send_command(0xAC)) { /* Does it return a version number? */
reset_mpu_vector();
return(FAIL);
}
if(!send_command(UART)) {
reset_mpu_vector();
return(FAIL);
}
return(SUCCESS);
}
/*---------------------------------------------------------------------------*/
/* Display instructions for using MIDIEX */
void instruct(void)
{
printf("\nCommands are:\n" );
printf(" T (path\\)filename to Transmit a data dump to your synthesizer.\n");
printf(" R (path\\)filename to Receive a data dump from your synthesizer.\n");
printf(" F (path\\)filespec to list files in the directory.\n\n");
printf("Press the Esc key at any time to exit.\n");
}
/*---------------------------------------------------------------------------*/
/* Lists the specified files on screen */
void list_files(void)
{
struct ffblk fileinfo;
char filename[81];
printf("\n\nFiles to display: ");
scanf("%s",filename);
if(!findfirst(filename,&fileinfo,0)) printf("\n%-16s",fileinfo.ff_name);
else {
printf("\n\nNo matching files.\n\n");
return;
}
while(!findnext(&fileinfo)) printf("%-16s",fileinfo.ff_name);
printf("\n");
}
/*---------------------------------------------------------------------------*/
/* Displays the menu for MIDIEX */
void menu(void)
{
int i=0;
while(i!=ESC) {
printf("\nCommand (T, R, F, Esc): " );
switch(i=getch()) {
case 'F':
case 'f':
list_files();
break;
case 'T':
case 't':
error=0;
set_handler(no_op);
transmitfile();
break;
case 'R':
case 'r':
error=0;
receivefile();
set_handler(no_op);
break;
case ESC:
break;
default:
error=0;
printf("\n");
instruct();
break;
}
}
}
/*----------------------------------------------------------------------------*/
/* Writes received SYSEX data to a file */
void receivefile(void)
{
FILE *fptr;
struct ffblk fileinfo;
char filename[81];
int i;
start:
printf("\n\nFilename to save to: ");
scanf("%s",filename);
if(!findfirst(filename,&fileinfo,0)) {
printf("\nFile already exists. Overwrite? ");
while(1) {
switch(getch()) {
case 'Y':
case 'y':
printf("\n");
goto open_file;
case 'N':
case 'n':
goto start;
default:
continue;
}
}
}
open_file:
fptr=fopen(filename,"wb");
printf("\nSend your SYSEX data now. (Hit ESC to abort).");
buffer_end=sysex_ended=0;
set_handler(receive_sysex);
while(!sysex_ended) {
if(kbhit()) {
i=getch();
if(((char)i==ESC)||((char)i==3)) {
printf("\n\nUser break. Action aborted.\n\n");
fclose(fptr);
remove(filename);
error=1;
return;
}
}
}
set_handler(no_op);
if(!buffer_end) {
printf("\n\nError receiving data. Action aborted.\n\n");
fclose(fptr);
remove(filename);
error=1;
return;
}
for(i=0;i<buffer_end;i++) fputc(*(buffer_ptr+i),fptr);
printf("\n\nReceived %u bytes. Writing to file %s.\n",buffer_end,filename);
fclose(fptr);
}
/*----------------------------------------------------------------------------*/
/* Sets the data port and the command and status port addresses */
void set_address(long address)
{
if(((int)address>0x200)&&((int)address<0x400)) {
mpu_data_port = (int)address;
mpu_status_port = (int)address+1;
}
else {
mpu_data_port = 0x330;
mpu_status_port = 0x331;
}
}
/*----------------------------------------------------------------------------*/
/* Sets the queue buffer for holding the incoming SYSEX data */
int set_buffer(int size)
{
if(!size) size=1024;
if((buffer_ptr=(char *)malloc(buffer_size=size))==NULL) return(FAIL);
return(SUCCESS);
}
/*---------------------------------------------------------------------------*/
/* Sets the IRQ variables */
void set_irq(int level)
{
/* If an IRQ level of 2 is declared on an AT or 386 computer, then */
/* convert it to a 9. */
if(second_8259()) if(level==2) level=9;
switch(level) {
case 3:
mpu_irq = 0xB;
irq_mask= 8;
eoi = 0x63;
break;
case 4:
mpu_irq = 0xC;
irq_mask= 16;
eoi = 0x64;
break;
case 5:
mpu_irq = 0xD;
irq_mask= 32;
eoi = 0x65;
break;
case 6:
mpu_irq = 0xE;
irq_mask= 64;
eoi = 0x66;
break;
case 7:
mpu_irq = 0xF;
irq_mask= 128;
eoi = 0x67;
break;
case 9:
mpu_irq = 0x71;
irq_mask= 2;
eoi = 0x6162;
break;
default:
mpu_irq = 0xA;
irq_mask= 4;
eoi = 0x62;
}
}
/*----------------------------------------------------------------------------*/
/* Sends a SYSEX file */
void transmitfile (void)
{
FILE *fptr;
char filename[81];
int i,j=0;
printf("\n\nName of file to transmit: ");
scanf("%s",filename);
if((fptr=fopen(filename,"rb"))==NULL) {
printf("\n\nCouldn't find the file %s.\n\n",filename);
fclose(fptr);
error=1;
return;
}
printf("\nHit any key to transmit.");
i=getch();
if((i==BRK)||(i==ESC)) {
printf("\n\nTransmission aborted.\n");
fclose(fptr);
error=1;
return;
}
while((i=fgetc(fptr))!=EOF) {
if(!send_data(i)) {
printf("\n\nError sending the file. Transmission aborted.\n\n");
fclose(fptr);
error=1;
return;
}
j++;
}
printf("\n\nTransmission complete, %u bytes sent.\n",j);
fclose(fptr);
}