/*
  VORTEX !!!!!!!1

This program is a translation of a BASIC program that
translates Yamaha setups into typhoon setups.

  Original BASIC version - Dan Schaaf  (16w2typh.bas)
  C port                 - Mark Lakata

Compiling (ANSI C):
  UNIX:    gcc vortex.c -o vortex

Help:  see help() at end of this file, or
 compile and run the program with vortex -h.

You will want to define the default input and output disks.  These can also
be directories or whatever. You can change them with command line options. 
If you have a directory, be sure to append the appropriate directory
separator (\,/,[], etc).

Examples:   IBM ->"A:\\"        UNIX -> "./"    Amiga -> "PC0:"   
            VAX ->"[.YAM]"     Atari -> I dunno
" */
#define YAMAHA_DISK  "./"
#define TYPHOON_DISK "./"
#define TYPHLABELNAME "        "
/* ____________________________________________________________  */

/* system dependent stuff here. If you don't want to deal with the
directory stuff, which is probably messy, then uncomment the following
line out: */
/* #define NODIRECTORYSTUFF */

/* other systems might need these include files if dirent.h causes problems */
/* #include <sys/dir.h> */
/* #include <sys/dirent.h> */

#ifdef AMIGA
#include <libraries/dos.h>
#include <exec/memory.h>
#else
#include <dirent.h>
#endif

#define VORTEXVERSION "0.93 Beta"
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#define OFFSET_BEGINNING_ 0
#define OFFSET_CURRENT_ 1
#define MODE_OLDFILE_ "rb"
#define MODE_NEWFILE_ "wb"

#define MIDI(k) ((12*((k)& 0xF0))/0x10 + (3*((k) & 0x0C))/4 + ((k)& 0x03)-11)

char Key[12][3] = {
 " C","C#"," D","Eb"," E"," F","F#"," G","G#"," A","Bb"," B"};

/* Yamaha Structures ----------------------------------------*/
struct YHeader_ {
  char
   MagicString[7], Version[4], Pad[5];
} YHeader;
#define YHEADERSIZE 16 

struct YWave_ {
  char Name[8],SizeInfo[8];
} YWave[64];
#define YWAVESIZE 16

struct YTimbre_ {
  unsigned char
    WaveNumber,
    OriginalPitch,
    FilterNumber,
    PitchbendRange,  PitchbendStep,
    LFOSpeed,  LFOPMD,  LFOAMD,
    Reserved,
     Tune[3],
    AEGD1L, AEGD2L, AEGAR, AEGD1R, AEGD2R, AEGRR,
    PEGR1, PEGR2, PEGR3, PEGR4, PEGL1, PEGL2, PEGL3, PEGL4,
    VCVolume, VCSwitch, VCBreakPoint1, VCLevel1, VCDepth1,
                        VCBreakPoint2, VCLevel2, VCDepth2,
    AmpModWheel, AmpModFoot, AmpModAfterTouch, AmpModBreath,
    PitchModWheel, PitchModFoot, PitchModAfterTouch, PitchModBreath,
    VelModWheel, VelModFoot, VelModAfterTouch, VelModBreath;
  char
    Name[10];
} *YTimbre;
#define YTIMBRESIZE 0x38

struct YVoice_ {
  struct {
    unsigned char  Number, LowKey, HiKey, Fade;
  } Timbre[0x20];
  unsigned char
    Reserved[0x06];
  char
    Name[0x0A];
  unsigned char 
    EditSlot, Pad;
} YVoice[0x20];
#define YVOICESIZE 0x92

struct YPerf_ {
  unsigned char
    AlternativeAssign[2],
    MIDIReceive[16], Voice[16], Group[16], Output[16], Volume[16];
  signed char
    Detune[16], NoteShift[16];
  unsigned char
    LFOSpeed, LFODelay, LFOWave, LFOSync, LFOAMD, LFOPMD;
  char Name[20];
  unsigned char
    IndOutput, Reserved,
    ExtTriggerMIDIChannel, ExtTriggerKey, ExtTriggerLevel, ExtTriggerGate;
} YPerf[32];
#define YPERFSIZE 0x92

struct YSetup_ {
  unsigned char
    MasterTune[2], MasterVolI, MasterVolII,
    ControlTable[90],
    ProgramChange[4][32],
    ProgramChangeSwitch, DeviceNumber, Reserved[2],
    MIDIChProgramChange, MIDIChControlChange,
    MIDIChAfterTouch, MIDIChPitchbend, MIDIChNoteOnOff;
} YSetup;
#define YSETUPSIZE1 226
#define YSETUPSIZE2 5

/* Typhoon Structures ---------------------------------------- */

struct TFORM_ {
  char Name[4];
  unsigned long BankLength;
  char TypeName[3], Type;
} VoiceFORM, PerfFORM, SetupFORM;
#define FORMSIZE 12

struct TVInf_ {
  char Name[4];
  unsigned long BankLength;
  unsigned char Data[12];
  unsigned long Version;
} VoiceVInf, PerfVInf, SetupVInf;
#define VINFSIZE 24

struct TGrop_ {
  char Name[4];
  unsigned long BankLength;
} VoiceGrop;
#define GROPSIZE 8


struct TVParm_ {
  char Name[4];
  unsigned long BankLength;
  unsigned char 
    BottomKey, TopKey, MinVelocity, MaxVelocity; /* midi note value, vel=0:127 */
  signed char NoteShift, CentShift; /* CentShift:-2B to 2B == -50 to 50 */
  unsigned char KeyScaling, /* KeyScaling 3=normal */
    Volume, PreVolume, MaxVolume, /* PreVolume=%, MaxVolume=0:127 */
    FilterNumber, DynAxis, DynLevel, FixedLevel, /* FilterNumber=FF off */
    Mode, Poly, GlideMSB, GlideLSB,  /* guide units of 10ms, max 3D0 */
         /* mode:FE=normal,FF=oneshot,00=glide,01=release */
         /* Poly:1=on,0=off */
    Output;         /* Output:0=none,1=left,2=right,3=mono,4=stereo */
  signed char Pan;  /* -3F to 3F */
  unsigned char IndOutFrom, IndOutTo;
  struct {
    unsigned char L1, L2, AR, D1, D2, RR;
  } AEG;
  struct {
    unsigned char 
      Shape, LFOAmplitude, Sync, Position, RateMSB, RateLSB;
  } LFO1,LFO2;
  struct {
    signed char
      L0,    L1,    L2,    L3;
    unsigned char
      T11,  T12,   T21,   T22,
      T31,  T32,   Amplitude, dummy;
  } Env1,Env2;
} TVoiceParm;
#define PARMSIZE 72

