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

#ifdef AWE_SUPPORT
#include <stdlib.h>
#include <sys/ultrasound.h>
#include <linux/awe_voice.h>

#include "defines.h"
#include "structs.h"

#include "defines.h"
#include "Sample.h"
#include "VoiceAWE.h"

void syncTime();

int
VoiceAWE::doPreUpdates(int dev)
{
  SEQ_DECLAREBUF();


  if (!delayCount_)
    {
      if (whatChanged_ & (NOTE_CHANGED | OFFSET_CHANGED))
	{
	  syncTime();
	  SEQ_STOP_NOTE(dev, channel_, 0, 127);
	  return 1;
	}
    }

  return 0;
}

void
VoiceAWE::doUpdates(int dev)
{
  SEQ_DECLAREBUF();

  if (!delayCount_)
    {
      if (whatChanged_ & (SAMPLE_CHANGED | PAN_CHANGED | OFFSET_CHANGED |
			  KEY_CHANGED))
	syncTime();

      if (whatChanged_ & SAMPLE_CHANGED)
	SEQ_SET_PATCH(dev, channel_, sample_->number());

      if (whatChanged_ & PAN_CHANGED)
	{
	  int panVal;
	  
	  panVal = pan_ + (envelopePan_ - 32) * (128 - abs(128 - pan_)) / 32;
	  
	  if (panVal > 255)
	    panVal = 255;
	  else if (panVal < 0)
	    panVal = 0;
	  
	  if (panFactor_ != 100)
	    {
	      panVal -= 128;
	      panVal = (panVal * panFactor_) / 100;
	      panVal += 128;
	    }

	  SEQ_CONTROL(dev, channel_, CTL_PAN, panVal); 

	  if (!(whatChanged_ & NOTE_CHANGED))
	    {
	      panVal = ((panVal * 2) - 240) / 32 + 7;
	      GUS_VOICEBALA(dev, channel_, panVal);
	    }
	}

      if (whatChanged_ & OFFSET_CHANGED)
	{
	  SEQ_START_NOTE(dev, channel_, note_, 0);
	  GUS_VOICE_POS(dev, channel_, offset_);
	  lastVol_ = 0;
	  startNote(dev, 255);
        }
      else if (whatChanged_ & NOTE_CHANGED)
	startNote(dev, note_);
      else if (whatChanged_ & VOL_CHANGED)
	startNote(dev, 255);

      if (whatChanged_ & BEND_CHANGED)
	{
	  int bend = pitchbender_ + vibraBend_ + arpegBend_ + finetune_;

	  if (bend != lastBend_)
	    {
	      lastBend_ = bend;
	      syncTime();
	      SEQ_BENDER(dev, channel_, bend + 8192);
	    }
	}

      if (whatChanged_ & KEY_CHANGED)
	{
	  SEQ_STOP_NOTE(dev, channel_, 0, 127);
	}
      
      whatChanged_ = 0;
    }
}

void
VoiceAWE::startNote(int dev, int note)
{
  SEQ_DECLAREBUF();
  int vol;

  if (flagVol_)
    vol = 0;
  else
    {
      vol = ((((volume_ * envelopeVol_) / 64) + tremoloVol_) *
	     mainVolume_) / 255;
  
      if (vol > 255)
	vol = 255;
      else if (vol < 0)
	vol = 0;
    }

  if ((note != 255) || (vol != lastVol_))
    {
      lastVol_ = vol;
      
      if (volType_ == VOL_LOG)
	{
	  int newVolume;
	  unsigned char bits;
	  
	  bits = (vol & 0xf0) >> 4;
	  newVolume = 1 << bits;
	  vol &= 0x0f;
	  if (bits >= 4)
	    {
	      newVolume |= (vol << (bits - 4));
	      for (bits -= 4; bits > 0; bits--)
		newVolume |= (1 << (bits - 1));
	    }
	  else
	    newVolume |= (vol >> (4 - bits));
	  
	  vol = (unsigned char)(newVolume / 256);
	}
      else
	vol /= 2;
      
      syncTime();
      SEQ_CONTROL(dev, channel_, CTL_EXPRESSION, vol << 7);
      SEQ_START_NOTE(dev, channel_, note, 127);
    }
}

#endif
