//=============================================================================
//! @file
//! @brief  Standard MIDI File (SMF) 読み取り
//! @author Yoshi.
//=============================================================================

#ifndef INCLUDED_SMF_LOADER_H_
#define INCLUDED_SMF_LOADER_H_
#include <vector>
//-----------------------------------------------------------------------------
//! @brief  SMFデータ読み込み
//-----------------------------------------------------------------------------
class SmfLoader
{
public:
    //! @brief  メタデータのテキスト最大長
    static const int METATEXT_MAXLEN = 255;

    //! @brief  トラック終了MIDIメッセージ
    static const int END_OF_TRACK = 0x80000000;//最上位ビットが 1
    //! @brief  システムエクスクルーシブ
    static const int SYS_EX = 0xc0000000;//最上位と2番目のビットが 1 (11000000000000000000000000000000)
    static const int SYS_EX_ALL_PORT = SYS_EX + 1;  //全ポートに送信すべき SysEx

    //! @brief  フォーマット
    enum SmfFormat
    {
        SMF_FORMAT_0,   //!< SMF Format0
        SMF_FORMAT_1,   //!< SMF Format1
        SMF_FORMAT_2,   //!< SMF Format2
    };

    //! @brief  音源のリセット種類
    enum ResetType
    {
        RESET_TYPE_GM1, //!< GM (デフォルト)
        RESET_TYPE_GM2, //!< GM2
        RESET_TYPE_XG,  //!< Yamaha XG系
        RESET_TYPE_GS,  //!< Roland GS系
    };
    //! @brief  読み込み時の設定
    struct LoadOption
    {
        bool    ignore_bank_select;     //!< バンクセレクトを無視する
        bool    detect_reset_type;      //!< 音源リセットタイプを確定する
    };

    //! @brief  MIDIメッセージ
    struct MidiMessage
    {
        __int64 time_smp;// サンプル単位の絶対時間
        int data;   // メッセージデータ(END_OF_TRACK or SYS_EX or other)
                    // (最上位8ビットが 0 のときが通常の MIDI イベント)
        int port;   // ポート番号
        std::vector<unsigned char> sysex_dump;//data==SYS_EXのときだけ有効
    };

public:
    SmfLoader();
    ~SmfLoader();

    //! @brief  SMFデータを読み込む
    bool Load(const void* data, size_t size, const LoadOption& option, int rate);

    //! @breif  読み込んだデータをクリアする
    void Clear();

    //! @brief  再生するMIDIメッセージ数取得
    int GetMidiMessageNum() const;

    //! @brief  指定インデックスのMIDIメッセージ取得
    const MidiMessage& GetMidiMessage(int index) const;

    //! @brief  音源リセットメッセージ取得
    //! @note   読み込み時の設定で、音源リセットタイプを決める設定にする必要あり
    const void* GetResetMessageData() const;
    static const void* GetResetMessageData(SmfLoader::ResetType type);
    //! @brief  音源リセットメッセージのバイト数取得
    int GetResetMessageSize() const;
    static int GetResetMessageSize(SmfLoader::ResetType type);

    //! @brief  音源リセットタイプを取得
    ResetType GetResetType() const;

    //! @brief  SMFフォーマット取得
    SmfFormat GetSmfFormat() const;

    //! @brief  トラック数取得
    int GetTrackNum() const;

    //! @brief  タイムベース（分解能）取得
    int GetTimeBase() const;

    //! @brief  曲の長さ取得
    __int64 GetDuration() const;

    //! @brief  ポート数取得
    int GetPortNum() const;

    //! @brief  メタデータに設定されたタイトル取得
    //const char* GetTitle() const;

    //! @brief  メタデータに設定された権利情報取得
    //const char* GetCopyright() const;
private:
    MidiMessage*    message_data_;  // MIDIメッセージデータ
    int             message_num_;   // MIDIメッセージ数
    ResetType       reset_type_;    // 音源リセットタイプ
    SmfFormat       smf_format_;    // SMFフォーマット
    int             track_num_;     // Format1のトラック数（SMF0は1固定）
    int             time_base_;     // タイムベース
    __int64         duration_;      // サンプル単位の時間
    int             port_num_;      // ポート数
    // メタデータ
    //char          title_[METATEXT_MAXLEN + 1];
    //char          copyright_[METATEXT_MAXLEN + 1];
};

#endif //INCLUDED_SMF_LOADER_H_