struct TMod_ {
  char Name[4];
  unsigned long BankLength;
  unsigned char
    source, dest, p1, p2, sm, cent;
} VoiceMod;
#define MODSIZE 14

struct TSplt_ {
  char Name[4];
  unsigned long BankLength;
} VoiceSplt;
#define SPLTSIZE 8

struct TSpltParm_ {
  char Name[4];
  unsigned long BankLength;
  unsigned char
    lowkey,
    random;
} VoiceSpltParm;
#define SIZESPLTPARM 10
  
struct TWave_ {
  char Name[4];
  unsigned long BankLength;
  char wavename[8];
  unsigned long Version;
  char DiskLabel[8];
} VoiceWave;
#define WAVESIZE 28

struct TPParm1_ {
  char Name[4];
  unsigned long BankLength;
  unsigned long magiccookie;
} PerfParm1;
#define PARM1SIZE 12

struct TEntr_ {
  char Name[4];
  unsigned long BankLength;
} PerfEntr;
#define ENTRSIZE 8

struct TPParm2_ {
  char Name[4];
  unsigned long BankLength;
  unsigned char
    MIDIReceive, Volume,
    LowKey, HiKey;
  signed char
    NoteShift, detune;
  unsigned char
    out, from, to,
    junk,
    priority,
    crap;
} PerfParm2;
#define PARM2SIZE 20

struct TVoic_ {
  char Name[4];
  unsigned long BankLength;
  char voicename[8];
  unsigned long VoiceVersion;
  char DiskLabel[8];
} PerfVoic;
#define VOICSIZE 28

struct TPerf_ {
  char Name[4];
  unsigned long BankLength;
  char perfname[8];
  unsigned long PerfVersion;
  char DiskLabel[8];
} SetupPerf;
#define PERFSIZE 28

struct TSParm_ {
  char Name[4];
  unsigned long BankLength;
  unsigned char Data[0x38]; 
/*  unsigned char
    LeftVolume, RightVolume, TuneMSB,TuneLSB,
    Dev, XCtl1, XCtl2, ??, SliderCntl, Shitskers,
    RemoteChannel,MinusOne,PlusOne,L,R,Ent,Alpha,
    RS422Mode, RS422Rate; 
  char SetupName[8],crap */
} SetupParm;
#define SPARMSIZE 0x40

unsigned char VInfDATA[12] = {
    0xA9, 0x23, 0xFD, 0x3A, 0xA8, 0xC6, 0xD1 ,0x86, 
    0x07, 0x3F, 0xFD, 0xC0 };

unsigned char SETUPDATA[0x38] = {
     0xFF, 0xFF, 0x00, 0x00,     
        0,    2,    4, 0x06, 0xFF, 0xFF, 0xFF, 0xFF,
     0xFF, 0xFF, 0xFF, 0xFF, 0xFF,    0,    0,    0,
	0,    0,    0,    0,    0, 0x4E, 0x4F, 0x4E,
     0x41, 0x4d, 0x45,    0,    0,    0,    1,    1,
	1,    0,    2,    1, 0x3D, 0x69,    0,    0,
     0x44, 0x55, 0x4D, 0x50,    0,    0,    0,    0,
        0,    0,    0, 0xFF
      };


/* 
 alternative for above data for remote keys,
 etc.; replace first two lines

        0,    2,    4, 0x7d, 0x0f, 0x0f, 0x76, 0x7e
     0x79, 0x7b, 0x7f,    0, 0xff,    0,    0,    0
*/


char
  YamahaDisk[80],TyphoonDisk[80],SetupFileName[80],Y_SetupFileName[80],
  TyphLabelName[9];
int
  Verbose,NumTimbres[32],GoodTimbres[32],
  TotalTimbres,AEG[6],Version,GoodPerfs;


void help(void);
void SetupBanks(void);
unsigned long TyphoonLong(unsigned long );
int GetYamahaSetup(void);
int GetYamahaInfo(void);
int ConvertVoices(void);
int PrepareDOSName(char *,char *);
int WriteTyphoonVoice(int);
int WriteTyphoonSetup(void);
int WriteTyphoonPerfs(void);



int main(int argc,char *argv[]) {
  int i;

  strcpy(YamahaDisk,YAMAHA_DISK);
  strcpy(TyphoonDisk,TYPHOON_DISK);
  strcpy(TyphLabelName,TYPHLABELNAME);

  for (i=1;i<argc;i++) {
    if (argv[i][0] == '-') 
      switch (argv[i][1]) {
      case 'h':
	help();
        return(0);
	break;

      case 'v':
	printf("verbose mode on\n");
	Verbose = 1;
	break;
	
      case 'y':
	strcpy(YamahaDisk,&argv[i][2]);
	break;

      case 't':
	strcpy(TyphoonDisk,&argv[i][2]);
	break;

      case 'l':
	strcpy(TyphLabelName,&argv[i][2]);
	break;

      default: 
	printf("bad argument %s\n\n",argv[i]);
	help();
	return 1;
      }
    else {
      printf("bad argument %s\n\n",argv[i]);
      help();
      return 1;
    }
  }

  printf("Vortex! TX16W Yamaha -> Typhoon conversion program. Version %s\n\n",
	 VORTEXVERSION);

  SetupBanks();

  if(GetYamahaSetup()) {
    printf("error in GetYamahaSetup\n");
    return 1;
  }

  if(GetYamahaInfo()) {
    printf("error in GetYamahaInfo\n");
    return 1;
  }

  if (WriteTyphoonVoices()) {
    printf("error in WriteTyphoonVoices\n");
    return 1;
  }

  if (WriteTyphoonPerfs()) {
    printf("error in WriteTyphoonPerfs\n");
    return 1;
  }

  if (WriteTyphoonSetup()) {
    printf("error in WriteTyphoonSetup\n");
    return 1;
  }

  free(YTimbre);

  printf("Successful completion.\n");

  return 0;
}



