#include <exec/types.h>
#include <exec/ports.h>
#include <exec/devices.h>
#include <exec/memory.h>
#include <exec/interrupts.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/libraries.h>
#include <exec/tasks.h>
#include <exec/execbase.h>
#include <exec/io.h>
#include <exec/resident.h>
#include <exec/execname.h>
#include <exec/exec.h>
#include <exec/errors.h>
#include <exec/alerts.h>
#include <devices/serial.h>
#include <stdio.h>
#include <ctype.h>

static char *commonarray[4] = {
		"Partial Structure 1 & 2",
		"Partial Structure 3 & 4",
		"Partial Mute",
		"Env Mode"
		};
		
static char *tonearray[58] = {"WGPitchCoarse        ",
		"WG Pitch Fine        ",
		"WG Pitch KeyFollow   ",
		"WG Pitch Bender SW   ",
		"WG Waveform          ",
		"WG PCM Wave          ",
		"WG Pulse Width       ",
		"WG PW Velo Sens      ",
		"P-Env Depth          ",
		"P-Env Velo Sens      ",
		"P-Env Time Keyf      ",
		"P-Env Time 1         ",
		"P-Env Time 2         ",
		"P-Env Time 3         ",
		"P-Env Time 4         ",
		"P-Env Level 0        ",
		"P-Env Level 1        ",
		"P-Env Level 2        ",
		"P-Env Sustain Level  ",
		"End Level            ",
		"P-LFO Rate           ",
		"P-LFO Depth          ",
		"P-LFO Mod Sens       ",
		"TVF Cutoff Freq      ",
		"TVF Resonance        ",
		"TVF Keyfollow        ",
		"TVF Bias Point       ",	
		"TVF Bias Level       ",
		"TVF Env Depth        ",
		"TVF Env Velo Sens    ",
		"TVF Env Depth Keyf   ",
		"TVF Env Time Keyf    ",
		"TVF Env Time 1       ",
		"TVF Env Time 2       ",
		"TVF Env Time 3       ",
		"TVF Env Time 4       ",
		"TVF Env Time 5	     ",
		"TVF Env Level 1      ",
		"TVF Env Level 2      ",
		"TVF Env Level 3      ",
		"TVF Env Sustain Level",
		"TVA Level	     ",
		"TVA Velo Sens        ",
		"TVA Bias Point 1     ",
		"TVA Bias Level 1     ",
		"TVA Bias Point 2     ",
		"TVA Bias Level 2     ",
		"TVA Env Time Keyf    ",
		"TVA Env Time V_Follow",
		"TVA Env Time 1       ",
		"TVA Env Time 2       ",
		"TVA Env Time 3       ",
		"TVA Env Time 4       ",
		"TVA Env Time 5       ",
		"TVA Env Level 1      ",	
		"TVA Env Level 2      ",
		"TVA Env Level 3      ",
		"TVA Env Sustain Level"
		};	
/* Resource allocation bits */

#define SERIAL_PORT	(1 << 0)
#define SERIAL_EXTIO	(1 << 1)
#define SERIAL_DEVICE	(1 << 2)
#define TIMER_PORT	(1 << 3)
#define TIMER_EXTIO	(1 << 4)
#define TIMER_DEVICE	(1 << 5)
#define ICR_VECTOR	(1 << 6)
#define ARRAY_ALLOCATED	(1 << 7)



/* MIDI end-system-exclusive byte */

#define END_SYSTEM_EXCLUSIVE	0xF7

#define MIDI_STATUS_MASK	0x80

/* Routine declarations */

extern struct MsgPort *CreatePort();
extern struct IORequest *CreateExtIO();

LONG ReadToneData();
void WriteToneData();

/* Serial device structures */

struct IOExtSer *IORser;
struct MsgPort *serialport;

UBYTE tonedata[246];
int channel,patchg,patchn,parameter,address,timbre,resources=0;
int i,cort,channum,notenum;
char filename[80];

