/*

 Name: LOAD_669.C

 Description:
 Tran's 669 module loader

 Portability:
 All systems - all compilers (hopefully)

 If this module is found to not be portable to any particular platform,
 please contact Jake Stine at dracoirs@epix.net (see MIKMOD.TXT for
 more information on contacting the author).

*/

#include <string.h>
#include "mikmod.h"

// Raw 669 header struct:

typedef struct S69HEADER
{   UBYTE  marker[2];
    CHAR   message[108];
    UBYTE  nos;
    UBYTE  nop;
    UBYTE  looporder;
    UBYTE  orders[0x80];
    UBYTE  tempos[0x80];
    UBYTE  breaks[0x80];
} S69HEADER;


// Raw 669 sampleinfo struct:

typedef struct S69SAMPLE
{   CHAR   filename[13];
    SLONG  length;
    SLONG  loopbeg;
    SLONG  loopend;
} S69SAMPLE;


// Raw 669 Note struct

typedef struct S69NOTE
{   UBYTE a,b,c;
} S69NOTE;


static S69NOTE *s69pat = NULL;
static S69HEADER *mh   = NULL;

static CHAR  *S69_Version[] =
{   "669",
    "Extended 669"
};


BOOL S69_Test(void)
{
    UBYTE id[2];

    if(!_mm_read_UBYTES(id,2,modfp)) return 0;
    if(!memcmp(id,"if",2) || !memcmp(id,"JN",2)) return 1;

    return 0;
}


BOOL S69_Init(void)
{
    if(!(s69pat=(S69NOTE *)_mm_malloc(64*8*sizeof(S69NOTE)))) return 0;
    if(!(mh=(S69HEADER *)_mm_calloc(1,sizeof(S69HEADER)))) return 0;
    return 1;
}


void S69_Cleanup(void)
{
   if(s69pat!=NULL) free(s69pat);
   if(mh!=NULL) free(mh);

   mh     = NULL;
   s69pat = NULL;
}


BOOL S69_LoadPatterns(void)
{
   int t,s,q,tracks=0,t2,t3;
   UBYTE note,inst,vol,a,b,c;
   S69NOTE *cur;

   if(!AllocPatterns()) return 0;
   if(!AllocTracks()) return 0;

   for(t=0; t<of.numpat; t++)
   {   of.pattrows[t] = mh->breaks[t]+1;

       // Load the pattern into the temp buffer
       // and convert it into the 3-byte format

       cur = s69pat;
       for(t2=64; t2; t2--)
       {   for(t3=8; t3; t3--, cur++)
           {   cur->a = _mm_read_UBYTE(modfp);
               cur->b = _mm_read_UBYTE(modfp);
               cur->c = _mm_read_UBYTE(modfp);
           }
       }

       if(feof(modfp))
       {   _mm_error = MLERR_LOADING_PATTERN;
           return 0;
       }

       for(s=0; s<8; s++)
       {   UniReset();
           UniPTEffect(0xf,78);
           UniPTEffect(0xf,3);

           for(q=0; q<64; q++)
           {   a = s69pat[(q*8)+s].a;
               b = s69pat[(q*8)+s].b;
               c = s69pat[(q*8)+s].c;

               note = a>>2;
               inst = ((a&0x3)<<4)|((b&0xf0)>>4);
               vol  = b&0xf;

               if(note<0x3e)
               {   UniInstrument(inst);
                   UniNote(note+24);
               }

               if(note<0x3f) UniPTEffect(0xc,vol<<2);

               UniNewline();
           }
           if(!(of.tracks[tracks++]=UniDup())) return 0;
       }
   }
   return 1;
}


BOOL S69_Load(void)
{
       int t;
       S69SAMPLE s;
       INSTRUMENT *d;
       SAMPLE *q;

       // try to read module header       
       _mm_read_UBYTES(mh->marker,2,modfp);
       _mm_read_UBYTES((UBYTE *)mh->message,108,modfp);
       mh->nos = _mm_read_UBYTE(modfp);
       mh->nop = _mm_read_UBYTE(modfp);
       mh->looporder = _mm_read_UBYTE(modfp);
       _mm_read_UBYTES(mh->orders,0x80,modfp);
       _mm_read_UBYTES(mh->tempos,0x80,modfp);
       _mm_read_UBYTES(mh->breaks,0x80,modfp);

       // set module variables
       of.initspeed = 6;
       of.inittempo = 125;
       of.modtype   = strdup(S69_Version[memcmp(mh->marker,"JN",2)==0]);
       of.numchn    = 8;
       of.numpat    = mh->nop;
       of.numins    = of.numsmp = mh->nos;
       of.numtrk    = of.numchn*of.numpat;

       memcpy(of.positions,mh->orders,0x80);

       for(t=0; t<128; t++)
          if(of.positions[t]==0xff) break;

       of.numpos = t;

       if(!AllocInstruments()) return 0;
       if(!AllocSamples()) return 0;
       d = of.instruments;
       q = of.samples;

       for(t=0; t<of.numins; t++)
       {   // try to read sample info

           _mm_read_UBYTES((UBYTE *)s.filename,13,modfp);
           s.length   = _mm_read_I_SLONG(modfp);
           s.loopbeg  = _mm_read_I_SLONG(modfp);
           s.loopend  = _mm_read_I_SLONG(modfp);

           d->insname    = DupStr(s.filename,13);
           q->samplename = DupStr(s.filename,13);

           q->seekpos   = 0;
           q->c2spd     = 8363;
           q->length    = s.length;
           q->loopstart = s.loopbeg;
           q->loopend   = (s.loopend<s.length) ? s.loopend : s.length;
           q->flags     = (s.loopbeg<s.loopend)?SF_LOOP:0;
           q->volume    = 64;
//           d->flags=(d->loopstart<d->loopend)?SF_LOOP:0;
           d++;
           q++;
       }

       if(!S69_LoadPatterns()) return 0;
       return 1;
}


MLOADER load_669 =
{   NULL,
    "669",
    "669 loader v0.1",
    S69_Init,
    S69_Test,
    S69_Load,
    S69_Cleanup
};


