// GuruGuruSMF ver.4.0.0 ヘッダ(C++スタイル)

#ifndef _GURUGURUSMF4H_
#define _GURUGURUSMF4H_

#include <windows.h>

namespace GuruGuruSmf {

    namespace PlayOption
    {
        const int Loop = 1;         // ループ再生する
        const int SkipBeginning = 2;    // 冒頭の空白をスキップ
        const int SkipEnding = 4;       // 末尾の空白をスキップ
        const int MasterPitch = 8;      // マスターピッチを有効にする
        const int Normalize = 16;       // 最大音量を127に引き上げる
        const int Exclusive = 32;       // エクスクルーシブを送信する
    }

    namespace LoadOption
    {
        const int Buffered = 1;     // データを内部に保持するか
    }

    namespace Device
    {
        const int DirectMusic = -1100;              // DirectMusic Portモード
    }

    namespace GgsError {
        enum Code {
            NoError,            // エラーなし
            Failed,             // なんだかよくわからないけど失敗
            FileNotFound,       // ファイルが存在しない
            CannotOpenFile,     // ファイルが開けない
            FileLoadFailed,     // ファイル読み込みに失敗
            BadFileSize,        // ファイルサイズが不正
            NoSmf,              // SMFではありません
            BadSmf,             // 不正なSMF
            UnmatchedSmf,       // 未対応のSMF
            CannotOpenDevice,   // デバイスが開けない
            CannotStartTimer,   // タイマーが開始できない
            IllegalPointer,     // 範囲外を参照しようとした
            TrackLimit,         // メッセージの途中でトラックが終端に達した
            NotReady,           // 演奏可能ではない
            UndefinedId,        // 未定義のID
            ApiNull             // APIが有効でない
        };
    }
    typedef GgsError::Code GGSERROR;

    namespace PlayerState {
        enum Code {
            Stop,       // 停止中
            Play,       // 演奏中
            Pause       // 一時停止中
        };
    }
    typedef PlayerState::Code PLAYERSTATE;

    struct PlayerStatus
    {
        PLAYERSTATE State;
        int Tempo;
        int Tick;
        int Time;
        int LoopCount;
    };

    struct SmfInformation
    {
        int TimeBase;       // ベースカウント
        int TotalTick;      // 総Tick
        int TotalTime;      // 総演奏時間
        int FirstNoteTick;  // 最初の発音tick
        int FirstNoteTime;  // 最初の発音の時間
        int LastNoteTick;   // 最後の発音tick
        int LastNoteTime;   // 最後の発音の時間
        int LoopTick;       // CC#111の位置
        int LoopTime;       // CC#111の位置の時間
    };

    struct SmfListKeys
    {
        int Count;      // キーの数
        int* Keys;      // キーのリスト
    };

//α版対応
    // GGSコントローラーのインターフェイス
    // Core/Interface.h より(呼び出し規約を WINAPI に変更)
    struct IGgsController
    {
        // オブジェクトを破棄
        virtual void WINAPI Release(void) = 0;

