//sorry for the stupid C-like code... #ifndef QMPMIDIPLAY_H #define QMPMIDIPLAY_H #include #include #include #include #include #include #include #include #include #define QMP_MAIN #include "qmpcorepublic.hpp" class CMidiPlayer; class CSMFReader : public qmpFileReader { private: CMidiFile *ret; CMidiTrack *curTrack; uint32_t fmt, trk; FILE *f; bool eventdiscarded; uint32_t byteread, curt, curid; void error(int fatal, const char *format, ...); uint8_t read_u8(); uint16_t read_u16(); uint32_t read_u32(); uint32_t read_varlen(); int read_event(); void read_track(); void read_header(); uint32_t read_chunk(int is_header); public: CSMFReader(); ~CSMFReader(); CMidiFile *readFile(const char *fn); void discardCurrentEvent(); void commitEventChange(SEvent d); }; class CMidiFileReaderCollection { private: std::vector> readers; qmpFileReader *currentReader; public: CMidiFileReaderCollection(); ~CMidiFileReaderCollection(); void registerReader(qmpFileReader *reader, std::string name); void unregisterReader(std::string name); CMidiFile *readFile(const char *fn); qmpFileReader *getCurrentReader(); }; class CMidiPlayer { friend class CMidiFileReaderCollection; private: CMidiFileReaderCollection *midiReaders; CMidiFile *midiFile; std::vector> eorder; uint32_t stamps[101], notes, ecnt, maxtk; uint32_t ccstamps[101][16][135], ccc[16][135]; //0..127:cc 128:pc 129:cp 130:pb 131:tempo 132:ts 133:ks 134:pbr int32_t rpnid[16], rpnval[16]; uint16_t mute, solo; double ftime; bool sendSysEx; uint8_t chstatus[16][130];//0..127: cc 128: pc uint32_t ctempo, ctsn, ctsd, divs, cks; double dpt;//time per tick //raw tempo, timesig num., timesig den., division, keysig //thread control uint32_t tceptr, tcpaused, ct; std::mutex intmtx; std::condition_variable intcv; bool tcstop; uint32_t finished, resumed; uint32_t pbr[16], pbv[16]; //playback correction uint32_t ttick; std::chrono::high_resolution_clock::time_point ttime; std::chrono::system_clock::time_point levtt[16]; struct SMidiDev { std::string name; qmpMidiOutDevice *dev; int refcnt; }; std::vector mididev; int mappedoutput[16]; ICallBack *eventHandlerCB[16]; ICallBack *eventReaderCB[16]; ICallBack *fileReadFinishCB[16]; void *eventHandlerCBuserdata[16]; void *eventReaderCBuserdata[16]; void *fileReadFinishCBuserdata[16]; std::unordered_map> event_handlers; std::unordered_map> event_read_handlers; std::unordered_map> file_read_finish_hooks; int event_handlers_id, event_read_handlers_id, file_read_finish_hooks_id; static CMidiPlayer *ref; SEvent *getEvent(uint32_t id); void dumpFile(); void setBit(uint16_t &n, uint16_t bn, uint16_t b); bool processEvent(const SEvent *e); void processEventStub(const SEvent *e); void prePlayInit(); void playEvents(); void fileTimer1Pass(); void fileTimer2Pass(); public: CMidiPlayer(); ~CMidiPlayer(); bool playerLoadFile(const char *fn); void playerInit(); void playerDeinit(); void playerThread(); void playerPanic(bool reset = false); //playing control methods uint32_t getStamp(int id); uint32_t getTCeptr(); void setTCeptr(uint32_t ep, uint32_t st); uint32_t getTCpaused(); void setTCpaused(uint32_t ps); void interrupt(); uint32_t isFinished(); bool stopFlag(); void setResumed(); double getFtime(); void getCurrentTimeSignature(int *n, int *d); int getCurrentKeySignature(); uint32_t getFileNoteCount(); uint32_t getFileStandard(); double getTempo(); uint32_t getTick(); uint32_t getRawTempo(); uint32_t getDivision(); uint32_t getMaxTick(); double getPitchBend(int ch); void getPitchBendRaw(int ch, uint32_t *pb, uint32_t *pbr); const char *getTitle(); const char *getCopyright(); void sendSysX(bool send); void setChannelPreset(int ch, int b, int p); void setMute(int ch, bool m); void setSolo(int ch, bool s); bool getChannelMask(int ch); uint16_t getCC(int ch, int id); void setCC(int ch, int id, int val); void registerMidiOutDevice(qmpMidiOutDevice *dev, std::string name); void unregisterMidiOutDevice(std::string name); std::vector getMidiOutDevices(); int getChannelOutput(int ch); qmpMidiOutDevice *getChannelOutputDevice(int ch); void setChannelOutput(int ch, int outid); const std::chrono::system_clock::time_point *getLastEventTS(); int setEventHandlerCB(ICallBack *cb, void *userdata); void unsetEventHandlerCB(int id); int setEventReaderCB(ICallBack *cb, void *userdata); void unsetEventReaderCB(int id); int setFileReadFinishedCB(ICallBack *cb, void *userdata); void unsetFileReadFinishedCB(int id); int registerEventHandler(callback_t cb, void *userdata, bool post); void unregisterEventHandler(int id); int registerEventReadHandler(callback_t cb, void *userdata); void unregisterEventReadHandler(int id); int registerFileReadFinishHook(callback_t cb, void *userdata); void unregisterFileReadFinishHook(int id); void registerReader(qmpFileReader *reader, std::string name); void unregisterReader(std::string name); void callEventReaderCB(SEvent d); void discardCurrentEvent(); void commitEventChange(SEvent d); static CMidiPlayer *getInstance(); }; #endif