/* testTP3() */
/* Rip_TP3() */
/* Depack_TP3() */


#include "globals.h"
#include "extern.h"


short testTP3 ( void )
{

  PW_Start_Address = PW_i;

  /* number of sample */
  PW_l = ( (in_data[PW_Start_Address+28]*256)+
	   in_data[PW_Start_Address+29] );
  if ( (((PW_l/8)*8) != PW_l) || (PW_l == 0) )
  {
/*printf ( "#2 Start: %ld\n" , PW_Start_Address );*/
    return BAD;
  }
  PW_l /= 8;
  /* PW_l is the number of sample */

  /* test finetunes */
  for ( PW_k=0 ; PW_k<PW_l ; PW_k++ )
  {
    if ( in_data[PW_Start_Address+30+PW_k*8] > 0x0f )
    {
/*printf ( "#3 Start: %ld\n" , PW_Start_Address );*/
      return BAD;
    }
  }

  /* test volumes */
  for ( PW_k=0 ; PW_k<PW_l ; PW_k++ )
  {
    if ( in_data[PW_Start_Address+31+PW_k*8] > 0x40 )
    {
/*printf ( "#4 Start: %ld\n" , PW_Start_Address );*/
      return BAD;
    }
  }

  /* test sample sizes */
  PW_WholeSampleSize = 0;
  for ( PW_k=0 ; PW_k<PW_l ; PW_k++ )
  {
    /* size */
    PW_j = (in_data[PW_Start_Address+PW_k*8+32]*256)+in_data[PW_Start_Address+PW_k*8+33];
    /* loop start */
    PW_m = (in_data[PW_Start_Address+PW_k*8+34]*256)+in_data[PW_Start_Address+PW_k*8+35];
    /* loop size */
    PW_n = (in_data[PW_Start_Address+PW_k*8+36]*256)+in_data[PW_Start_Address+PW_k*8+37];
    PW_j *= 2;
    PW_m *= 2;
    PW_n *= 2;
    if ( (PW_j > 0xFFFF) ||
         (PW_m > 0xFFFF) ||
         (PW_n > 0xFFFF) )
    {
/*printf ( "#5 Start:%ld\n" , PW_Start_Address );*/
      return BAD;
    }
    if ( (PW_m + PW_n) > (PW_j+2) )
    {
/*printf ( "#5,1 Start:%ld\n" , PW_Start_Address );*/
      return BAD;
    }
    if ( (PW_m != 0) && (PW_n == 0) )
    {
/*printf ( "#5,2 Start:%ld\n" , PW_Start_Address );*/
      return BAD;
    }
    PW_WholeSampleSize += PW_j;
  }
  if ( PW_WholeSampleSize <= 4 )
  {
/*printf ( "#5,3 Start:%ld\n" , PW_Start_Address );*/
    return BAD;
  }

  /* pattern list size */
  PW_j = in_data[PW_Start_Address+PW_l*8+31];
  if ( (PW_j==0) || (PW_j>128) )
  {
/*printf ( "#6 Start:%ld\n" , PW_Start_Address );*/
    return BAD;
  }

  /* PW_j is the size of the pattern list */
  /* PW_l is the number of sample */
  /* PW_WholeSampleSize is the sample data size */
  return GOOD;
}




void Rip_TP3 ( void )
{
  /* PW_j is the size of the pattern list */
  /* PW_l is the number of sample */
  /* PW_WholeSampleSize is the sample data size */


  PW_m=0;
  for ( PW_k=0 ; PW_k<PW_j ; PW_k++ )
  {
    PW_o = (in_data[PW_Start_Address+PW_l*8+32+PW_k*2]*256)+in_data[PW_Start_Address+PW_l*8+33+PW_k*2];
    if ( PW_o > PW_m )
      PW_m = PW_o;
  }
  /* PW_m is the highest pattern number */
  PW_m += 8;
  /* PW_m is now the size of the track table list */
  PW_n = 0;
/*printf ( "highest pattern : %ld (%x)\n" , PW_m , PW_m );*/
  for ( PW_k=0 ; PW_k<(PW_m/2) ; PW_k++ )
  {
    PW_o = (in_data[PW_Start_Address+PW_l*8+32+PW_j*2+PW_k*2]*256)+in_data[PW_Start_Address+PW_l*8+33+PW_j*2+PW_k*2];
/*printf ( "%4x, " , PW_o );*/
    if ( PW_o > PW_n )
      PW_n = PW_o;
  }
/*printf ( "\nhighest : %ld (%x)\n" , PW_n , PW_n );*/
/*printf ( "track data address : %ld (%x)\n" , (34+8*PW_l+2*PW_j+PW_m ),(34+8*PW_l+2*PW_j+PW_m));*/
  PW_n += (34+8*PW_l+2*PW_j+PW_m);
/*printf ( "address of last track : %ld\n" , PW_n );*/
  OutputSize = PW_n;
  

  /* all vars are availlable now, save PW_WholeSampleSize */

  /* now counting size of the last pattern ... pfiew .. */
  PW_l = 0;
  for ( PW_j=0 ; PW_j<64 ; PW_j++ )
  {
/*printf ( "%ld," , PW_l );*/
    if ( (in_data[PW_Start_Address+PW_n+PW_l]&0xC0 ) == 0xC0 )
    {
      PW_j += (0x100-in_data[PW_Start_Address+PW_n+PW_l]);
      PW_j -= 1;
      PW_l += 1;
      continue;
    }
    if ( (in_data[PW_Start_Address+PW_n+PW_l]&0xC0 ) == 0x80 )
    {
      PW_l += 2;
      continue;
    }
    PW_l += 1;
    if ( (in_data[PW_Start_Address+PW_n+PW_l]&0x0F ) == 0x00 )
    {
      PW_l += 1;
      continue;
    }
    PW_l += 2;
  }
/*printf ( "\nsize of the last track : %ld\n" , PW_l );*/

  OutputSize += PW_l + 2;  /* +2 for $0000 at the end .. */
  if ( ((OutputSize/2)*2) != OutputSize )
    OutputSize += 1;
  OutputSize += PW_WholeSampleSize;

  CONVERT = GOOD;
  Save_Rip ( "Tracker Packer v3 module", TP3 );
  
  if ( Save_Status == GOOD )
    PW_i += (OutputSize - 1); /* 0 could be enough */
}