main()
{
int error,x;

/* Create a message port for the serial device */

serialport = CreatePort(SERIALNAME,0);
if (serialport == NULL) Cleanup("Unable to CreatePort serial",100);


/* Create an I/O request block for the serial device */

IORser = (struct IOExtSer *)
	CreateExtIO(serialport, sizeof(struct IOExtSer));

if (IORser == NULL) Cleanup("Unable to CreateExtIO serial",200);

resources |= SERIAL_EXTIO;

/* Open the serial device */

if ((error = OpenDevice(SERIALNAME,0,IORser,0))!= 0)
	Cleanup("Unable to open serial device",error);

resources |= SERIAL_DEVICE;

/* Set serial device parameters for MIDI communications */

if ((error = SetParams(IORser)) != 0)
	Cleanup("Unable to set serial parameters",error);


for (;;) {
	char buf[80];
	UBYTE *ptr;
	printf("\nMT-32 Editor Commands:\n");
	
	printf("  [D]ownload tone data to MT-32\n");
	printf("  [U]pload tone data from Temp Memory in MT-32\n");
	printf("  [P]rint tone data\n");
	printf("  [L]oad tone data to Parts\n");
	printf("  [Q]uantify tone data\n");
	printf("  [S]how particular data\n");
	printf("  [M]odify patch in MT-32\n");
	printf("  [R]everb Modify in MT-32\n");
	printf("  [N]ame change of Channel\n");
	printf("  [A]ssign Presets to Memory (1-8)\n");
	printf("  [E]xit\n\n");

	printf("Enter command > ");
	gets(buf);

	switch (toupper(buf[0])) {
		
		case 'L': if (ReadToneData (&tonedata))
			  printf("Which channel? (1-8) > ");
			  gets(buf);
			  channel=atoi(buf);
			  SendToneData (&tonedata,channel-1);
			  SendPatchData (channel,2,channel-1);
			  break;
			  
		case 'D': if (ReadToneData (&tonedata))
			  printf("Which Timbre? (1-64) > ");
			  gets(buf);
			  timbre=atoi(buf);
			  SendToneData (&tonedata,timbre);
			  break;
			  
		case 'U': printf("Which Address? 4(Part 1) or 8 > ");
			  gets(buf);
			  address=atoi(buf);
			  if(address==4) {
			   timbre=1;
			   goto place;
			   }
			  printf("Which Timbre? (1-64) > ");
			  gets(buf);
			  timbre=atoi(buf);
			  place:
			  printf("Save Timbre as Filename > ");
			  gets(filename);
			  ReceiveToneData (address,&tonedata,timbre-1);
			  WriteToneData (&tonedata,&filename);
			  break;
		case 'Q': printf("Which Timbre (1-8)? > ");	  
			  gets(buf);
			  timbre=atoi(buf);
			  ReceiveToneData (8,&tonedata,timbre-1);
			  printf("ToneData or CommonData (0 or 1)? > ");
			  gets(buf);
			  cort=atoi(buf);
			  if (cort) {
			  	for (i=10;i<14;i++)
			  	QuantifyToneData(&tonedata,cort,i);
			  }
			  else  {
			  	for (i=0;i<58;i++)
			  	QuantifyToneData(&tonedata,cort,i);
			  }
			  break;
		case 'S': printf("Which Timbre (1-8)? > ");	  
			  gets(buf);
			  timbre=atoi(buf);
			  printf("ToneData or CommonData (0 or 1)? > ");
			  gets(buf);
			  cort=atoi(buf);
			  if(!cort)  {
			  printf("Which Partial Parameter (1-58)? > ");	  
			  gets(buf);
			  i=atoi(buf);
			  ReceiveToneData (8,&tonedata,timbre-1);
			  QuantifyToneData(&tonedata,0,i-1);
			  }
			  else {
			  printf("Which Common Parameter (1-4) > "); 
			  gets(buf);
			  i=atoi(buf);
			  ReceiveToneData (8,&tonedata,timbre-1);
			  QuantifyToneData(&tonedata,1,i+9);
			  }
			  break;
		case 'P': if (ReadToneData (&tonedata))
			  PrintToneData(&tonedata);
			  break;
		case 'A': for (x=0;x<8;x++)  {
				ModifyPatchData(x+1,5,0,2);
				ModifyPatchData(x+1,5,1,x);
				}
			  break;
		case 'M': printf("Which Address Area? (3,5,8,10) > ");
			  gets(buf);
			  address=atoi(buf);
			  if(address== 3 || address==5 || address==10) goto system;
			  printf("Modify Which Timbre? (1-8) > ");
			  gets(buf);
			  timbre=atoi(buf);
			  printf("ToneData or CommonData (0 or 1)? > ");
			  gets(buf);
			  cort=atoi(buf);
			  if(!cort)  {
			  printf("Modify Which Patch (1-4) > "); 
			  gets(buf);
			  x=atoi(buf);
			  printf("Modify Which Partial Parameter? (1-58) > ");
			  gets(buf);
			  parameter=atoi(buf);
			  printf("New Data > ");
			  gets(buf);
			  patchn=atoi(buf);
			  ReceiveToneData (8,&tonedata,timbre-1);
			  ptr=&tonedata;
			  *(ptr+(x-1)*58+parameter+13)=patchn;
			  SendToneData (&tonedata,timbre-1);
			  SendPatchData (timbre,2,timbre-1);
			  }
			  else {
			  printf("Modify Which Common Parameter (1-4) > "); 
			  gets(buf);
			  parameter=atoi(buf);
			  printf("New Data > ");
			  gets(buf);
			  patchn=atoi(buf);
			  ModifyPatchData(timbre,address,parameter+9,patchn);
			  SendPatchData (timbre,2,timbre-1);
			  }
			  break;
			  system:
			  if (address==10) goto tenspot;
			  printf("Modify Which Channel > ");
			  gets(buf);
			  channel=atoi(buf);
			  tenspot:
			  printf("Modify Which Parameter > "); 
			  gets(buf);
			  parameter=atoi(buf);
			  printf("New Data > "); 
			  gets(buf);
			  patchn=atoi(buf);
			  if (address==10) channel = 0;
			  ModifyPatchData(channel,address,parameter,patchn);
			  break;  
		case 'R': printf("Which Reverb Mode? (0-3) > ");
			  gets(buf);
			  patchn=atoi(buf);
			  ModifyPatchData (0,10,1,patchn);
			  printf("Which Reverb Time? (0-7) > ");
			  gets(buf);
			  patchn=atoi(buf);
			  ModifyPatchData (0,10,2,patchn);
			  printf("Which Reverb Level? (0-7) > ");
			  gets(buf);
			  patchn=atoi(buf);
			  ModifyPatchData (0,10,3,patchn);
			  break;  	
		case 'N': printf("Which Channel? (1-8) > ");
	  		  gets(buf);
	  		  address=atoi(buf);
	  		  printf("New Name > ");
	  		  gets(buf);
	  		  for(i=0;i<10;i++)
	  		      ModifyPatchData(address,8,i,toascii(buf[i]));
	  		  SendPatchData(address,2,address-1);
	  		  break;
		case 'E': Cleanup ("", 0);
		}
	}
}

