// move that to EDKWin.h


#include <dsound.h>

#define mm(x) \
  { \
    MMRESULT i = (x); \
    if (i != MMSYSERR_NOERROR) { \
      char ac[1024]; \
      waveOutGetErrorText(i, ac, sizeof ac); \
      error("%s failed\nin file %s at line %d\n%s", #x, __FILE__, __LINE__, ac); \
    } \
  }

inline int bound(int iLower, int i, int iUpper) {
  if (i <= iLower) {
    return iLower;
  }
  if (i >= iUpper) {
    return iUpper;
  }
  return i;
}

extern int GetInt(const char* pcSection, const char* pcKey, int iDefault);

#include "CC64.h"

////////////////////////////////////////////////////////////////////////////////

class SoundBase : public Chip {
public:

  // destructor
  virtual ~SoundBase() {}

  // synchronize to 100% and tell whether to display the next frame or not
  virtual flag Synchronize() { return false; }

  // get description for display
  virtual const char* GetDescription() { return NULL; }

};

////////////////////////////////////////////////////////////////////////////////

class NoSound : public SoundBase {

  double dPCClocksPerC64Clock;

  int iC64Clocks;
  int iPCClocks;

public:

  // constructor
  NoSound(int iC64ClockFrequency);

  // synchronize to 100% and tell whether to display the next frame or not
  virtual flag Synchronize();

  // get description for display
  virtual const char* GetDescription();

};

////////////////////////////////////////////////////////////////////////////////

class MMSound : public SoundBase {

  SID6581* pSID;

  HWAVEOUT hwo;
  int iBuffers;
  int iBufferSize;
  int iPCClocksPerBuffer;
  const enum { iMaxBuffers = 10 };
  WAVEHDR awh[iMaxBuffers];
  int iRecordBuffer;
  int iRecordSample;

  int iSampleRate;
  int iC64ClockFrequency;
  int iClocksPerSample;
  int iSampleResolution;
  int iClockAdd;
  int iClockSum;
  int iLastClocksPerSample;

  Timer Sample;
  void OnSample();

public:

  void CleanUp();

  // destructor
  virtual ~MMSound();

  // constructor
  MMSound(SID6581* pNewSID, int iNewC64ClockFrequency, int iNewSampleRate, int iNewSampleResolution);

  // synchronize to 100% and tell whether to display the next frame or not
  virtual flag Synchronize();

  // get description for display
  virtual const char* GetDescription();

};

////////////////////////////////////////////////////////////////////////////////

class QuickSound : public SoundBase {

  SID6581* pSID;

  HWAVEOUT hwo;
  int iBufferSize;  // must be 2^x
  WAVEHDR wh;
  int iRecordPos;
  int iLatency;

  int iSampleRate;
  int iC64ClockFrequency;
  int iClocksPerSample;
  int iSampleResolution;
  int iClockAdd;
  int iClockSum;
  int iLastClocksPerSample;
  Timer Sample;
  void OnSample();

public:

  void CleanUp();

  // destructor
  virtual ~QuickSound();

  // constructor
  QuickSound(SID6581* pNewSID, int iNewC64ClockFrequency, int iNewSampleRate, int iNewSampleResolution);

  // synchronize to 100% and tell whether to display the next frame or not
  virtual flag Synchronize();

  // get description for display
  virtual const char* GetDescription();

};

////////////////////////////////////////////////////////////////////////////////

class DirectSound : public SoundBase {

  SID6581* pSID;

  HMODULE hDirectSoundLib;
  IDirectSound* pDirectSound;
  IDirectSoundBuffer* pPrimaryBuffer;

  void* pAudioPtr1;
  dword dwAudioBytes1;
  void* pAudioPtr2;
  dword dwAudioBytes2;
  byte* pbRecord;

  int iSampleRate;
  int iC64ClockFrequency;
  int iClocksPerSample;
  int iSampleResolution;
  int iClockAdd;
  int iClockSum;
  int iLastClocksPerSample;
  Timer Sample;
  void OnSample();

public:

  void CleanUp();

  // destructor
  virtual ~DirectSound();

  // constructor
  DirectSound(SID6581* pNewSID, int iNewC64ClockFrequency, int iNewSampleRate, int iNewSampleResolution, HWND hwnd);

  // synchronize to 100% and tell whether to display the next frame or not
  virtual flag Synchronize();

  // get description for display
  virtual const char* GetDescription();

};
