#include #include #include #include "midifmtplugin.hpp" qmpPluginAPI *qmpMidiFmtPlugin::api = nullptr; uint32_t CMidiStreamReader::readDWLE() { uint32_t ret = 0; for (uint32_t i = 0; i < 4; ++i) ret |= ((uint32_t)fgetc(f)) << (i << 3); return ret; } bool CMidiStreamReader::RIFFHeaderReader() { char hdr[9]; fread(hdr, 1, 4, f); if (strncmp(hdr, "RIFF", 4)) return false; fseek(f, 4, SEEK_CUR); fread(hdr, 1, 8, f); if (strncmp(hdr, "MIDSfmt ", 8)) return false; if (readDWLE() != 0x0C) return false; ret->divs = readDWLE(); readDWLE(); fmt = readDWLE(); return true; } bool CMidiStreamReader::midsBodyReader() { char buf[9]; fread(buf, 1, 4, f); if (strncmp(buf, "data", 4)) return false; readDWLE();//size uint32_t cblocks = readDWLE(); uint32_t curid = 0, cts = 0; for (uint32_t i = 0; i < cblocks; ++i) { readDWLE(); uint32_t blocksz = readDWLE(), cpos = ftell(f); while (ftell(f) - cpos < blocksz) { cts += readDWLE(); if (!(fmt & 1))readDWLE(); uint32_t e = readDWLE(); SEvent ev; if (e >> 24 == 1) //set tempo { char s[3] = {'\0'}; for (int i = 0; i < 3; ++i) s[i] = (e >> (8 * (2 - i))) & 0xff; ev = SEvent(curid, cts, 0xFF, 0x51, 0); ev.str = std::string(s, 3); } else if (e >> 24 == 0) //midishortmsg ev = SEvent(curid, cts, e & 0xFF, (e >> 8) & 0xFF, (e >> 16) & 0xFF); else return false; ret->tracks.back().appendEvent(ev); eventdiscarded = 0; qmpMidiFmtPlugin::api->callEventReaderCB(ev); if (eventdiscarded) ret->tracks.back().eventList.pop_back(); ++curid; } } return true; } CMidiFile *CMidiStreamReader::readFile(const char *fn) { ret = new CMidiFile; ret->title = ret->copyright = nullptr; ret->std = 0; ret->valid = 1; ret->tracks.push_back(CMidiTrack()); try { if (!(f = fopen(fn, "rb"))) throw std::runtime_error("File doesn't exist"); if (!RIFFHeaderReader()) throw std::runtime_error("Wrong RIFF header"); if (!midsBodyReader()) throw std::runtime_error("MIDS data error"); } catch (std::runtime_error &e) { fprintf(stderr, "CMidiStreamReader E: %s is not a supported file. Cause: %s.\n", fn, e.what()); ret->valid = 0; if (f) fclose(f); f = nullptr; } return ret; } void CMidiStreamReader::discardCurrentEvent() { eventdiscarded = 1; } void CMidiStreamReader::commitEventChange(SEvent d) { ret->tracks.back().eventList.back().time = d.time; ret->tracks.back().eventList.back().type = d.type; ret->tracks.back().eventList.back().p1 = d.p1; ret->tracks.back().eventList.back().p2 = d.p2; } CMidiStreamReader::CMidiStreamReader() { ret = nullptr; f = nullptr; } CMidiStreamReader::~CMidiStreamReader() { } qmpMidiFmtPlugin::qmpMidiFmtPlugin(qmpPluginAPI *_api) { api = _api; } qmpMidiFmtPlugin::~qmpMidiFmtPlugin() { api = nullptr; } void qmpMidiFmtPlugin::init() { api->registerFileReader(mdsreader = new CMidiStreamReader, "MIDS reader"); } void qmpMidiFmtPlugin::deinit() { api->unregisterFileReader("MIDS reader"); delete mdsreader; } const char *qmpMidiFmtPlugin::pluginGetName() { return "QMidiPlayer extra midi formats plugin"; } const char *qmpMidiFmtPlugin::pluginGetVersion() { return PLUGIN_VERSION; }