/* Receive tone data from the MT-32 */

ReceiveToneData (address,tonedata,timbre)
UBYTE timbre;
{
UBYTE checksum=0;
int addSB,addLSB;

/* Send Request 1 system exclusive data */
UBYTE sendrequest[13];
static UBYTE sendarray[5] = {0xF0,0x41,0x10,0x16,0x11};
UBYTE data[512];
UBYTE *ptr;

int i;
for (i=0;i<5;i++) sendrequest[i]=sendarray[i];
if (address==4) i = 0;
else if (address==8) i = timbre * 0x200;
addSB=(i>>8);addLSB=((i<<4)>>4);
sendrequest[5]=address;
sendrequest[6]=addSB;sendrequest[7]=addLSB;
sendrequest[8]=0;
if (address==4) {sendrequest[9]=1;  sendrequest[10]=0x76;}
else if (address==8) {sendrequest[9]=2;  sendrequest[10]=0x00;}
for (i=5;i<11;i++)  {
	checksum += sendrequest[i];
		    }  
   checksum=checksum%256;
   if (checksum<=128)checksum=128-checksum;	
   else if (checksum<256) checksum=256-checksum;
sendrequest[11]=checksum;
sendrequest[12]=0xF7;
	
/* Clear the serial buffer of any unread data */

IORser->IOSer.io_Command = CMD_CLEAR;
DoIO (IORser);

/* Send request to MT-32 */

IORser->IOSer.io_Data = (APTR) &sendrequest;
IORser->IOSer.io_Length = sizeof(sendrequest);
IORser->IOSer.io_Command = CMD_WRITE;

DoIO(IORser);

/* Read tone data and "end-system-exclusive" from MT-32 */

IORser->IOSer.io_Data = (APTR) &data;
if (address==4) IORser->IOSer.io_Length = 254;
if (address==8) IORser->IOSer.io_Length = 265;
IORser->IOSer.io_Command = CMD_READ;

DoIO (IORser);
	
/* Build a Tone Data  from the 8 bit values returned from the MT-32 */

ptr = (UBYTE *) tonedata;
for (i=8; i<254; i++)  {
    *(ptr++) = (data[i]);
    }
printf("Timbre name is ");
for (i=8; i<18;i++) {
    printf("%c",data[i]);
    }
    printf("\n");
}
	/* Send tone data to the MT-32 */

