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

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

void loadMTM( FILE *file, char *filename )
{
  byte *rbuf, *rbuf1, *ptr;
  unsigned short tracks, extraLen, trkPtr;
  short i, lastPat, beats, chn, row;

  pprintf( "Loading Multitracker file %s... ", filename );
  fflush( stdout );

  if ( ( rbuf = malloc( MAX_INSTRUMENTS * 37 ) ) == NULL )
    fatal( "loadMTM: buffer alloc" );
  if ( ( rbuf1 = malloc( 192 * 32 ) ) == NULL )
    fatal( "loadMTM: buffer1 alloc" );

  if ( fread( rbuf, 66, 1, file ) != 1 )
    fatal( "loadMTM: header read" );
  if ( rbuf[ 3 ] != 0x10 )
    dprintf( "/nloadMTM: warning - version != 0x10\n" );
  strncpy( songName, &rbuf[ 4 ], 20 );
  songName[ 20 ] = 0;
  strcpy( songType, "MTM" );
  tracks = rbuf[ 24 ] | ( rbuf[ 25 ] << 8 );
  lastPat = rbuf[ 26 ];
  songMaxOrder = rbuf[ 27 ];
  extraLen = rbuf[ 28 ] | ( rbuf[ 29 ] << 8 );
  songInstr = rbuf[ 30 ];
  if ( rbuf[ 31 ] != 0 )
    dprintf( "\nloadMTM: warning - attribute byte != 0\n" );
  beats = rbuf[ 32 ];
  songChannels = rbuf[ 33 ];
  for ( i = 0; i < 32; i++ )
    voices[ i ].pan = rbuf[ 34 + i ];

#ifdef 0
  dprintf( "\n" );
  dprintf( "version: 0x%x\n", rbuf[ 3 ] );
  dprintf( "songName: %s\n", songName );
  dprintf( "saved tracks: %i, last pattern: %i, last order: %i\n", tracks, lastPat, songMaxOrder );
  dprintf( "extra len: %i, instruments: %i, channels: %i\n", extraLen, songInstr, songChannels );
  dprintf( "beats: %i\n", beats );
#endif

  if ( fread( rbuf, songInstr * 37, 1, file ) != 1 )
    fatal( "loadMTM: instruments info read" );
  ptr = rbuf;
  for ( i = 0; i < songInstr; i++ )
    {
      struct INSTR *is = newInstrument( i );
      struct SAMPLE *smp = newSample( i, 0 );

      strncpy( is -> name, ptr, 22 ); is -> name[ 22 ] = 0; 
      strncpy( smp -> name, ptr, 22 ); smp -> name[ 22 ] = 0;
      ptr += 22;
      smp -> length = ptr[ 0 ] | ( ptr[ 1 ] << 8 ) |
      		     ( ptr[ 2 ] << 16 ) | ( ptr[ 3 ] << 24 ); ptr += 4;
      smp -> lstart = ptr[ 0 ] | ( ptr[ 1 ] << 8 ) |
      		     ( ptr[ 2 ] << 16 ) | ( ptr[ 3 ] << 24 ); ptr += 4;
      smp -> lend =   ptr[ 0 ] | ( ptr[ 1 ] << 8 ) |
      		     ( ptr[ 2 ] << 16 ) | ( ptr[ 3 ] << 24 ); ptr += 4;
      smp -> freqC4 = palFreq ? PAL_FREQ : NTSC_FREQ;
      smp -> finetune = finetuneTable[ *(ptr++) & 0x0f ];
      if ( smp -> lend < 4 || smp -> lstart > smp -> lend )
        smp -> lend = smp -> lstart = 0;
      smp -> volume = *(ptr++);
      smp -> type = SMP_TYPE_UNSIGNED;
      smp -> ident = -1;
      is -> used = smp -> used = smp -> length > 0;
      if ( *ptr & 1 )
        fatal( "loadMTM: 16-bit sample" );
      ptr++;
    }
  if ( fread( rbuf, 128, 1, file ) != 1 )
    fatal( "loadMTM: pattern order" );

  for ( i = 0; i <= songMaxOrder; i++ )
    songOrder[ i ] = rbuf[ i ];

  for ( i = 0; i <= lastPat; i++ )
    {
      fseek( file, 194 + ( songInstr * 37 ) + ( tracks * 192 ) + ( 32 * 2 * i ), SEEK_SET );
      if ( fread( &rbuf[ 128 ], 32 * 2, 1, file ) != 1 )
        fatal( "loadMTM: track order read" );
      for ( chn = 0; chn < songChannels; chn++ )
        {
          trkPtr = rbuf[ 128 + ( chn * 2 ) ] |
                   ( rbuf[ 129 + ( chn * 2 ) ] << 8 );
          if ( trkPtr )
            {
              trkPtr--;
              fseek( file, 194 + ( songInstr * 37 ) + ( trkPtr * 192 ), SEEK_SET );
#ifdef 0
              dprintf( "track pos: 0x%x\n", (int)ftell( file ) );
#endif
              if ( fread( &rbuf1[ chn * 192 ], 192, 1, file ) != 1  )
                fatal( "loadMTM: track read" );
            }
           else
            {
              memset( &rbuf1[ chn * 192 ], 0, 192 );
#ifdef 0
              dprintf( "skipped\n" );
#endif
            }
        }
      convInitPattern();
      for ( row = 0; row < beats; row++ )
        {
          convInitRow();
          for ( chn = 0; chn < songChannels; chn++ )
            {
              byte pitch, instr, volume = 255, eff, arg;

#ifdef 0
              if ( chn > 1 ) continue; 
#endif
              ptr = &rbuf1[ ( chn * 192 ) + row * 3 ];
              pitch = *ptr >> 2;
              instr = ( ( *ptr & 3 ) << 4 ) | ( *(ptr + 1) >> 4 );
              eff = *(ptr + 1) & 0x0f;
              arg = *(ptr + 2);
#ifdef 0
              dprintf( "row: %i, chn: %i, pitch: %i, instr: %i, eff: 0x%x, arg: 0x%x\n",
              			row, chn, pitch, instr, eff, arg );
#endif
              if ( pitch || instr || eff || arg )
                {
                  if ( pitch ) pitch += 24; else pitch = 255;
                  if ( instr ) instr--; else instr = 255;
		  if ( eff == MEF_VOLUME )
		    {
		      volume = arg;
		      if ( volume == 255 ) volume--;
		      eff = arg = 0;
		    }
                  translateModEffect( &eff, &arg );
                  if ( eff == 0x7f )
                    dprintf( "\nloadMTM: wrong or unimplemented effect (0x%x/0x%x)\n",
                            *(ptr + 1) >> 4, *(ptr + 2) );
                  convAddNote( chn,
                               instr,
                               pitch,
                               volume,
                               eff,
                               arg,
                               0, 0 );
                }
            }                    
          convDoneRow();
        }
      convDonePattern();
    }
  fseek( file, 194 + ( songInstr * 37 ) + ( tracks * 192 ) + 
               ( ( lastPat + 1 ) * 32 * 2 ) + extraLen, SEEK_SET );
#ifdef 0
  dprintf( "first instr: 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;
      }
  free( rbuf );
  free( rbuf1 );
  pprintf( "Done.\n" );

  songPlaySpeed = 6;
  songTempo = 125;
  songGlobalVolume = 128;
  currentPalFreq = palFreq;
#if 0
  if ( freqType == FTYPE_NOTHING ) freqType = FTYPE_AMIGA;
#else
  if ( freqType == FTYPE_NOTHING ) freqType = FTYPE_LINEAR;
#endif
}
