#ifndef __CSMFPLAY_HPP__
#define __CSMFPLAY_HPP__
#include <vector>
#include "CSMF.hpp"
#include "CMIDIModule.hpp"

namespace dsa {

class CSMFPlay {
  static const int MAX_PORTNUM = 4;
  static const int MAX_THREADS = 16;
  CSMF m_smf;
  CMIDIModule **m_modules;

  std::vector<CSMFEvent> m_events;
  int    m_mods;         //設定の NumDevices の 2倍
  int    m_threads;      //m_mods/2 より大きくしても m_mods/2 に制限される
  bool   m_bEnableOPLL;  
  bool   m_bEnableSCC;
  bool   m_bEnablePSGDrum;
  int    m_cur_idx;       //現在再生中の MIDI イベントのインデックス番号
  int    m_cur_port;      //現在の使用ポート
  int    m_port_num;      //使用ポート数
  int    m_rate;          //再生周波数
  int    m_loop_point;    //ループポイントのインデックス番号(ない場合は -1)
  DWORD  m_dwCurSample;   //現在の再生位置
  DWORD  m_dwEndSample;   //最後の MIDI イベント送信以降に再生したサンプル数
  DWORD  m_dwSilentSample;//無音再生時間
  struct THREAD_INFO{
      CSMFPlay    *pThis;
      int          Channels[17];
      int         nChannels;//↑のうち有効なチャンネルの数
      HANDLE       hThread;   //m_ThreadInfo[0].hThread は常に NULL
      HANDLE       hEvent;    //m_ThreadInfo[0].hEvent  は常に NULL
      DWORD        dwThreadId;//m_ThreadInfo[0].dwThreadId は常に 0
  }; 
  THREAD_INFO m_ThreadInfo[MAX_THREADS];

  void CreateRenderThreads(void);
  void TerminateRenderThreads(void);

  static unsigned __stdcall ThreadProc(void* pRederParam);
  static DWORD RenderToChannel(CSMFPlay *pThis, double *buf, DWORD length, int Channels[17], int nChannels, 
                      int *pNewIdx, int *pNewPort, DWORD *pdwNewCurSample);

public:  
  CSMFPlay(DWORD rate, bool bEnableOPLL, bool bEnableSCC, bool bEnablePSGDrum, int mods, int threads);
  ~CSMFPlay(void);
  bool Open(const BYTE *data, DWORD data_length);//{return m_smf.Load((const char*)data, data_length);}
  bool IsLoopMIDI(void)const{return m_loop_point >= 0;}
  DWORD Render(double *buf, DWORD length);
  void  Start(void);
  double GetDuration(void)const;
};

} // namespace dsa

#endif