SendToneData (filedata,timbre)
UBYTE timbre,*filedata[];

{
/* Receive request 1 system exclusive */

static UBYTE receivearray [] = {0xF0,0x41,0x10,0x16,0x12};
UBYTE receive_request[265];    

UBYTE checksum=0;
UBYTE *ptr;

int i,addSB,addLSB;

/* Clear the serial buffer of any unread data */

IORser->IOSer.io_Command = CMD_CLEAR;
DoIO (IORser);

for (i=0;i<5;i++) receive_request[i]=receivearray[i];
i = timbre * 0x0200; 
addSB=(i>>8);    addLSB=((i<<4)>>4);
receive_request[5]=8;receive_request[6]=addSB;receive_request[7]=addLSB;
ptr = (UBYTE *) filedata;

for (i=8; i<254; i++)
	{
	receive_request[i] = *ptr;
	checksum += receive_request[i];
	ptr++;
	}
for (i=5;i<8;i++)  {
	checksum += receive_request[i];
		    }
   checksum=checksum%256;
   if (checksum<=128) checksum=128-checksum;	
   else if (checksum<256) checksum=256-checksum;
   
/* Add "end-system-exclusive" to tone data buffer */

receive_request[254] = checksum;
receive_request[255]= END_SYSTEM_EXCLUSIVE;

/* Send tone data to MT-32 */

IORser->IOSer.io_Data = (APTR) &receive_request;
IORser->IOSer.io_Length = 256;
IORser->IOSer.io_Command = CMD_WRITE;

DoIO (IORser);

}

/* Write tone data to file */

void WriteToneData (tonedata,filename)
char *filename;
{
FILE *fileptr;

/* Loop until success */

do      {

	/* Create the file */

	fileptr = fopen (filename, "w");
        }
while (fileptr == NULL);

/* Write tone data to file */
fwrite (tonedata, 254, 1, fileptr);

fclose (fileptr);

}

/* Read tone data from file */

LONG ReadToneData (filedata)
UBYTE *filedata[];
{
FILE *fileptr;

char buf[80];

/* Loop until success */

do	{
	/* Prompt for a filename */

	printf ("Input filename (RETURN to cancel) > ");
	gets(&buf);

	if (buf[0] == 0) return (FALSE);

	/* Open the file */

	fileptr = fopen (&buf, "r");
	}
while (fileptr == NULL);

/* Read tone data from file */

fread (filedata, 246, 1, fileptr);

fclose (fileptr);

/* Return success */

return (TRUE);
}

/* Set serial device parameters */

SetParams (io)
struct IOExtSer *io;
{

/* Set serial port for MIDI communications */

io->io_SerFlags = SERF_RAD_BOOGIE;
io->io_Baud = 31250;
io->IOSer.io_Command = SDCMD_SETPARAMS;

return(DoIO(io));
}

/* Cleanup and exit routine */

