// -*-C++-*-
// This file is part of the gmod package
// Copyright (C) 1997 by Andrew J. Robinson

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>

#ifdef USE_LOCAL
#include "soundcard.h"
#else
#include <sys/soundcard.h>
#endif

#include <sys/ultrasound.h>

#include "commands.h"
#include "defines.h"
#include "structs.h"
#include "globals.h"
#include "protos.h"

#include "Six69.h"

int
load_669_module(FILE * modFd, struct songInfo *songChar,
		struct optionsInfo options, unsigned char *buffer)
{
  extern Sample *samples[];
  extern Sequencer *seq;

  int i;
  int samplePtr;
  int position;
  int voice;
  unsigned char *tunePtr, *lenPtr, *tempoPtr;	/* array 0-127 */
  unsigned char header[0x1f1];	/* changed from 1084 */
  unsigned char *sampleInfox;
  int nrSamples;		/* 16 or 32 samples */
  int slen, npat;
  int formatVersion = 0;

  memcpy (header, buffer, HDR_SIZE);

  if (fread(header + HDR_SIZE, 1, sizeof(header) - HDR_SIZE, modFd) !=
      sizeof(header) - HDR_SIZE)
    {
      /* short file (header) */
      return 0;
    }

  if (INTEL_SHORT(header) != 0x6669)
    formatVersion = 1;

  songChar->comment = (char *)realloc(songChar->comment, 109);
  bzero(songChar->comment, 109);
  strncpy(songChar->comment, header + 2, 108);
  songChar->commentLineLen = 36;
  npat = header[0x6f];
  songChar->nrPatterns = npat;
  tunePtr = &header[0x71];

  for (slen = 0; slen < 128 && tunePtr[slen] != 0xff; slen++);

  for (i = 0; i < slen; i++)
    tune[i] = tunePtr[i];

  lenPtr = &header[0x171];

  for (i = 0; i < 0x80; i++)
    patternLen[i] = lenPtr[i] + 1;

  tempoPtr = &header[0xf1];

  for (i = 0; i < slen; i++)
    patternTempo[i] = tempoPtr[i];

  nrSamples = header[0x6e];

  if ((sampleInfox = (unsigned char *)malloc(nrSamples * 0x19)) == NULL)
    {
      /* Could not allocate memory for sample information */
      return 0;
    }

  if (fread(sampleInfox, 1, nrSamples * 0x19, modFd) != (nrSamples * 0x19))
    {
      /* Could not read sample information */
      free(sampleInfox);
      return 0;
    }

  songChar->nrSamples = nrSamples;
  songChar->nrTracks = npat * 8;
  songChar->songlength = slen;
  songChar->nrChannels = 8;
  songChar->lowestNote = 36;
  songChar->highestNote = 99;
  songChar->playSpeed = 4;
  songChar->tempo = 75;
  songChar->volType = VOL_LINEAR;
  songChar->volOnZero = MY_FALSE;
  songChar->slideType = SLIDE_FREQ_LIN;
  songChar->clockSpeed = 60;
  strcpy (songChar->desc, "669");

