/* Traks.c
 *
 * Routines for accessing Trak memory chunks during ms2iff
 */


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


extern GroupContext *OpenWSmus();
extern BOOL CloseWSmus();

static IFFP ifferror = IFF_OKAY;


/*
 * Allocate another 1K of memory for given track
 *  This becomes necessary when a track becomes longer than
 *  current length estimate.  
 *  A new block of memory 1K longer than the current track size
 *  is allocated and the entire track is copied to the new block.
 *  The previous track block is then freed.
 */
MoreMem(TrackNo)
   int   TrackNo;
{
   char  *NewTrak;

   NewTrak = (char *) ExtAlloc( (LONG) (Traks[TrackNo].TrakSize + 1024));
   if (NewTrak == NULL)
   {
      Traks[TrackNo].TrakSize = 0;
      FreeTraks();
      CleanExit("Out of Memory...Song too long!");
   }
   else
   {
      movmem(Traks[TrackNo].TrakData,NewTrak,Traks[TrackNo].TrakSize+1);
      RemFree( (UBYTE *) Traks[TrackNo].TrakData);
      Traks[TrackNo].TrakSize += 1024;
      Traks[TrackNo].TrakData = NewTrak;
   }
} /* MoreMem */



/*
 * Add a SMUS SEvent to given track at track's current position
 *  Also advance given track to the next position
 */
AddEvent(TargTrack,NewEvent)
   int   TargTrack;
   SEvent *NewEvent;
{
   char  *TrackP;          /* Pointer into SMUS track */
   int   EventNum;         /* Which event in SMUS track */

   EventNum = (Traks[TargTrack].CurrEvent)++;   /* Find new event # */
   if (2*EventNum >= Traks[TargTrack].TrakSize)  /* if overflow this trak */
      MoreMem(TargTrack);
   TrackP = &(Traks[TargTrack].TrakData[2*EventNum]);
   *TrackP++ = NewEvent->sID;                   /* stuff SEvent ID */
   *TrackP = NewEvent->data;                    /* and data bytes */
} /* AddEvent */



/*
 * Allocate memory for IFF TRAK chunks
 */
AllocTraks()
{
   int i;
   int   TraksSoFar = 0;               /* runs up to MaxTracks */
   BOOL  TooMany = FALSE;              /* True when over MaxTracks */
   BOOL  Enough  = FALSE;              /* False until alloc'ed Max tracks */

   for (i = 1; i <= MAXCOLORS; i++)    /* Don't alloc track for NN[0] */
   {
      if ((NumNotes[i] > 0) && !(TooMany))     /* if notes on this inst */
      {
            /* Initial guess on track size is 3 bytes per note */
         Traks[i].TrakSize = 3*(NumNotes[i]);   /* size in bytes */
         Traks[i].TrakData = (char *) ExtAlloc((LONG) Traks[i].TrakSize);
         if (Traks[i].TrakData == NULL)
         {
            Traks[i].TrakSize = 0;
            FreeTraks();
            CleanExit("Out Of Memory -- Song too long!");
         }
         if ((MaxTracks > 0) && (++TraksSoFar >= MaxTracks))
            TooMany = TRUE;
         Traks[i].CurrEvent = 0;
         Traks[i].CurrTime = 0;        /* time in 144ths */
      }
      else
      {
         Traks[i].TrakSize = 0;
         Traks[i].TrakData = NULL;
      }
   } /* for */

      /* Now allocate memory for 'extra' tracks up to MaxTracks */
      /* 'extra' tracks not assigned to any instrument, but are used */
      /* to contain overflow notes when a chord consisting of more than */
      /* one note on a given instrument is encountered */
      
   if ((MaxTracks > 0) && (TraksSoFar < MaxTracks))
      for (i = MAXCOLORS; ((i > 0) && !(Enough)); i--)
         if (Traks[i].TrakData == NULL)   /* if not already allocated */
         {
            if (Debug)
               printf("Extra Trak: %d\n",i);

            Traks[i].TrakSize = 3*100;   /* allocate it */
            Traks[i].TrakData = (char *) ExtAlloc ((LONG) Traks[i].TrakSize);
            if (Traks[i].TrakData == NULL)
            {
               Traks[i].TrakSize = 0;
               FreeTraks();
               CleanExit("Out of memory - song too long!");
            }
            if (++TraksSoFar >= MaxTracks)
               Enough = TRUE;
            Traks[i].CurrEvent = 0;
            Traks[i].CurrTime = 0;
            NumNotes[i] = 0;
         }  /* if */
} /* AllocTraks */


/*
 * Write all assembled tracks to SMUS file track chunks
 */
WriteTraks(Context)
GroupContext *Context;
{
   int   i;

   for (i = 1; i < MAXCOLORS+1; i++)
         /* If some data in track and track not all rests */
      if ((Traks[i].TrakSize > 0) && (NumNotes[i] > 0)) {
            /* and write it out as an IFF TRAK Chunk */
         CkErr( PutCk(Context,ID_TRAK, 2*(Traks[i].CurrEvent),(BYTE *) Traks[i].TrakData) );
      } /* if */                              /* ^^^ to be continued ^^^ */
} /* WriteTraks */

/*
 * Free the memory allocated to the tracks
 */
FreeTraks()
{

   int i;

   for (i = 1; i <= MAXCOLORS; i++)
      if ((Traks[i].TrakSize > 0) && (Traks[i].TrakData != NULL))
        RemFree( (UBYTE *) Traks[i].TrakData);
}