Cleanup (str, n)
char *str;
int n;
{

if (strlen(str) != 0) printf ("%s", str);
if (n != 0) printf (", error = %ld", n);
if (strlen(str) != 0) printf ("\n"); 

/* Release all resources */

if (resources & SERIAL_DEVICE) {
	/* Reset the serial device and then close it */
	IORser->IOSer.io_Command = CMD_RESET;
	DoIO (IORser);
	CloseDevice (IORser); }
if (resources & SERIAL_EXTIO)
	DeleteExtIO(IORser, sizeof(struct IOExtSer));
if (resources & SERIAL_PORT) DeletePort (serialport);

exit(n);

}

	
SendPatchData (channel,patchg,patchn)
UBYTE channel,patchg,patchn;
{
UBYTE checksum=0;

/* Send Request 1 system exclusive data */
UBYTE sendrequest[12];
static UBYTE sendarray[5] = {0xF0,0x41,0x10,0x16,0x12};

int i;
for (i=0;i<5;i++) sendrequest[i]=sendarray[i];
i = (channel-1) * 0x010;
sendrequest[5]=3;sendrequest[6]=0;sendrequest[7]=i;
sendrequest[8]=patchg;sendrequest[9]=patchn;
for (i=5;i<10;i++)  {
	checksum += sendrequest[i];
		    }  
   checksum = checksum%256;
   if (checksum<=128) checksum = 128-checksum;	
   else if (checksum<256) checksum = 256-checksum;
sendrequest[10]=checksum;
sendrequest[11]=0xF7;
	
/* Clear the serial buffer of any unread data */

IORser->IOSer.io_Command = CMD_CLEAR;
DoIO (IORser);

/* Send request to MT-32 */

IORser->IOSer.io_Data = (APTR) &sendrequest;
IORser->IOSer.io_Length = sizeof(sendrequest);
IORser->IOSer.io_Command = CMD_WRITE;

DoIO(IORser);
	
}


ModifyPatchData (channel,address,parameter,patchn)
UBYTE channel,address,parameter,patchn;
{
UBYTE addSB,addLSB,checksum=0;

/* Send Request 1 system exclusive data */
UBYTE sendrequest[11];
static UBYTE sendarray[5] = {0xF0,0x41,0x10,0x16,0x12};

int i;
for (i=0;i<5;i++) sendrequest[i]=sendarray[i];
sendrequest[5]=address;
if (address==3) {
	i = (channel-1) * 0x10 + parameter; 
	}
if (address==5) {
	i = (channel-1) * 0x08 + parameter; 
	}
if (address==8)	i = (channel-1) * 0x0200 + parameter;
if (address==10) goto ten;

addSB=(i>>8);addLSB=((i<<4)>>4);
sendrequest[6]=addSB;sendrequest[7]=addLSB;
	
	ten:
		if (address==10) {
			sendrequest[5]=0x10;
			sendrequest[6]=0;
			sendrequest[7]=parameter;
		}
		
sendrequest[8]=patchn;
for (i=5;i<9;i++)  {
	checksum += sendrequest[i];
		    }  
   checksum = checksum%256;
   if (checksum<=128) checksum = 128-checksum;	
   else if (checksum<256) checksum = 256-checksum;
sendrequest[9]=checksum;
sendrequest[10]=0xF7;

/* Clear the serial buffer of any unread data */

IORser->IOSer.io_Command = CMD_CLEAR;
DoIO (IORser);

/* Send request to MT-32 */

IORser->IOSer.io_Data = (APTR) &sendrequest;
IORser->IOSer.io_Length = sizeof(sendrequest);
IORser->IOSer.io_Command = CMD_WRITE;

DoIO(IORser);
	
}

PrintToneData(filedata)
UBYTE *filedata[];
{
FILE *pfp;
UBYTE *ptr;
int i,data,y;

ptr = (UBYTE *) tonedata;	

pfp = fopen("PRT:", "w");
if (pfp==NULL)
	{
	Cleanup("Cannot open Printer Stream",100);
	}
for (i=0; i<10;i++) {
    fprintf(pfp,"%c",tonedata[i]);
    }
fprintf(pfp,"\n");	


for (i=10;i<14;i++) {    
	y=*(ptr+i);
 	fprintf(pfp,"%s  = %d \n",commonarray[i-10],y);
  }  

for (i=0;i<58;i++) {
    fprintf(pfp,"%s ",tonearray[i]);
    for (data=0;data<4;data++){
      y=*(ptr+(data*58+i+14));
      fprintf(pfp,"    %.3d ",y);
     }
     fprintf(pfp,"\n");
  }   
fprintf(pfp,"\n");
fclose(pfp);    
}  



QuantifyToneData(tonedata,cort,data)
int cort,data;
{
int i,y;
UBYTE *ptr;

ptr = (UBYTE *) tonedata;		
if (cort) {
    y=*(ptr+data);
    printf("%s  = %d \n",commonarray[data-10],y);
    }
else  {
    printf("%s ",tonearray[data]);
    for (i=0;i<4;i++){
      y=*(ptr+(i*58+data+14));
      printf("    %.3d ",y);
     }
    printf("\n");
    }
  }  
