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

#ifndef SequencerH_
#define SequencerH_

#include <sys/ioctl.h>
#include <sys/soundcard.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>

#ifdef USE_X
#include <qapp.h>
#include <qsocknot.h>
#endif

#include "Voice.h"

struct OutBuffer;
class Sample;
struct songInfo;
struct optionsInfo;

template<class T> class deque;

class Sequencer
#ifdef USE_X
  : public QObject
#endif
{
#ifdef USE_X
  Q_OBJECT
#endif

public:
  Sequencer();
  ~Sequencer();

  int bufferSize() const;
  void close() const { ::close(seqfd_); };
  int doCommand(int, int, int, int, int, songInfo *, optionsInfo *);
  int doTick(int chan, int tick, songInfo *s)
  { return voices_[chan].doTick(gusDev_, tick, s); };
  void doUpdates(int chan) { voices_[chan].doUpdates(gusDev_); };
  void dump();
  void force();
  int memory() const;
  void numVoices(int, int, const Sample *);
  int open();
  void panFactor(int factor);
  int patchLoad(FILE *, int, Sample &, int &, int) const;
  int read(char *) const;
  void resetSamples() const;
  void stopPlayback();
  void sync() const;
  int write();

  // The following functions provide access to the sequencer voices.  They
  // will be removed once the sequencer does the command processing.
  void mainVolume(int vol);
  void globalVolSlide(int amt);
  void pan(int chan, int amt) { voices_[chan].pan(amt); }
  void sample(int chan, Sample *s) { voices_[chan].sample(s); }
  void keyOff(int chan) { voices_[chan].keyOff(); }
  void note(int chan, int n, int t) { voices_[chan].note(n, t); }
  void resetEffects(int chan, int p) { voices_[chan].resetEffects(p); }

  // The following function provides access to the sequencer file descriptor.
  // It will be removed later.
  int seqFd() const { return seqfd_; };

#ifdef USE_X
  void readEnabled(bool);
  void writeEnabled(bool);
#endif

private:
  int gusDev_;
  int numVoices_;
  int seqfd_;
  int songFinished_;
  int synthType_;
  Voice *voices_;

  // bufferList is a pointer so deque.h doesn't need to be included
  deque<OutBuffer *> *bufferList;

#ifdef USE_X
  QSocketNotifier *writeNotifier_;
  QSocketNotifier *readNotifier_;

 private slots:
 void writeReady();
  void readReady();
  
#endif
};

inline void
Sequencer::globalVolSlide(int amt)
{
  for (int i = 0; i < numVoices_; i++)
    voices_[i].globalVolSlide(amt);
}

inline void
Sequencer::mainVolume(int vol)
{
  for (int i = 0; i < numVoices_; i++)
    voices_[i].mainVolume(vol);
}

inline int
Sequencer::memory() const
{
  int memory;

  memory = gusDev_;
  ioctl(seqfd_, SNDCTL_SYNTH_MEMAVL, &memory);

  return (memory);
}

inline void
Sequencer::panFactor(int factor)
{
  for (int i = 0; i < numVoices_; i++)
    voices_[i].panFactor(factor);
}

inline int
Sequencer::read(char *inbuf) const
{
  return (::read(seqfd_, inbuf, 4));
}

#ifdef USE_X
inline void
Sequencer::readEnabled(bool status)
{
  readNotifier_->setEnabled(status);
}
#endif

inline void
Sequencer::resetSamples() const
{
  ioctl(seqfd_, SNDCTL_SEQ_RESETSAMPLES, &gusDev_);
}

inline void
Sequencer::sync() const
{
  ioctl(seqfd_, SNDCTL_SEQ_SYNC, 0);
}

#ifdef USE_X
inline void
Sequencer::writeEnabled(bool status)
{
  writeNotifier_->setEnabled(status);
}
#endif

#endif