  for (position = 0; position < npat; position++)
    {
      unsigned char patterns[0x600];
      int pat, channel, x;

      /*
	 int pp = 0x1f1 + (nrSamples * 0x19) + (position * 0x600);
	 */

      for (voice = 0; voice < songChar->nrChannels; voice++)
	if ((patternTable[position * songChar->nrChannels + voice] =
	     (struct noteInfo *) malloc (sizeof (struct noteInfo) * 64)) ==
	    NULL)
	  {
	    /* Can't allocate memory for a pattern */
	    free(sampleInfox);
	    return 0;
	  }

      if ((x = fread(patterns, 1, 0x600, modFd)) != 0x600)
	{
	  /* Short file */
	  free(sampleInfox);
	  return 0;
	}

      for (pat = 0; pat < 64; pat++)
	{

	  for (channel = 0; channel < 8; channel++)
	    {
	      unsigned char *p;

	      unsigned vol, period, sample, effect, params;
	      unsigned effect1 = 0, effect2 = 0, parm1 = 0, parm2 = 0;

	      p = &patterns[pat * 24 + channel * 3];

	      if (p[0] >= 0xfe)
		{
		  sample = 0;
		  period = 0;
		}
	      else
		{
		  period = (p[0] >> 2) + 36;	/* AJR:  changed from 48 */
		  sample = (((p[0] << 4) & 0x30) | ((p[1] >> 4) & 0x0f)) + 1;
		}

	      effect = (p[2] >> 4);
	      params = p[2] & 0x0f;
	      vol = (p[1] & 0x0f) * 17;

	      if (period)
		{
		  effect1 = CMD_VOLUME;
		  parm1 = vol;
		}

	      if (p[0] == 0xfe)
		{
		  effect1 = CMD_VOLUME;
		  parm1 = vol;
		}

	      if (p[2] == 0xff)
		{
		  effect2 = CMD_NOP;
		}
	      else
		switch (effect)
		  {
		  case 0:	/* a - Portamento up */
		    parm2 = params * SLIDE_RATE_669;
		    if (parm2 == 0)
		      effect2 = 0;
		    else
		      effect2 = CMD_SLIDEUP;
		    break;

		  case 1:	/* b - Portamento down */
		    parm2 = params * SLIDE_RATE_669;
		    if (parm2 == 0)
		      effect2 = 0;
		    else
		      effect2 = CMD_SLIDEDOWN;
		    break;

		  case 2:	/* c - Port to note */
		    parm2 = params * SLIDE_RATE_669;
		    if (parm2 == 0)
		      effect2 = 0;
		    else
		      effect2 = CMD_SLIDETO;
		    break;

		  case 3:	/* d - Frequency adjust */
		    parm2 = params * SLIDE_RATE_669;
		    if (parm2 == 0)
		      effect2 = 0;
		    else
		      effect2 = CMD_FINEPORTUP;
		    break;

		  case 4:	/* e - Frequency vibrato */
		    parm2 = 0x70 || params;
		    if (parm2 == 0x70)
		      effect2 = 0;
		    else
		      effect2 = CMD_VIBRATO;
		    break;

		  case 5:	/* f - Set tempo */
		    if ((params == 0) && (formatVersion == 1))
		      parm2 = 1;
		    else
		      parm2 = params;
		    if (parm2 == 0)
		      effect2 = 0;
		    else
		      effect2 = CMD_SET_TICKS;
		    break;

		  default:
		    effect2 = 0;
		    parm2 = 0;
		  }

	      if (period)
		if (period < songChar->lowestNote)
		  period = songChar->lowestNote;
		else if (period > songChar->highestNote)
		  period = songChar->highestNote;

	      voice = position * songChar->nrChannels + channel;
	      voiceTable[position][channel] = voice;

	      (patternTable[voice])[pat].note = period;
	      (patternTable[voice])[pat].sample = sample;
	      (patternTable[voice])[pat].command[0] = effect1;
	      (patternTable[voice])[pat].parm1[0] = parm1;
	      (patternTable[voice])[pat].parm2[0] = 0;
	      (patternTable[voice])[pat].command[1] = effect2;
	      (patternTable[voice])[pat].parm1[1] = parm2;
	      (patternTable[voice])[pat].parm2[1] = 0;
	    }

	}

      if (options.compress)
	for (channel = 0; channel < songChar->nrChannels; channel++)
	  voiceTable[position][channel] =
	    compressVoice(voiceTable[position][channel],
			   voiceTable[position][channel],
			   64, 1);
    }

  samplePtr = 0x1f1 + (nrSamples * 0x19) + (npat * 0x600);	/* Location where the
								 * first sample is
								 * stored */
  // totalMem = 0;

  for (i = 0; i < nrSamples; i++)
    {
      samples[i] = new Six69_sample;
      samples[i]->load(*seq, modFd, i, 1, &sampleInfox[i * 0x19]);
    }

  /* set panning */

  for (i = 0; i < songChar->nrChannels; i++)
    if ((i % 2) == 0)
      songChar->panning[i] = 0;
    else
      songChar->panning[i] = 255;

  free(sampleInfox);
  return 1;
}
