aboutsummaryrefslogtreecommitdiff
path: root/midifmt-plugin
diff options
context:
space:
mode:
authorGravatar Chris Xiong <chirs241097@gmail.com> 2017-02-09 16:04:43 +0800
committerGravatar Chris Xiong <chirs241097@gmail.com> 2017-02-09 16:04:43 +0800
commit620aad63042e0f397ea6691fe92ac40fcc6b6fed (patch)
treeb36a0f0c00ffba03bfed9513a360b7ecf442e720 /midifmt-plugin
parent1976c49f835267d33ef88bd3fc20d18363e12c0b (diff)
downloadQMidiPlayer-620aad63042e0f397ea6691fe92ac40fcc6b6fed.tar.xz
Add extra midi formats support via the file reader API.
Fix note counting.
Diffstat (limited to 'midifmt-plugin')
-rw-r--r--midifmt-plugin/midifmt-plugin.pro27
-rw-r--r--midifmt-plugin/midifmtplugin.cpp111
-rw-r--r--midifmt-plugin/midifmtplugin.hpp45
3 files changed, 183 insertions, 0 deletions
diff --git a/midifmt-plugin/midifmt-plugin.pro b/midifmt-plugin/midifmt-plugin.pro
new file mode 100644
index 0000000..e063dac
--- /dev/null
+++ b/midifmt-plugin/midifmt-plugin.pro
@@ -0,0 +1,27 @@
+#-------------------------------------------------
+#
+# Project created by QtCreator 2017-02-09T09:24:43
+#
+#-------------------------------------------------
+
+QT -= core gui
+
+CONFIG += c++11
+
+TARGET = midifmt-plugin
+TEMPLATE = lib
+
+DEFINES += MIDIFMTPLUGIN_LIBRARY
+
+SOURCES += midifmtplugin.cpp
+
+HEADERS += midifmtplugin.hpp
+
+unix {
+ QMAKE_CXXFLAGS_RELEASE -= -O2
+ QMAKE_CXXFLAGS_RELEASE += -O3
+ QMAKE_LFLAGS_RELEASE -= -O1
+ QMAKE_LFLAGS_RELEASE += -O3
+ target.path = $$PREFIX/lib/qmidiplayer
+ INSTALLS += target
+}
diff --git a/midifmt-plugin/midifmtplugin.cpp b/midifmt-plugin/midifmtplugin.cpp
new file mode 100644
index 0000000..33e636e
--- /dev/null
+++ b/midifmt-plugin/midifmtplugin.cpp
@@ -0,0 +1,111 @@
+#include <cstring>
+#include <algorithm>
+#include <stdexcept>
+#include "midifmtplugin.hpp"
+qmpPluginAPI* qmpMidiFmtPlugin::api=NULL;
+
+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(int 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
+ ev=SEvent(curid,cts,0xFF,0x51,e&0x00FFFFFF);
+ else if(e>>24==0)//midishortmsg
+ ev=SEvent(curid,cts,e&0xFF,(e>>8)&0xFF,(e>>16)&0xFF);
+ else return false;
+ //fprintf(stderr,"ev: @ %x t %x p1 %x p2 %x\n",ev.time,ev.type,ev.p1,ev.p2);
+ if((ev.type&0xF0)==0x90&&ev.p2==0)//Note on with zero velo
+ ev.type=(ev.type&0x0F)|0x80;
+ if((ev.type&0xF0)==0xE0)//pitch wheel
+ {ev.p1=(ev.p1|(ev.p2<<7))&0x3FFF;ev.p2=0;}
+ ret->eventList.push_back(ev);eventdiscarded=0;
+ qmpMidiFmtPlugin::api->callEventReaderCB(SEventCallBackData(ev.type,ev.p1,ev.p2,ev.time));
+ if(eventdiscarded)ret->eventList.pop_back();
+ ++curid;
+ }
+ }
+ return true;
+}
+CMidiFile* CMidiStreamReader::readFile(const char *fn)
+{
+ ret=new CMidiFile;
+ ret->title=ret->copyright=NULL;ret->std=0;ret->valid=1;
+ 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");
+ std::sort(ret->eventList.begin(),ret->eventList.end());
+ }catch(std::runtime_error& e){fprintf(stderr,"MIDI Format plugin: E: %s is not a supported file. Cause: %s.\n",fn,e.what());ret->valid=0;fclose(f);f=NULL;}
+ return ret;
+}
+void CMidiStreamReader::discardCurrentEvent()
+{
+ eventdiscarded=1;
+}
+void CMidiStreamReader::commitEventChange(SEventCallBackData d)
+{
+ ret->eventList[ret->eventList.size()-1].time=d.time;
+ ret->eventList[ret->eventList.size()-1].type=d.type;
+ ret->eventList[ret->eventList.size()-1].p1=d.p1;
+ ret->eventList[ret->eventList.size()-1].p2=d.p2;
+}
+CMidiStreamReader::CMidiStreamReader()
+{
+ ret=NULL;f=NULL;
+}
+CMidiStreamReader::~CMidiStreamReader()
+{
+}
+
+qmpMidiFmtPlugin::qmpMidiFmtPlugin(qmpPluginAPI *_api)
+{api=_api;}
+qmpMidiFmtPlugin::~qmpMidiFmtPlugin()
+{api=NULL;}
+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 "0.8.5";}
diff --git a/midifmt-plugin/midifmtplugin.hpp b/midifmt-plugin/midifmtplugin.hpp
new file mode 100644
index 0000000..f6284dd
--- /dev/null
+++ b/midifmt-plugin/midifmtplugin.hpp
@@ -0,0 +1,45 @@
+#ifndef MIDIFMTPLUGIN_HPP
+#define MIDIFMTPLUGIN_HPP
+
+#include <cstdio>
+#include "../include/qmpcorepublic.hpp"
+
+class CMidiStreamReader:public IMidiFileReader
+{
+ private:
+ CMidiFile* ret;
+ FILE* f;
+ int eventdiscarded,fmt;
+ uint32_t readDWLE();
+ bool RIFFHeaderReader();
+ bool midsBodyReader();
+ public:
+ CMidiStreamReader();
+ ~CMidiStreamReader();
+ CMidiFile* readFile(const char *fn);
+ void discardCurrentEvent();
+ void commitEventChange(SEventCallBackData d);
+};
+
+class qmpMidiFmtPlugin:public qmpPluginIntf
+{
+ private:
+ CMidiStreamReader* mdsreader;
+ public:
+ static qmpPluginAPI* api;
+ qmpMidiFmtPlugin(qmpPluginAPI* _api);
+ ~qmpMidiFmtPlugin();
+ void init();
+ void deinit();
+ const char* pluginGetName();
+ const char* pluginGetVersion();
+};
+
+extern "C"{
+ EXPORTSYM qmpPluginIntf* qmpPluginGetInterface(qmpPluginAPI* api)
+ {return new qmpMidiFmtPlugin(api);}
+ EXPORTSYM const char* qmpPluginGetAPIRev()
+ {return QMP_PLUGIN_API_REV;}
+}
+
+#endif // MIDIFMTPLUGIN_HPP