int GetYamahaSetup(void)
{
#ifndef NODIRECTORYSTUFF
#ifndef AMIGA
  DIR *YamahaDir;
  struct dirent *DirEntry;
  char *tmpname;

  if ((YamahaDir = opendir(YamahaDisk))==NULL) {
    printf("Error opening yamaha disk as %s.(%d)\n",YamahaDisk,errno);
    return 1;
  }
  
  while ( (DirEntry = readdir(YamahaDir)) != NULL) {
    tmpname= DirEntry->d_name;
    if(!strcasecmp(&tmpname[DirEntry->d_namlen-4],".s01")) {
      closedir(YamahaDir);
      strncpy(Y_SetupFileName,YamahaDisk,80);
      strncat(Y_SetupFileName,tmpname,80);
      strncpy(SetupFileName,tmpname,80);
      return 0;
    }
  }
  printf("No Setup file *.S01 Found.\n");
  closedir(YamahaDir);
  
  return 1;
#else

  struct FileLock *lock;
  struct FileInfoBlock *fib_ptr;
  char *tmpname;
 
  /* Allocate enough memory for a FileInfoBlock structure: */
  fib_ptr = (struct FileInfoBlock *)
            AllocMem( sizeof( struct FileInfoBlock ),
                      MEMF_PUBLIC | MEMF_CLEAR );

  if( fib_ptr == NULL )  {
    printf("Not enough memory!\n");
    return 1;
  }
  
  lock = (struct FileLock *) Lock( YamahaDisk, SHARED_LOCK );
  if( lock == NULL )  {
    printf("Error opening(lock) yamaha disk as %s.(%d)\n",YamahaDisk,errno);
    FreeMem( fib_ptr, sizeof( struct FileInfoBlock ) );
    return 1;
  }

  if( Examine( lock, fib_ptr ) )  {
    if( fib_ptr->fib_DirEntryType > 0 )  {
      while( ExNext( lock, fib_ptr ) ) {
        if( fib_ptr->fib_DirEntryType < 0 ) {
          tmpname= fib_ptr->fib_FileName;
          if(!strcmp(&tmpname[strlen(tmpname)-4],".S01")) {
            strncpy(Y_SetupFileName,YamahaDisk,80);
            strncat(Y_SetupFileName,tmpname,80);
            strncpy(SetupFileName,tmpname,80);
            goto goodanswer;
          }

        }
      }
      if( IoErr() != ERROR_NO_MORE_ENTRIES ) {
        printf("ERROR WHILE READING!!!\n");
        goto badanswer;
      }
    }
    else {
      printf("%s is a file!\n", YamahaDisk);
      goto badanswer;
    }
  }
  else {
    printf("Could not examine %s!\n", YamahaDisk);
    goto badanswer;
  }

badanswer:
  UnLock( lock );  
  FreeMem( fib_ptr, sizeof( struct FileInfoBlock ) );
  printf("No Setup file *.S01 Found.\n");
  return 1;

goodanswer:
  UnLock( lock );  
  FreeMem( fib_ptr, sizeof( struct FileInfoBlock ) );
  return 0;

#endif   
#else
  char tmpname[80];

  printf("Enter name of setup file that is in %s :",YamahaDisk);
  scanf("%s",tmpname);  
  if(!strcasecmp(&tmpname[strlen(tmpname)-4],".S01")) {
    strncpy(Y_SetupFileName,YamahaDisk,80);
    strncat(Y_SetupFileName,tmpname,80);
    strncpy(SetupFileName,tmpname,80);
    return 0;
  }
  else {
    printf("Not a valid setup file name (needs .S01 extension)\n");
    return 1;
  }
#endif
}



