#pragma once

#include "kpi_decoder.h"
#include "kpi_impl.h"
#include "sequencer.hpp"
#include "midisynth.hpp"

class KbFmMidiDecoder : public KbKpiUnknownImpl<IKpiDecoder>, public output
{
private:
    struct kbfmmidi_File
    {
        BYTE *pBuffer;
        DWORD dwSize;
        DWORD dwPointer;
    };

    KPI_MEDIAINFO m_MediaInfo;
    enum{
        MAX_NUM_PORTS = 4
    };
    fm_note_factory m_note_factory;
    synthesizer     m_synthesizer;
    sequencer       m_sequencer;
    synthesizer*    m_synthesizers[MAX_NUM_PORTS];
    double m_dLoopPoint;//ループポイント(見つかってない場合は -1.0)
    int    m_nNumPorts;
    UINT64 m_qwCurrentSample;
    UINT64 m_qwLastSample;
    DWORD  m_dwEndSample;   //MIDI 解析終了後に再生したサンプル数
    DWORD  m_dwSilentSample;//解析終了後の無音再生時間

    bool   m_bLoop;   //ループポイントに戻った直後の状態のとき true
    bool   m_bSeeking;//シーク中は true

    void __fastcall Close(void);
    static int kbfmmidi_getc(void *fp);
    void midi_message(int port, uint_least32_t message);
    void sysex_message(int port, const void* data, size_t size);
    void meta_event(int type, const void* data, size_t size);
    void reset();
public:
    KbFmMidiDecoder(void);
    ~KbFmMidiDecoder(void);
    DWORD __fastcall Open(const KPI_MEDIAINFO *cpRequest,
                          IKpiFile *pFile,
                          IKpiFolder *pFolder);
    DWORD  WINAPI Select(DWORD dwNumber,
                         const KPI_MEDIAINFO **ppMediaInfo,
                         IKpiTagInfo *pTagInfo,
                         DWORD dwTagGetFlags);
    UINT64 WINAPI Seek(UINT64 qwPosSample, DWORD dwFlag);
    DWORD  WINAPI Render(BYTE *pBuffer, DWORD dwSizeSample);
    DWORD  WINAPI UpdateConfig(void *pvReserved){return 0;}
};
