/*
 *  Copyright (c) by Jaroslav Kysela (Perex soft)
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pmod.h"

#define PAN_LEFT	3
#define PAN_RIGHT	( 15 - PAN_LEFT )

void load669( FILE *file, char *filename )
{
  byte *rbuf, *rbuf1, *ptr;
  short patterns, i, pat, row, chn, version, lastPat, firstRow;

  pprintf( "Loading Composer 669 file %s... ", filename );
  fflush( stdout );
  
  if ( ( rbuf = malloc( 0x1f1 ) ) == NULL )
    fatal( "load669: buffer alloc" );
  if ( ( rbuf1 = malloc( 0x600 ) ) == NULL )
    fatal( "load669: buffer1 alloc" );
  
  if ( fread( rbuf, 0x1f1, 1, file ) != 1 )
    fatal( "load669: header read" );
  version = rbuf[ 0 ] != 0x69 || rbuf[ 1 ] != 0x66;
  strncpy( songName, &rbuf[ 2 ], 30 );
  songName[ 30 ] = 0;
  strcpy( songType, "669" );
  songInstr = rbuf[ 0x6e ];
  patterns = rbuf[ 0x6f ];
  songChannels = 8;

  for ( i = 0; i < songInstr; i++ )
    {
      struct INSTR *is = newInstrument( i );
      struct SAMPLE *smp = newSample( i, 0 );
      
      if ( fread( rbuf1, 25, 1, file ) != 1 )
        fatal( "load669: read instrument header\n" );
      strncpy( is -> name, rbuf1, 13 ); is -> name[ 13 ] = 0;
      strncpy( smp -> name, rbuf1, 13 ); smp -> name[ 13 ] = 0;
      smp -> length = rbuf1[ 13 ] | ( rbuf1[ 14 ] << 8 ) |
                      ( rbuf1[ 15 ] << 16 ) | ( rbuf1[ 16 ] << 24 );
      smp -> lstart = rbuf1[ 17 ] | ( rbuf1[ 18 ] << 8 ) |
                      ( rbuf1[ 19 ] << 16 ) | ( rbuf1[ 20 ] << 24 );
      smp -> lend   = rbuf1[ 21 ] | ( rbuf1[ 22 ] << 8 ) |
                      ( rbuf1[ 23 ] << 16 ) | ( rbuf1[ 24 ] << 24 );
      if ( smp -> lend > smp -> length ||
           smp -> lend < smp -> lstart ) smp -> lstart = smp -> lend = 0;
      smp -> finetune = 0;
      smp -> freqC4 = NTSC_FREQ;
      smp -> volume = 64;
      smp -> type   = SMP_TYPE_UNSIGNED;
      smp -> ident  = -1;
      is -> used = smp -> used = smp -> length > 0;
    }  

  songMaxOrder = -1;
  for ( i = 0, lastPat = -1; i < 128; i++ )
    {
      byte p;
    
      p = rbuf[ 0x71 + i ];
      if ( rbuf[ p ] == 0xff || p >= patterns ) break;
      songOrder[ ++songMaxOrder ] = p;
      if ( p > lastPat ) lastPat = p;
    }

#ifdef 0
  fseek( file, 0x1f1 + ( songInstr * 25 ) + ( ?pattern? * 0x600L ), SEEK_SET );
#endif
  fseek( file, 0x1f1 + songInstr * 25, SEEK_SET );
  for ( pat = 0; pat < patterns; pat++ )
    {
      if ( fread( rbuf1, 0x600, 1, file ) != 1 )
        fatal( "load669: pattern read" );
      convInitPattern();
      ptr = rbuf1;
      for ( row = 0, firstRow = 1;
            row < 64 && row <= (short)rbuf[ 0x171 + pat ]; 
            row++ )
        {
          convInitRow();
          if ( firstRow )
            {
              convAddNote( 0, 0, 255, 0, EFF_SPEED, rbuf[ 0xf1 + pat ], 0, 0 );
              firstRow = 0;
#ifdef 0
              dprintf( "speed: %i\n", rbuf[ 0xf1 + pat ] );
#endif
            }
          for ( chn = 0; chn < 8; chn++, ptr += 3 )
            {
              byte pitch = 255, instr = 255, volume = 255, eff = 0, arg = 0;

              if ( *ptr != 0xff )	/* no note or volume change */
                {
                  if ( *ptr != 0xfe )	/* volume change only */
                    {
                      pitch = ( *ptr >> 2 ) + 24;
                      instr = ( ( *ptr & 3 ) << 4 ) | ( *(ptr + 1) >> 4 );
                    }
                  volume = ( ( *(ptr + 1) & 0x0f ) * 17 ) >> 2;
                }
              if ( *(ptr + 2) != 255 )
                {
                  eff = *(ptr + 2) >> 4;
                  arg = *(ptr + 2) & 0x0f;
                  switch ( eff ) {
                    case 0: eff = EFF_SLIDE_UP; arg <<= 1; break;
                    case 1: eff = EFF_SLIDE_DOWN; arg <<= 1; break;
                    case 2: eff = EFF_SLIDE_TO; arg <<= 1; break;
                    case 3: eff = EFF_EXTRA_SLIDE_UP; arg <<= 1; break;
                    case 4: eff = EFF_VIBRATO; if ( arg ) arg |= 0x70; break;
                    case 5: 
                      eff = EFF_SPEED; 
                      if ( arg == 0 && version )
                        arg = 1;
                       else
                        arg = 0;
                      if ( arg == 0 ) eff = 0; 
                      break;
                    default:
                      fatal( "load669: bad effect (0x%x/0x%x)", eff, arg );
                  }
                }
               else
                if ( volume == 255 ) continue;
              convAddNote( chn,
                           instr,
                           pitch,
                           volume,
                           eff,
                           arg,
                           0, 0 );
            }
          convDoneRow();
        }
      convDonePattern();
    }
    
  free( rbuf );
  free( rbuf1 );

  for ( i = 0; i < songChannels; i++ )
    voices[ i ].pan = i & 1 ? PAN_RIGHT : PAN_LEFT;
  
  fseek( file, 0x1f1 + ( songInstr * 25 ) + ( patterns * 0x600 ), SEEK_SET );
#ifdef 0
  dprintf( "file pos: 0x%x\n", (int)ftell( file ) );
#endif
  row = 0;
  gusSetupChannels();
  for ( i = 0; i < songInstr; i++ )
    if ( songInstrs[ i ] && songInstrs[ i ] -> used )
      {
        gusDownload( file, i, 0 );
        if ( songInstrs[ i ] -> samples[ 0 ] -> length ) 
          songInstrs[ i ] -> samples[ 0 ] -> ident = row++;
         else
          songInstrs[ i ] -> used = songInstrs[ i ] -> samples[ 0 ] -> used = 0;
      }
  
  pprintf( "Done.\n" );
  
  songPlaySpeed = 4;
  songTempo = 75;
  songGlobalVolume = 128;
  currentPalFreq = 0;
  if ( freqType == FTYPE_NOTHING ) freqType = FTYPE_LINEAR;
}