int GetYamahaInfo(void)
{
  FILE *Y_SetupFile,*Y_VoiceFile,*Y_PerfFile;
  int i,k,l,found,bad,len,tim,PerfNum,v,w;
  char dummy[2],Y_VoiceFileName[80],Y_PerfFileName[80];

/* ------------------------------------------------------------*/  
/* Read Setup */
/* ------------------------------------------------------------*/  
  if((Y_SetupFile = (FILE *) fopen( Y_SetupFileName, MODE_OLDFILE_))
     == NULL ) {
    printf("Error fopening file: %s\n",Y_SetupFileName);
    return 1;
  }

  if ( fread((char *)&YHeader,1,YHEADERSIZE,Y_SetupFile)
      != YHEADERSIZE) {
    printf("Unable to read setup header\n");
    fclose(Y_SetupFile);
    return 1;
  }

  if (Verbose) {
    printf("Reading Yamaha Setup: %s, ",Y_SetupFileName);
    printf("Header: %s Version: %s ->",YHeader.MagicString,
	   YHeader.Version);
  }

  /* Find Version Number */
  if (YHeader.Version[1]=='2') {
    if (Verbose) printf("Version 2!!!!\n");
    Version = 2;
  }
  else {
    if (Verbose) printf("Version 1....\n");
    Version = 1;
  }

/* read rest of setup information */
  if ( fread((char *)&YSetup,1,YSETUPSIZE1,Y_SetupFile)
      != YSETUPSIZE1) {
    printf("Unable to read setup1\n");
    fclose(Y_SetupFile);
    return 1;
  }
/* necessary to skip 2 bytes for Version 2. stupid */
  if (Version == 2) fread(dummy,1,2,Y_SetupFile);
  if ( fread((char *)&YSetup.MIDIChProgramChange,1,YSETUPSIZE2,Y_SetupFile)
      != YSETUPSIZE2) {
    printf("Unable to read setup2\n");
    fclose(Y_SetupFile);
    return 1;
  }
/* ------------------------------------------------------------*/  
/* Read Wave Names (same file as setup) */
/* ------------------------------------------------------------*/  

  if ( fread((char *)&YWave,1,64*YWAVESIZE,Y_SetupFile)
      != 64*YWAVESIZE) {
    printf("Unable to read wavenames\n");
    fclose(Y_SetupFile);
    return 1;
  }
  fclose(Y_SetupFile);

  w=0;
  found=0;
  for(w=0;w<64;w++) {
    for(i=0; i<8 && YWave[w].SizeInfo[i]==0; i++);
    YWave[w].Name[8]=0; /* careful, this is writing into next record...*/
    if (i !=8 ) {       /* but the next 8 bytes are crap anyways */
      i=strlen(YWave[w].Name);
      while (i>0 && YWave[w].Name[i-1] == ' ') i--; 
      if (i>0) {
	YWave[w].Name[i] = '\0';
	if (Verbose) printf("\nWave[%2d]:'%s' ",w,YWave[w].Name);
        found++;
      }
      else
       if (Verbose) printf(",");
    }
    else { 
      YWave[w].Name[0] = '\0';
      if (Verbose) printf(".");
    }
  }

  if (Verbose) printf("\n%d waves found, out of %d scanned.\n\n",found,w);

/* ------------------------------------------------------------------*/
/* Read Voices */
/* ------------------------------------------------------------------*/

/* edit setupfile name by changing ".S" to ".V" */
  strcpy(Y_VoiceFileName,Y_SetupFileName);
  k=strlen(Y_VoiceFileName)-1;
  while(Y_VoiceFileName[k]!='.' && k>0) k--;
  Y_VoiceFileName[k+1] = 'V';

  if((Y_VoiceFile = (FILE *) fopen( Y_VoiceFileName, MODE_OLDFILE_ ))
     == NULL ) {
    printf("voice file %s not fopened correctly.\n",Y_VoiceFileName);
    return 1;
  }
  if (Verbose) printf("\nReading Voice File: %s, ",Y_VoiceFileName);

  if ( fread((char *)&YHeader,1,YHEADERSIZE,Y_VoiceFile) != YHEADERSIZE) {
    printf("Unable to read voice header\n");
    fclose(Y_VoiceFile);
    return 1;
  }

  if (Verbose)
    printf("Header: %s Version: %s\n",YHeader.MagicString,
	   YHeader.Version);

  for(v=0;v<32;v++) {
    if ((fread((char *) &YVoice[v],1,YVOICESIZE,Y_VoiceFile))
      != YVOICESIZE) {
      printf("Error reading voice %d\n",v);
      fclose(Y_VoiceFile);
      return 1;
    }
  }

/* clean up voice names, and look around */
  TotalTimbres = 0;
  for (v=0;v<32;v++) {
    NumTimbres[v]=0;
    YVoice[v].Name[10] = 0;
    len = strlen(YVoice[v].Name);
    bad = 0;
    for(l=0;l<len;l++) if ( YVoice[v].Name[l]<' ' || YVoice[v].Name[l]>'}') bad=1;
    if (!strcmp(YVoice[v].Name,"init voice") ||
	YVoice[v].Name[0] == ' ' ||
	bad ) {
      if (Verbose)printf(".");
      YVoice[v].Name[0]  = '\0';
    }
    else {
      l=len;
      while (l>0 && YVoice[v].Name[l-1] == ' ') l--; 
      YVoice[v].Name[l] = '\0';
      if (l>0) {
        for(l=0;l<32 && YVoice[v].Timbre[l].LowKey < 0x80; l++) {
          tim = YVoice[v].Timbre[l].Number;
          if (TotalTimbres < tim) TotalTimbres = tim;
        }
        NumTimbres[v] = l;
      }
    }

  }

  TotalTimbres++;
  if (Verbose) printf("\nNo More than %d Timbres Total\n\n",TotalTimbres);

/* ------------------------------------------------------------*/
/* read all the timbres */
/* ------------------------------------------------------------*/

  YTimbre = ( struct YTimbre_ *) malloc(TotalTimbres * YTIMBRESIZE);
  if(fread((char *)YTimbre,1,TotalTimbres*YTIMBRESIZE,Y_VoiceFile) !=
           YTIMBRESIZE* TotalTimbres) {
    printf("Error freading timbres.\n");
    return 1;
  }

  fclose(Y_VoiceFile);
  
  for(v=0;v<32;v++) {
    GoodTimbres[v]=0;
    if(YVoice[v].Name[0]) {
      if (Verbose) printf("\nVoice[%2d] = '%s' Timbres: ",v,YVoice[v].Name);
      for(l=0;l<NumTimbres[v]; l++) {
        tim = YVoice[v].Timbre[l].Number;
        if (YWave[YTimbre[tim].WaveNumber].Name[0] != 0) {
          if (Verbose) printf("%d ",tim);
            GoodTimbres[v]++;
          }
        else {
          if (Verbose) printf("Empty(%d) ",tim);
        }
      }
      if (Verbose) printf(" = %d timbres of %d. ",GoodTimbres[v],
              NumTimbres[v]);
    }
  }

/* ------------------------------------------------------------*/
/* read performances */
/* ------------------------------------------------------------*/

/* edit setupfile name by changing ".S" to ".U" */
  strcpy(Y_PerfFileName,Y_SetupFileName);
  i=strlen(Y_PerfFileName);
  k=i-1;
  while(Y_PerfFileName[k]!='.' && k>0) k--;
  Y_PerfFileName[k+1] = 'U';

  if((Y_PerfFile = (FILE *) fopen( Y_PerfFileName, MODE_OLDFILE_ ))
     == NULL ) {
    printf("Error fopening file: %s\n",Y_PerfFileName);
    return 1;
  }
  if (Verbose) printf("\nReading Performance File: %s, ",Y_PerfFileName);

  if ( fread((char *)&YHeader,1,YHEADERSIZE,Y_PerfFile) != YHEADERSIZE) {
    printf("Unable to read performance header\n");
    fclose(Y_PerfFile);
    return 1;
  }

  if (Verbose)
    printf("Header: %s Version: %s\n",YHeader.MagicString,
	   YHeader.Version);

  for(PerfNum=0;PerfNum<32;PerfNum++) {
    if(fread((char *)&YPerf[PerfNum],1,YPERFSIZE,Y_PerfFile) != 
       YPERFSIZE) {
      printf("Error reading yamaha perf %d\n",PerfNum);
      return 1;
    }
  }

  fclose(Y_PerfFile);

  GoodPerfs = 0;
  for(PerfNum=0;PerfNum<32;PerfNum++) {
    YPerf[PerfNum].Name[20]=0;
    for(i=strlen(YPerf[PerfNum].Name);i>0 && 
      YPerf[PerfNum].Name[i-1] ==' ';i-- );
    YPerf[PerfNum].Name[i] = 0;
/* warning, got rid of strcasecmp */
    if (!strcmp(YPerf[PerfNum].Name,"init perf") ||
        !strcmp(YPerf[PerfNum].Name,"init performance") ||
                YPerf[PerfNum].Name[0] == 0) {
      YPerf[PerfNum].Name[0] = 0;
      if (Verbose) printf(".");
      }
    else {
      if (Verbose) printf("\nPerf[%d]='%s'",PerfNum,YPerf[PerfNum].Name);
      GoodPerfs++;
    }
  }

  if (Verbose) {
     printf("\nFound %d good performance(s).\n\n",GoodPerfs);
     printf("  ***         --- Done Reading Input ---\n\n");
  }
  
  return 0;
}



int WriteTyphoonVoices(void)
{
  int v;

  for(v=0;v<32;v++) {
    if (YVoice[v].Name[0] != 0) {
      if(WriteTyphoonVoice(v)) {
	printf("Problem in WriteTyphoonVoice\n");
	return 1;
      }
    }
  }

  if (Verbose) printf(" ***  ---Done writing voices--- \n\n");
  return 0;
}