        // デバイスを開く
        virtual GGSERROR WINAPI OpenDevice(int deviceId) = 0;
        // DirectMusicモードで開く
        virtual GGSERROR WINAPI OpenDirectMusic(void* buffer8, int maxvoice) = 0;
        // デバイスを閉じる
        virtual void WINAPI CloseDevice(void) = 0;
        // DLSを追加(Unicode)
        virtual GGSERROR WINAPI AddDlsW(LPCWSTR fileName) = 0;
        // DLSを追加(ANSI)
        virtual GGSERROR WINAPI AddDlsA(LPCSTR fileName) = 0;
        // DLSリストをクリア
        virtual void WINAPI ClearDls(void) = 0;
        // 演奏！
        virtual GGSERROR WINAPI Play(int option, int musicId, int seek, int fadeInTime, int keyShift) = 0;
        // 演奏停止
        virtual void WINAPI Stop(int fadeOutTime) = 0;
        // 一時停止
        virtual void WINAPI Pause(void) = 0;
        // 一時停止解除
        virtual void WINAPI Restart(void) = 0;
        // マスターテンポ
        virtual void WINAPI SetMasterTempo(float tempo) = 0;
        // マスターボリューム
        virtual void WINAPI SetMasterVolume(int volume) = 0;
        // マスターボリューム(DirectSound)
        virtual void WINAPI SetMasterVolumeDS(int volume) = 0;
        // マスターピッチ
        virtual void WINAPI SetMasterPitch(int pitch) = 0;
        // 演奏状態を取得
        virtual void WINAPI GetPlayerStatus(PlayerStatus* status, int size) = 0;
        // リストにファイルからSMFを追加(Unicode)
        virtual GGSERROR WINAPI AddListFromFileW(LPCWSTR fileName, int option, int musicId) = 0;
        // リストにファイルからSMFを追加(ANSI)
        virtual GGSERROR WINAPI AddListFromFileA(LPCSTR fileName, int option, int musicId) = 0;
        // リストにメモリからSMFを追加
        virtual GGSERROR WINAPI AddListFromMemory(const byte* smfBinary, int length, int option, int musicId) = 0;
        // リスト内のアイテムを1つ削除
        virtual void WINAPI DeleteListItem(int musicId) = 0;
        // リストをクリア
        virtual void WINAPI ClearList(void) = 0;
        // リスト内のIDを列挙
        virtual const SmfListKeys* WINAPI EnumList(void) = 0;
        // SMFの情報を取得
        virtual GGSERROR WINAPI GetSmfInformation(SmfInformation* info, int size, int musicId) = 0;
    };
    // GGSコントローラーのインターフェイス(ver.0.3.x)
    // SmfInformation3 => void に変更(使わないので支障なし)
    struct IGgsController3 : public IGgsController
    {
        // 一時停止/解除
        virtual void WINAPI PauseRestart(void) = 0;
        // マスターテンポ
        virtual void WINAPI SetMasterTempo3(int tempo) = 0;
        // 演奏状態を取得
        virtual void WINAPI GetPlayerStatus3(void/*PlayerStatus3*/* status) = 0;
        // リストにファイルからSMFを追加
        virtual GGSERROR WINAPI AddListFromFile3(LPCSTR fileName, int option, int musicId) = 0;
        // リストにメモリからSMFを追加
        virtual GGSERROR WINAPI AddListFromMemory3(const byte* smfBinary, int length, int option, int musicId) = 0;
        // リスト内のIDを列挙して文字列化
        virtual const char* WINAPI EnumListToString(void) = 0;
        // SMFの情報を取得
        virtual GGSERROR WINAPI GetSmfInformation3(void/*SmfInformation3*/* info, int musicId) = 0;
    };
	typedef IGgsController3* HGGS;
//α版対応ここまで

    class Ggs4
    {
    private:
        static Ggs4* instance;
        static int instance_count;
        Ggs4(){ggs=NULL; hGgs = NULL; instance_count++;}
        Ggs4(void*p){ggs=p; hGgs = NULL; instance_count++;}
        Ggs4(HGGS hggs){ggs=NULL; hGgs = hggs; instance_count++;}
        Ggs4(const Ggs4&);
        Ggs4& operator =(const Ggs4&);
        ~Ggs4();
        void *ggs;
        HGGS  hGgs;//α版対応
    public:
        GGSERROR OpenDevice(int deviceId, HWND handle);
        void CloseDevice();
        GGSERROR AddDlsW(LPCWSTR fileName);
        GGSERROR AddDlsA(LPCSTR fileName);
        GGSERROR Play(int option, int musicId, int seek, int fadeInTime, int keyShift);
        void Stop(int fadeOutTime);
        void Pause();
        void Restart();
        void SetMasterTempo(float tempo);
        void SetMasterVolume(int volume);
        void SetMasterPitch(int pitch);
        void GetPlayerStatus(PlayerStatus* status);
        GGSERROR AddListFromFileW(LPCWSTR fileName, int option, int musicId);
        GGSERROR AddListFromFileA(LPCSTR fileName, int option, int musicId);
        GGSERROR AddListFromMemory(LPCBYTE smfBinary, int length, int option, int musicId);
        void DeleteListItem(int musicId);
        void ClearList();
        const SmfListKeys* EnumList();
        GGSERROR GetSmfInformation(SmfInformation* info, int musicId);

        static GGSERROR Initialize(const wchar_t *dllpath);
        static Ggs4* CreateInstance(void);
        void DeleteInstance(){delete this;}
        static void UnloadDll();
        static bool IsMultipleInstance();
    };

}

//#define GGS GuruGuruSmf::Ggs4::GetInstance()
#define GGSINITIALIZE GuruGuruSmf::Ggs4::Initialize
#define GGSFREE GuruGuruSmf::Ggs4::FreeInstance
#define GGSUNLOAD GuruGuruSmf::Ggs4::UnloadDll

#endif

