/*---------------------------------------------------------------------*
 * SMUS.C
 *
 *----------------------------------------------------------------------*/

#include "smus.h"
#include "music.h"

typedef struct {
    ClientFrame clientFrame;
    int levels;      /* # groups currently nested within.*/
    } Frame;


char MsgOkay[] = { "----- (IFF_OKAY) A good IFF file." };
char MsgEndMark[] = {"----- (END_MARK)" };
char MsgDone[] = { "----- (IFF_DONE)"};
char MsgDos[] = { "----- (DOS_ERROR) The DOS gave back an error." };
char MsgNot[] = { "----- (NOT_IFF) Not an IFF file." };
char MsgNoFile[] = { "----- (NO_FILE) No such file found." };
char MsgClientError[] = {"----- (CLIENT_ERROR) IFF Checker bug."};
char MsgForm[] = { "----- (BAD_FORM)" };
char MsgShort[] = { "----- (SHORT_CHUNK)" };
char MsgBad[] = { "----- (BAD_IFF) a mangled IFF file." };
 
/* MUST GET THESE IN RIGHT ORDER!!*/
char *IFFPMessages[-LAST_ERROR+1] = {
    /*IFF_OKAY*/  MsgOkay,
    /*END_MARK*/  MsgEndMark,
    /*IFF_DONE*/  MsgDone,
    /*DOS_ERROR*/ MsgDos,
    /*NOT_IFF*/   MsgNot,
    /*NO_FILE*/   MsgNoFile,
    /*CLIENT_ERROR*/ MsgClientError,
    /*BAD_FORM*/  MsgForm,
    /*SHORT_CHUNK*/  MsgShort,
    /*BAD_IFF*/   MsgBad
    };
 
/* FORWARD REFERENCES */
extern IFFP GetList(/*GroupContext */);
extern IFFP GetForm(/*GroupContext */);
extern IFFP GetProp(/*GroupContext */);
extern IFFP GetCat (/*GroupContext */);

extern BOOL GetPallette();

void DoSMUS(name,PalName,DestDir)
   char *name;                /* name of IFF SMUS file */
   char *PalName;             /* name of MS sound file */
   char *DestDir;             /* path of Destination directory */
{
   IFFP iffp;
   BPTR file;
   Frame frame;

   frame.levels = 0;
   frame.clientFrame.getList = GetList;
   frame.clientFrame.getForm = GetForm;
   frame.clientFrame.getProp = GetProp;
   frame.clientFrame.getCat  = GetCat ;

   InitTracks();
   InitSong();

   if (PalName != NULL)
      if (!GetPallette(PalName))     /* if sound file load fails */
         InitSong();                 /* fall back on intro.song */
   file = Open(name, MODE_OLDFILE);
   if (file != NULL)
   {
      iffp = ReadIFF(file, (ClientFrame *)&frame);
      TracksToMS();
      WriteSong(name,DestDir);
   }
   else
      iffp = NO_FILE;
   Close(file);
   if (iffp != 0)
      printf("%s\n", IFFPMessages[-iffp]);
}

   /* storage for source filename while it is being assembled */
static char FileName[MS_NAME_MAX];

main(argc, argv)
   int argc;
   char **argv;
{
   int   argno = 0;
   int   Remains;          /* # remaining free chars in FileName */
   char  *palname = NULL;  /* name of sound pallette file to load */
   char  *DestDir = NULL;

   FileName[0] = NULL;
   Debug = FALSE;

   if (argc <= 1)
   {
      printf("Usage: 'smus2ms [-s sounds] [-d dest-dir] filename'\n");
      exit(0);
   }
   argc--;  /* skip command name */
   while (argc-- > 0)
   {
         argno++;
         if (*argv[argno] == '-')
         {
            argv[argno]++;                /* skip over the dash */
            switch(*argv[argno])          /* check char after dash */
            {
               case 'z':
               case 'Z':
                  Debug = TRUE;
                  break;
               case 's':
               case 'S':
                  argno++;             /* skip ahead to pallette filename */
                  palname = argv[argno];
                  argc--;              /* one less arg - grabbed PalName */
                  break;
               case 'd':
               case 'D':
                  argno++;             /* skip ahead to Dest directory */
                  DestDir = argv[argno];
                  argc--;              /* one less arg - grabbed Dest */
                  break;
               default:
                  printf("Usage: 'smus2ms [-s sounds] [-d dest-dir] filename'\n");
                  exit(0);
            } /* switch */
         } /* if */
         else /* not dash arg */
         {
            if (FileName[0] == NULL)                /* 1st piece */
               (VOID) strncpy(FileName,argv[argno],MS_NAME_MAX-1);
            else
            {                                      /* subsequent ones */
                  /* calculate remaining FileName capacity */
               Remains = MS_NAME_MAX-strlen(FileName)-1;
               (VOID) strcat(FileName," ");
               (VOID) strncat(FileName,argv[argno],Remains);
            }
         }
   } /* while more arguments */
   DoSMUS(FileName,palname,DestDir);
} /* main */
 