int PrepareDOSName(char *in,char *out)
{
  char badchars[6]="|/\\. ",vowels[7]="AEIOU-";
  int i,j,len,outlen;

  j=0;
  len = strlen(in);
  outlen=0;
/* first clean out bad characters */
  for(i=0;i<len;i++)
    if (strchr(badchars,in[i]) == NULL)
      out[outlen++]=toupper(in[i]);
  out[outlen]=0;
  if (Verbose) printf(" -[Strip %s]-> '%s'",badchars,out);

/* remove vowels (strip all vowels after the first letter) */
  j=0;
  for(i=outlen-1;i >=1 && outlen > 8; i--) {
    if (strchr(vowels,out[i]) != NULL) {
      for(j=i+1;j<=outlen;j++)
	out[j-1]=out[j];
      outlen--;
    if (Verbose) printf(" -[Strip %s]-> %s ",vowels,out);
    }
  }
/* if it still too long, just lop it off */
  if (outlen>8) {
    out[8] = 0;
    outlen = 8;
    if (Verbose) printf("-[Lop]-> %s\n",out);
  }
  
  return outlen;
}


    
int WriteTyphoonVoice(int v)
{
  int i,j,l,tim,tim0,len,lo,hi,minlo,maxhi,WaveNum,pitchbend,AEG[6],FirstSplit;
  long tmp;
  /* int volume; */
  char TyphoonVoiceFileName[80],TempVoiceName[11];
  FILE *TyphoonVoiceFile;


  if (Verbose) printf("Voice[%2d]= %s ",v,YVoice[v].Name);
  len = PrepareDOSName(YVoice[v].Name,TempVoiceName);
  if (len<8) len++;
  for (j=0;j<v;j++) {
/* check that it isn't used before, and increment the last character if so */
    if (!strncmp(YVoice[j].Name,TempVoiceName,8)) {
      if (Verbose) 
	    printf("-[Clash with #%d '%s']-> ",j,YVoice[j].Name);
      if (TempVoiceName[len-1] <'0' || TempVoiceName[len-1] >'9')
	    TempVoiceName[len-1] ='0';
      else
	    TempVoiceName[len-1]++;
      if (Verbose) printf("'%s' ",TempVoiceName);
    }
  }
  strcpy(YVoice[v].Name,TempVoiceName);
      
  strcpy(TyphoonVoiceFileName,TyphoonDisk);
  strcat(TyphoonVoiceFileName,YVoice[v].Name);
  strcat(TyphoonVoiceFileName,".O01");  /* be careful, thats "Oh" "Zero" */
  TyphoonVoiceFile = (FILE *) fopen(TyphoonVoiceFileName,MODE_NEWFILE_);
  if (TyphoonVoiceFile == NULL) {
    printf("Could not write the typhoon voice file.\n");
    fclose(TyphoonVoiceFile);
    return 1;
  }
  if (Verbose) printf("\nWriting Typhoon Voice File: %s\n",
     TyphoonVoiceFileName);

/* write Voice Header */
  VoiceFORM.Type = 'V';
  VoiceFORM.BankLength =
    TyphoonLong((long)(4 + VINFSIZE + GROPSIZE + PARMSIZE + MODSIZE * 8 +
		GoodTimbres[v] * ( SPLTSIZE + WAVESIZE ) +
		(GoodTimbres[v] - 1 ) * SIZESPLTPARM ));
/* goto cont; */

  if(fwrite((char *)&VoiceFORM,1,FORMSIZE,TyphoonVoiceFile) != FORMSIZE) {
    printf("Error writing first record\n");
    return 1;
  }

/* zero averages -- this should probably be in groups */
  pitchbend                = 0;
/*  volume                   = 0; */
  for (j=0;j<6;j++) AEG[j] = 0;

  for (i=0;i<NumTimbres[v];i++) {
    tim = YVoice[v].Timbre[i].Number;
/* skip timbres with no wave */
    if (YWave[YTimbre[tim].WaveNumber].Name[0] == 0) continue;

    pitchbend  += YTimbre[tim].PitchbendRange;
/*    volume     += YTimbre[tim].Volume; */
    for (j=0;j<6;j++)
        AEG[j] += (&(YTimbre[tim].AEGD1L))[j];
    if (Verbose) {
      printf("tim %2d: Pitchbend %2d, AEG = %2d %2d %2d %2d %2d %2d\n",
	   tim,
           YTimbre[tim].PitchbendRange,
           (&(YTimbre[tim].AEGD1L))[0],
           (&(YTimbre[tim].AEGD1L))[1],
           (&(YTimbre[tim].AEGD1L))[2],
           (&(YTimbre[tim].AEGD1L))[3],
           (&(YTimbre[tim].AEGD1L))[4],
           (&(YTimbre[tim].AEGD1L))[5] );
    }
  }
  pitchbend                /= GoodTimbres[v];
/*  volume                   /= GoodTimbres[v]; */
  for (j=0;j<6;j++) AEG[j] /= (unsigned char)GoodTimbres[v];
 
  if (Verbose) printf("Decision: 1 Group with Many Splits\n");     


/* write General Voice Info */
  fwrite((char *)&VoiceVInf,1,VINFSIZE,TyphoonVoiceFile);

/* write Group */
  VoiceGrop.BankLength = 
    TyphoonLong(PARMSIZE + MODSIZE*8 +
		GoodTimbres[v]*(SPLTSIZE+WAVESIZE)+
		(GoodTimbres[v]-1)*SIZESPLTPARM);
  fwrite((char *)&VoiceGrop,1,GROPSIZE,TyphoonVoiceFile);

/* find min/max keys */
  minlo = 0xFF;
  maxhi = 0x00;
  for (l=0; l < NumTimbres[v]; l++) {

/* Yamaha OS encodes key likes this:
bits:AAAABBCC,  Midi Note = 12*(AAAA)+3*(BB)+(CC)-11
Was that LSD or 'shrooms? */

    lo = YVoice[v].Timbre[l].LowKey =
         MIDI(YVoice[v].Timbre[l].LowKey);
    hi = YVoice[v].Timbre[l].HiKey =
         MIDI(YVoice[v].Timbre[l].HiKey);
    if(lo<minlo) minlo= lo;
    if(hi>maxhi) maxhi= hi;
  }

  if (Verbose) printf("MIDI Key Range [%d,%d]\n",minlo,maxhi);

  tim0 = YVoice[v].Timbre[0].Number;

  TVoiceParm.BottomKey  = minlo;
  TVoiceParm.TopKey     = maxhi;
  TVoiceParm.MinVelocity= 0;
  TVoiceParm.MaxVelocity= 0x7F; 
  TVoiceParm.NoteShift  = 0;
  TVoiceParm.CentShift  = 0;
/*  TVoiceParm.CentShift  = YTimbre[tim0].Tune[0]; */
  TVoiceParm.KeyScaling = 0x03;  /* normal scaling */
  TVoiceParm.Volume     = 0;     /* this is actually maximum ! */
  TVoiceParm.PreVolume  = 0x19;  /* velocity curve slope 20% */
  TVoiceParm.MaxVolume  = 0x70;  /* a bit lower than 7F */
  TVoiceParm.FilterNumber= 0xFF;  /* no filter */
  TVoiceParm.DynAxis    = 0;
  TVoiceParm.DynLevel   = 0x32;  /* ??? */
  TVoiceParm.FixedLevel = 0x05;  /* ??? */
  TVoiceParm.Mode       = 0xFE;  /* normal mode */
  TVoiceParm.Poly       = 0x01;  /* on */
  TVoiceParm.GlideMSB   = 0;
  TVoiceParm.GlideLSB   = 0;
  TVoiceParm.Output     = 0x03;  /* mono Output */
  TVoiceParm.Pan        = 0;
  TVoiceParm.IndOutFrom = 0;
  TVoiceParm.IndOutTo   = 0x07;

/* this is really wacko */
  TVoiceParm.AEG.L1 = (unsigned char) (((99L-AEG[0]) * 0x3FL) / 99L);
  TVoiceParm.AEG.L2 = (unsigned char) (((99L-AEG[1]) * 0x3FL) / 99L);
  TVoiceParm.AEG.AR = (unsigned char) (((    AEG[2]) * 0x7FL) / 99L);
  TVoiceParm.AEG.D1 = (unsigned char) (((    AEG[3]) * 0x7FL) / 99L);
  TVoiceParm.AEG.D2 = (unsigned char) (((    AEG[4]) * 0x7FL) / 99L);
  TVoiceParm.AEG.RR = (unsigned char) (((    AEG[5]) * 0x7FL) / 99L);

  TVoiceParm.LFO1.Shape        = 0; /* triangle */
  TVoiceParm.LFO1.LFOAmplitude = 0x7F;  /* maximum */
  TVoiceParm.LFO1.Sync         = 0xFF;     /* no Sync */
  TVoiceParm.LFO1.Position     = 0;
  tmp  = ((YTimbre[tim0].LFOSpeed)*0x7FF)/8;
  TVoiceParm.LFO1.RateMSB      = (unsigned char) (tmp / 0x100);
  TVoiceParm.LFO1.RateLSB      = (unsigned char) (tmp & 0xFF);

  TVoiceParm.Env1.L0  = (signed char)((YTimbre[tim0].PEGL4-50L)*0x7f/50);
  TVoiceParm.Env1.L1  = (signed char)((YTimbre[tim0].PEGL1-50L)*0x7f/50);
  TVoiceParm.Env1.L2  = (signed char)((YTimbre[tim0].PEGL2-50L)*0x7f/50);
  TVoiceParm.Env1.L3  = (signed char)((YTimbre[tim0].PEGL3-50L)*0x7f/50);
  tmp = ((99-YTimbre[tim0].PEGR1)*0x4C3L)/99;
  TVoiceParm.Env1.T11 = (unsigned char) (tmp / 0x100);
  TVoiceParm.Env1.T12 = (unsigned char) (tmp & 0xFF);
  tmp = ((99-YTimbre[tim0].PEGR2)*0x4C3L)/99;
  TVoiceParm.Env1.T21 = (unsigned char) (tmp / 0x100);
  TVoiceParm.Env1.T22 = (unsigned char) (tmp & 0xFF);
  tmp = ((99-YTimbre[tim0].PEGR3)*0x4C3L)/99;
  TVoiceParm.Env1.T31 = (unsigned char) (tmp / 0x100);
  TVoiceParm.Env1.T32 = (unsigned char) (tmp & 0xFF);
  TVoiceParm.Env1.Amplitude = 0x7F;

  fwrite((char *)&TVoiceParm,1,PARMSIZE,TyphoonVoiceFile);

/* pitch bender 0*/
  VoiceMod.source = 0x05;  /* pitchbender number */
  VoiceMod.dest   = 0;
  VoiceMod.p1     = 0;
  VoiceMod.p2     = 0;
  VoiceMod.sm     = pitchbend;
  VoiceMod.cent   = 0;
  fwrite((char *)&VoiceMod,1,MODSIZE,TyphoonVoiceFile);

/* key -> AEG 1*/
  VoiceMod.source = 0x02;   /* key */
  VoiceMod.dest   = 0x05;   /* AEG/Time */
  VoiceMod.p1     = 0x01;
  VoiceMod.p2     = 0x0F;
  VoiceMod.sm     = 0xFF;
  VoiceMod.cent   = (0xFF - 26); 
  fwrite((char *)&VoiceMod,1,MODSIZE,TyphoonVoiceFile);

/* breath controller 2*/
  VoiceMod.source = 0x07;  /* Xctl1 */
  VoiceMod.dest   = 0x04;
  VoiceMod.p1     = 0x01;
  VoiceMod.p2     = 0x0F;
  VoiceMod.sm     = 0;
  VoiceMod.cent   = 0x60;
  fwrite((char *)&VoiceMod,1,MODSIZE,TyphoonVoiceFile);

/* PEG 3*/
  VoiceMod.source = 0x0D;  /* Env1 */
  VoiceMod.dest   = 0;     /* pitch */
  VoiceMod.p1     = 0;
  VoiceMod.p2     = 0xF;
  VoiceMod.sm     = 48;   /* four octaves */
  VoiceMod.cent   = 0;
  fwrite((char *)&VoiceMod,1,MODSIZE,TyphoonVoiceFile);

/* LFO-PMD 4*/
  VoiceMod.source = 0x0B;  /* Env1 */
  VoiceMod.dest   = 0;     /* pitch */
  VoiceMod.p1     = 0;
  VoiceMod.p2     = 0xF;
  VoiceMod.sm     = YTimbre[tim0].LFOPMD;
  VoiceMod.cent   = 0;
  fwrite((char *)&VoiceMod,1,MODSIZE,TyphoonVoiceFile);

/* LFO-AMD 5*/
  VoiceMod.source = 0x0B;  /* Env1 */
  VoiceMod.dest   = 1;     /* volume */
  VoiceMod.p1     = 0;
  VoiceMod.p2     = 0xF;
  VoiceMod.sm     = YTimbre[tim0].LFOAMD*100/3;
  VoiceMod.cent   = 0;
  fwrite((char *)&VoiceMod,1,MODSIZE,TyphoonVoiceFile);

/* "empty" modulation sources */
  for (i=6;i<8;i++) {
    VoiceMod.source = (unsigned char) i;
    VoiceMod.dest   = (unsigned char) i;
    VoiceMod.p1     = 0;
    VoiceMod.p2     = 0x0F;
    VoiceMod.sm     = 0;
    VoiceMod.cent   = 0;
    fwrite((char *)&VoiceMod,1,MODSIZE,TyphoonVoiceFile);
  }

  if (Verbose) printf("Pitchbend= %2d AEG= %2d %2d %2d %2d %2d %2d\n",
           pitchbend, AEG[0],AEG[1],AEG[2],AEG[3],AEG[4],AEG[5]);

/* put in split point and wavename from each timbre */

  FirstSplit = 1;
  for(i=0;i < NumTimbres[v];i++)  {
    tim = YVoice[v].Timbre[i].Number;
    WaveNum = YTimbre[tim].WaveNumber;

/* skip timbres with no wave */
    if (YWave[WaveNum].Name[0] == 0) continue;

    if (Verbose) {
      if(WaveNum < 64)
        printf("tim[%2d]: keyrange= %2s%1d-%2s%1d wave[%d]='%s'\n",
          tim,
          Key[YVoice[v].Timbre[i].LowKey % 12],
          YVoice[v].Timbre[i].LowKey / 12 -1,
          Key[YVoice[v].Timbre[i].HiKey % 12],
          YVoice[v].Timbre[i].HiKey / 12 -1,
          WaveNum,YWave[WaveNum].Name);
      else
        printf("Data corrupted. WaveNum= %d!\n",WaveNum);
    }

    if (FirstSplit) {
      FirstSplit=0;
      VoiceSplt.BankLength = WAVESIZE;
      fwrite((char *)&VoiceSplt,1,SPLTSIZE,TyphoonVoiceFile);
    }
    else {
      VoiceSplt.BankLength = SIZESPLTPARM + WAVESIZE;
      fwrite((char *)&VoiceSplt,1,SPLTSIZE,TyphoonVoiceFile);
      VoiceSpltParm.lowkey = YVoice[v].Timbre[i].LowKey;
      fwrite((char *)&VoiceSpltParm,1,SIZESPLTPARM,TyphoonVoiceFile);
    }
    strncpy(VoiceWave.wavename,YWave[WaveNum].Name,8);  /* wave name:       */
      /* I hope that strncpy doesn't copy the 9th NULL string term. */
     /* but if it does, it shouldn't be a problem, as long as
        we write the version immediately after */
    VoiceWave.Version = TyphoonLong(WaveNum+1)   ;  /* .Wxx ??? */
    strncpy(VoiceWave.DiskLabel,TyphLabelName,8); /* disk label */
    fwrite((char *)&VoiceWave,1,WAVESIZE,TyphoonVoiceFile);
  }

  fclose(TyphoonVoiceFile);
  if (Verbose) printf("Typhoon voice saved successfully in file '%s'.\n\n",
		      TyphoonVoiceFileName);

  return 0;
}