/*
 *   TrackerPacker_v3.c   1998 (c) Asle / ReDoX
 *
 * Converts TP3 packed MODs back to PTK MODs
 ********************************************************
 * 13 april 1999 : Update
 *   - no more open() of input file ... so no more fread() !.
 *     It speeds-up the process quite a bit :).
 *
 * 28 November 1999 : Update
 *   - Some Optimizing for Speed and for Size.
*/

void Depack_TP3 ( void )
{
  Uchar c1=0x00,c2=0x00,c3=0x00;
  Uchar poss[37][2];
  Uchar *Whatever;
  Uchar Note,Smp,Fx,FxVal;
  Uchar PatMax=0x00;
  long Track_Address[128][4];
  long i=0,j=0,k;
  long Start_Pat_Address=999999l;
  long Whole_Sample_Size=0;
  long Max_Track_Address=0;
  long Where=PW_Start_Address;   /* main pointer to prevent fread() */
  FILE *out;

  fillPTKtable(poss);

  if ( Save_Status == BAD )
    return;

  BZERO ( Track_Address , 128*4*4 );

  sprintf ( Depacked_OutName , "%ld.mod" , Cpt_Filename-1 );
  out = PW_fopen ( Depacked_OutName , "w+b" );

  /* title */
  Where += 8;
  fwrite ( &in_data[Where] , 20 , 1 , out );
  Where += 20;

  /* number of sample */
  j = (in_data[Where]*256)+in_data[Where+1];
  Where += 2;
  j /= 8;
  /*printf ( "number of sample : %ld\n" , j );*/

  Whatever = (Uchar *) malloc ( 1024 );
  BZERO ( Whatever , 1024 );
  for ( i=0 ; i<j ; i++ )
  {
    /*sample name*/
    fwrite ( Whatever , 22 , 1 , out );

    /* size */
    Whole_Sample_Size += (((in_data[Where+2]*256)+in_data[Where+3])*2);
    fwrite ( &in_data[Where+2] , 2 , 1 , out );

    /* write finetune & Volume */
    fwrite ( &in_data[Where] , 2 , 1 , out );

    /* loop start & Loop size */
    fwrite ( &in_data[Where+4] , 4 , 1 , out );

    Where += 8;
  }
  Whatever[29] = 0x01;
  while ( i!=31 )
  {
    fwrite ( Whatever , 30 , 1 , out );
    i++;
  }
  /*printf ( "Whole sample size : %ld\n" , Whole_Sample_Size );*/

  /* read size of pattern table */
  Where += 1;
  Whatever[256] = in_data[Where++]; /* PatPos*/
  fwrite ( &Whatever[256] , 1 , 1 , out );

  /* ntk byte */
  Whatever[0] = 0x7f;
  fwrite ( &Whatever[0] , 1 , 1 , out );

  for ( i=0 ; i<Whatever[256] ; i++ )
  {
    Whatever[i] = ((in_data[Where]*256)+in_data[Where+1])/8;
    Where += 2;
    if ( Whatever[i] > PatMax )
      PatMax = Whatever[i];
/*fprintf ( info , "%3ld: %ld\n" , i,Pats_Address[i] );*/
  }

  /* read tracks addresses */
  /* bypass 4 bytes or not ?!? */
  /* Here, I choose not :) */
/*fprintf ( info , "track addresses :\n" );*/
  for ( i=0 ; i<=PatMax ; i++ )
  {
    for ( j=0 ; j<4 ; j++ )
    {
      Track_Address[i][j] = (in_data[Where]*256)+in_data[Where+1];
      Where += 2;
      if ( Track_Address[i][j] > Max_Track_Address )
        Max_Track_Address = Track_Address[i][j];
/*fprintf ( info , "%6ld, " , Track_Address[i][j] );*/
    }
/*fprintf ( info , "  (%x)\n" , Max_Track_Address );*/
  }

  /*printf ( "Highest pattern number : %d\n" , PatMax );*/

  /* write pattern list */
  fwrite ( Whatever , 128 , 1 , out );


  /* ID string */
  Whatever[0] = 'M';
  Whatever[1] = '.';
  Whatever[2] = 'K';
  Whatever[3] = '.';
  fwrite ( Whatever , 4 , 1 , out );

  Start_Pat_Address = Where + 2;
  /*printf ( "address of the first pattern : %ld\n" , Start_Pat_Address );*/
/*fprintf ( info , "address of the first pattern : %x\n" , Start_Pat_Address );*/

  /* pattern datas */
  /*printf ( "converting pattern data " );*/
  for ( i=0 ; i<=PatMax ; i++ )
  {
/*fprintf ( info , "\npattern %ld:\n\n" , i );*/
    BZERO ( Whatever , 1024 );
    for ( j=0 ; j<4 ; j++ )
    {
/*fprintf ( info , "track %ld: (at %ld)\n" , j , Track_Address[i][j]+Start_Pat_Address );*/
      Where = Track_Address[i][j]+Start_Pat_Address;
      for ( k=0 ; k<64 ; k++ )
      {
        c1 = in_data[Where++];
/*fprintf ( info , "%ld: %2x," , k , c1 );*/
        if ( (c1&0xC0) == 0xC0 )
        {
/*fprintf ( info , " <--- %d empty lines\n" , (0x100-c1) );*/
          k += (0x100-c1);
          k -= 1;
          continue;
        }
        if ( (c1&0xC0) == 0x80 )
        {
          c2 = in_data[Where++];
/*fprintf ( info , "%2x ,\n" , c2 );*/
          Fx    = (c1>>1)&0x0f;
          FxVal = c2;
          if ( (Fx==0x05) || (Fx==0x06) || (Fx==0x0A) )
          {
            if ( FxVal > 0x80 )
              FxVal = 0x100-FxVal;
            else if ( FxVal <= 0x80 )
              FxVal = (FxVal<<4)&0xf0;
          }
          if ( Fx == 0x08 )
            Fx = 0x00;
          Whatever[k*16+j*4+2]  = Fx;
          Whatever[k*16+j*4+3]  = FxVal;
          continue;
        }

        c2 = in_data[Where++];
/*fprintf ( info , "%2x, " , c2 );*/
        Smp   = ((c2>>4)&0x0f) | ((c1>>2)&0x10);
        if ( (c1&0x40) == 0x40 )
          Note = 0x7f-c1;
        else
          Note  = c1&0x3F;
        Fx    = c2&0x0F;
        if ( Fx == 0x00 )
        {
/*fprintf ( info , " <--- No FX !!\n" );*/
          Whatever[k*16+j*4] = Smp&0xf0;
          Whatever[k*16+j*4]   |= poss[Note][0];
          Whatever[k*16+j*4+1]  = poss[Note][1];
          Whatever[k*16+j*4+2]  = (Smp<<4)&0xf0;
          Whatever[k*16+j*4+2] |= Fx;
          continue;
        }
        c3 = in_data[Where++];
/*fprintf ( info , "%2x\n" , c3 );*/
        if ( Fx == 0x08 )
          Fx = 0x00;
        FxVal = c3;
        if ( (Fx==0x05) || (Fx==0x06) || (Fx==0x0A) )
        {
          if ( FxVal > 0x80 )
            FxVal = 0x100-FxVal;
          else if ( FxVal <= 0x80 )
            FxVal = (FxVal<<4)&0xf0;
        }

        Whatever[k*16+j*4] = Smp&0xf0;
        Whatever[k*16+j*4]   |= poss[Note][0];
        Whatever[k*16+j*4+1]  = poss[Note][1];
        Whatever[k*16+j*4+2]  = (Smp<<4)&0xf0;
        Whatever[k*16+j*4+2] |= Fx;
        Whatever[k*16+j*4+3]  = FxVal;
      }
      if ( Where > Max_Track_Address )
        Max_Track_Address = Where;
/*fprintf ( info , "%6ld, " , Max_Track_Address );*/
    }
    fwrite ( Whatever , 1024 , 1 , out );
    /*printf ( "." );*/
  }
  free ( Whatever );
  /*printf ( " ok\n" );*/

  /*printf ( "sample data address : %ld\n" , Max_Track_Address );*/

  /* Sample data */
  if ( ((Max_Track_Address/2)*2) != Max_Track_Address )
    Max_Track_Address += 1;
  fwrite ( &in_data[Max_Track_Address] , Whole_Sample_Size , 1 , out );

  Crap ( " Tracker Packer 3 " , BAD , BAD , out );

  fflush ( out );
  fclose ( out );

  printf ( "done\n" );
  return; /* useless ... but */
}