/* ---------- AtLeaf ---------------------------------------------------*/
 
/* At Leaf chunk.  That is, a chunk which does NOT contain other chunks.
 * Print "ID size".*/
IFFP AtLeaf(context)  GroupContext *context; {

    SEvent *buffer;
    ID id;

    /* A typical reader would read the chunk's contents, using the "Frame"
     * for local data, esp. shared property settings (PROP).*/

    buffer = (SEvent *) ExtAlloc((LONG) context->ckHdr.ckSize);

    if (buffer == NULL)
    {
      printf("Out of memory - song too long");
      exit();
    }

    IFFReadBytes(context,(char *) buffer, context->ckHdr.ckSize);

    id = context->ckHdr.ckID;

    switch (id) {
      case ID_NAME:
         NameToMS(context->ckHdr.ckSize,(char *) buffer);
         break;
      case ID_SHDR:
         ShdrToMS((SScoreHeader *) buffer);
         break;
      case ID_INS1:
         Ins1ToMS(context->ckHdr.ckSize,(RefInstrument *) buffer);
         break;
      case ID_TRAK:
         ReadTrack(context->ckHdr.ckSize, buffer, NumTracks);
         NumTracks++;
         break;
      case ID_ANNO:
      case ID_Copyright:
      case ID_AUTH:
      default:
         break;
    } /* switch */
    RemFree( (UBYTE *) buffer);
    return(IFF_OKAY);
} /* At Leaf */


/* ---------- GetList --------------------------------------------------*/
/* Handle a LIST chunk.  Print "LIST size subTypeID".
 * Then dive into it.*/
IFFP GetList(parent)  GroupContext *parent; {
    Frame newFrame;
 
    newFrame = *(Frame *)parent->clientFrame;  /* copy parent's frame*/
    newFrame.levels++;
 
    return( ReadIList(parent, (ClientFrame *)&newFrame) );
    }
 
/* ---------- GetForm --------------------------------------------------*/
/* Handle a FORM chunk.  Print "FORM size subTypeID".
 * Then dive into it.*/
IFFP GetForm(parent)   GroupContext *parent; {
    /*CompilerBug register*/ IFFP iffp;
    GroupContext new;
    Frame newFrame;
 
    newFrame = *(Frame *)parent->clientFrame;  /* copy parent's frame*/
    newFrame.levels++;
 
    iffp = OpenRGroup(parent, &new);
    CheckIFFP();
    new.clientFrame = (ClientFrame *)&newFrame;
 
    /* FORM reader for Checker. */
    /* LIST, FORM, PROP, CAT already handled by GetF1ChunkHdr. */
    do {if ( (iffp = GetF1ChunkHdr(&new)) > 0 )
       iffp = AtLeaf(&new);
   } while (iffp >= IFF_OKAY);
 
    CloseRGroup(&new);
    return(iffp == END_MARK ? IFF_OKAY : iffp);
    }
 
/* ---------- GetProp --------------------------------------------------*/
/* Handle a PROP chunk.  Print "PROP size subTypeID".
 * Then dive into it.*/
IFFP GetProp(listContext)  GroupContext *listContext; {
    /*CompilerBug register*/ IFFP iffp;
    GroupContext new;
 
    iffp = OpenRGroup(listContext, &new);
    CheckIFFP();
 
    /* PROP reader for Checker. */
    ((Frame *)listContext->clientFrame)->levels++;
 
    do {if ( (iffp = GetPChunkHdr(&new)) > 0 )
       iffp = AtLeaf(&new);
   } while (iffp >= IFF_OKAY);
 
    ((Frame *)listContext->clientFrame)->levels--;
 
    CloseRGroup(&new);
    return(iffp == END_MARK ? IFF_OKAY : iffp);
    }
 
/* ---------- GetCat ---------------------------------------------------*/
/* Handle a CAT chunk.  Print "CAT size subTypeID".
 * Then dive into it.*/
IFFP GetCat(parent)  GroupContext *parent;  {
    IFFP iffp;
 
    ((Frame *)parent->clientFrame)->levels++;
 
    iffp = ReadICat(parent);
 
    ((Frame *)parent->clientFrame)->levels--;
    return(iffp);
    }