/* on some machines, this routine is unnecessary, but machines do
have different byte ordering, so this is just in case.
Typhoon uses high(MSB)->low(LSB) byte ordering. */

unsigned long TyphoonLong(unsigned long value)
{
  unsigned long number;
  unsigned char *form;
  
  number = 0;
  form = (unsigned char *) &number;
  form[0] = (value & 0xFF000000) >>24;
  form[1] = (value & 0x00FF0000) >>16;
  form[2] = (value & 0x0000FF00) >> 8;
  form[3] = (value & 0x000000FF)     ;
  
  return number;
}


int WriteTyphoonSetup(void)
{
  FILE *TyphoonSetupFile;
  char TyphoonSetupFileName[80];
  int i,k,PerfNum;

/* edit setupfile name by changing ".S" to ".X" */
  strcpy(TyphoonSetupFileName,TyphoonDisk);
  strcat(TyphoonSetupFileName,SetupFileName);
  i=strlen(TyphoonSetupFileName);
  k=i-1;
  while(TyphoonSetupFileName[k]!='.' && k>0) k--;
  TyphoonSetupFileName[k+1] = 'X';
  if (Verbose) printf("Attempting to open '%s' for write as typh setup\n",
     TyphoonSetupFileName);
  if((TyphoonSetupFile = (FILE *) fopen( TyphoonSetupFileName, MODE_NEWFILE_ ))
     == NULL ) {
    printf("Error fopening file: %s\n",TyphoonSetupFileName);
    return 1;
  }

/* write SetUp Header */
  SetupFORM.Type = 'S';
  SetupFORM.BankLength =
    TyphoonLong(4 + VINFSIZE + SPARMSIZE + GoodPerfs*PERFSIZE);
  fwrite((char *)&SetupFORM,1,FORMSIZE,TyphoonSetupFile); 

/* write General Info */
  fwrite((char *)&SetupVInf,1,VINFSIZE,TyphoonSetupFile);

  fwrite((char *)&SetupParm,1,SPARMSIZE,TyphoonSetupFile);

  for(PerfNum=0;PerfNum<32;PerfNum++) {
    if (YPerf[PerfNum].Name[0] == 0) continue;
/* add each performance to setup */  
    strcpy(SetupPerf.perfname,YPerf[PerfNum].Name);
    SetupPerf.PerfVersion = TyphoonLong(1L);
    strncpy(SetupPerf.DiskLabel,TyphLabelName,8);
    fwrite((char *)&SetupPerf,1,PERFSIZE,TyphoonSetupFile);
    if (Verbose) printf("Added perf '%s' to setupfile.\n",YPerf[PerfNum].Name); 
  }

  fclose(TyphoonSetupFile);

  return 0;
}


int WriteTyphoonPerfs() {

  int voicecount,len,mark,j,c,p;
  char TyphoonPerfFileName[80],TempFileName[13];
  FILE *TyphoonPerfFile;


  for(p=0;p<32;p++) {
    if (YPerf[p].Name[0] == 0) continue;
    if (Verbose) printf("\nWriting performance %s as ",YPerf[p].Name);
    len = PrepareDOSName(YPerf[p].Name,TempFileName);
    if (len<8) len++;
/* check that it isn't used before, and increment the last character if so */
    for (j=0;j<p;j++) {
      if (!strncmp(YPerf[j].Name,TempFileName,8)) {
        if (Verbose)   
	  printf("Clash found between perf[%d]=%s and perf[%d]=%s\n",
   	       p,TempFileName,j,YPerf[j].Name);
        if (TempFileName[len-1] <'0' || TempFileName[len-1]>'9') 
          TempFileName[len-1] ='0';
        else
	  TempFileName[len-1]++;
      }
    }

    strcpy(YPerf[p].Name,TempFileName);

/* open performance file */
    strcpy(TyphoonPerfFileName,TyphoonDisk);
    strcat(TyphoonPerfFileName,TempFileName);
    strcat(TyphoonPerfFileName,".P01");
    TyphoonPerfFile = (FILE *) fopen(TyphoonPerfFileName,MODE_NEWFILE_);
    if (TyphoonPerfFile == NULL) {
      printf("Could not write a typhoon perf file '%s'.\n",TyphoonPerfFileName);
      fclose(TyphoonPerfFile);
      return 1;
    }

    if (Verbose) printf("'%s'\n",TyphoonPerfFileName);


    mark=99;
    voicecount=0;
    for(c=0;c<16;c++) {
      if (mark != YPerf[p].Group[c]) {
        mark = YPerf[p].Group[c];
        if (YVoice[YPerf[p].Voice[c]].Name[0] != 0) 
          voicecount++;
      }
    }
/* write Voice Header */
    PerfFORM.Type = 'P';
    PerfFORM.BankLength =
      TyphoonLong(4 + VINFSIZE + PARM1SIZE+
		voicecount*(ENTRSIZE+PARM2SIZE+VOICSIZE));
    fwrite((char *)&PerfFORM,1,FORMSIZE,TyphoonPerfFile);

/* write General Info */
    PerfVInf.Version = TyphoonLong(1);
    fwrite((char *)&PerfVInf,1,VINFSIZE,TyphoonPerfFile);

    PerfParm1.magiccookie = TyphoonLong(0x00FF040A);
    fwrite((char *)&PerfParm1,1,PARM1SIZE,TyphoonPerfFile);
      
    mark = 99;
    for(c=0;c<16;c++) {
      if (mark != YPerf[p].Group[c]) {
        mark = YPerf[p].Group[c];

        if (YVoice[YPerf[p].Voice[c]].Name[0] == 0) continue;

        fwrite((char *)&PerfEntr,1,ENTRSIZE,TyphoonPerfFile);
        if(YPerf[p].MIDIReceive[c] == 0x10)
          PerfParm2.MIDIReceive = 0xFF;   /* OMNI/any mode */
        else
          PerfParm2.MIDIReceive = YPerf[p].MIDIReceive[c];
        PerfParm2.Volume =
          (unsigned char) (((99L-YPerf[p].Volume[c]) * 0x3FL) / 99L);
        PerfParm2.LowKey       = 0;
        PerfParm2.HiKey       = 0x60;
        PerfParm2.NoteShift    = YPerf[p].NoteShift[c];
        PerfParm2.detune      = (signed char)((YPerf[c].Detune[c]*0x2BL)/7L);
        PerfParm2.out         = YPerf[p].Output[c];
        PerfParm2.from        = 0;
        PerfParm2.to          = 7;
        PerfParm2.junk        = 0;
        PerfParm2.priority    = 0x02; /* 1=low,2=mid,3=hi */
        PerfParm2.crap        = 0;
        fwrite((char *)&PerfParm2,1,PARM2SIZE,TyphoonPerfFile);
      
        strncpy(PerfVoic.voicename,YVoice[YPerf[p].Voice[c]].Name,8);
        PerfVoic.VoiceVersion     = TyphoonLong(1L);
        strncpy(PerfVoic.DiskLabel,TyphLabelName,8);
        fwrite((char *)&PerfVoic,1,VOICSIZE,TyphoonPerfFile);

        if (Verbose) { 
          printf("Voice:%8s ",PerfVoic.voicename);
          printf(" MIDI:");
          if (PerfParm2.MIDIReceive == 0xFF) 
            printf("Any");
          else
            printf("%3d",PerfParm2.MIDIReceive+1);
          printf(" Out:");
          switch (PerfParm2.out) {
            case 0:  printf("off "); break;
            case 1:  printf("I   "); break;
            case 2:  printf("  II"); break;
            case 3:  printf("I+II"); break;
          }
          printf(" Vol:%3d Shift:%3d Detune:%3d\n",
            PerfParm2.Volume,PerfParm2.NoteShift,PerfParm2.detune);
        }
      }
    }

    fclose(TyphoonPerfFile);
    if (Verbose)
       printf("Successfully wrote performance %s.\n\n",TyphoonPerfFileName);
  }
  return 0;
}



void SetupBanks(void)
{
  int i;

  strncpy(    VoiceFORM.Name,"FORM",4);
  strncpy(     PerfFORM.Name,"FORM",4);
  strncpy(    SetupFORM.Name,"FORM",4);
  strncpy(    VoiceVInf.Name,"VInf",4);
  strncpy(     PerfVInf.Name,"VInf",4);
  strncpy(    SetupVInf.Name,"VInf",4);
  strncpy(    VoiceGrop.Name,"Grop",4);
  strncpy(   TVoiceParm.Name,"Parm",4);
  strncpy(VoiceSpltParm.Name,"Parm",4);
  strncpy(    PerfParm1.Name,"Parm",4);
  strncpy(    PerfParm2.Name,"Parm",4);
  strncpy(    SetupParm.Name,"Parm",4);
  strncpy(     VoiceMod.Name,"Mod ",4);
  strncpy(    VoiceSplt.Name,"Splt",4);
  strncpy(    VoiceWave.Name,"Wave",4);
  strncpy(     PerfEntr.Name,"Entr",4);
  strncpy(     PerfVoic.Name,"Voic",4);
  strncpy(    SetupPerf.Name,"Perf",4);

  strncpy(VoiceFORM.TypeName,"TYP",3);
  strncpy( PerfFORM.TypeName,"TYP",3);
  strncpy(SetupFORM.TypeName,"TYP",3);
  
      VoiceVInf.BankLength = TyphoonLong(0x10L);
     TVoiceParm.BankLength = TyphoonLong(0x40L);
       VoiceMod.BankLength = TyphoonLong(0x06L);
  VoiceSpltParm.BankLength = TyphoonLong(0x02L);
      VoiceWave.BankLength = TyphoonLong(0x14L);
       PerfVInf.BankLength = TyphoonLong(0x10L);
       PerfEntr.BankLength = TyphoonLong(0x30L);
      PerfParm1.BankLength = TyphoonLong(0x04L);
      PerfParm2.BankLength = TyphoonLong(0x0CL);
       PerfVoic.BankLength = TyphoonLong(0x14L);
      SetupVInf.BankLength = TyphoonLong(0x10L);
      SetupPerf.BankLength = TyphoonLong(0x14L);
      SetupParm.BankLength = TyphoonLong(0x38L);

  VoiceVInf.Version = TyphoonLong(1);
   PerfVInf.Version = TyphoonLong(1);
  SetupVInf.Version = TyphoonLong(1);

  PerfParm1.magiccookie = TyphoonLong(0x00FF040A);

  for (i=0;i<12;i++) {
    VoiceVInf.Data[i] = VInfDATA[i];
    PerfVInf.Data[i]  = VInfDATA[i];
    SetupVInf.Data[i] = VInfDATA[i];
  }
  for (i=0;i<0x38;i++)
    SetupParm.Data[i] = SETUPDATA[i];
  
  return;
}



void help(void)
{
  printf("\nsynopsis:\nvortex [-h] [-yNAME] [-tNAME] [-v]\n");
  printf(" -h      This help message\n");
  printf(" -yNAME  Set yamaha (input) disk name to NAME\n");
  printf(" -tNAME  Set typhoon (output) disk name to NAME\n");
  printf(" -lNAME  Set typhoon (output) disk label to NAME\n");
  printf(" -v      Turn debug mode on\n\n");
  printf("Example: vortex -v -y./ -tB: -lANALOGS \n\n");
}
