aboutsummaryrefslogtreecommitdiff
path: root/visualization/renderer
diff options
context:
space:
mode:
authorGravatar Chris Xiong <chirs241097@gmail.com> 2020-04-30 01:12:38 +0800
committerGravatar Chris Xiong <chirs241097@gmail.com> 2020-04-30 01:12:38 +0800
commitbd165c0254b9095bb9e5ea54def56b6404033ebe (patch)
treee6e965ff343c0cd4feea0180dd63522e05085567 /visualization/renderer
parent8766f3b12e13d40b65eca23a850f687b0043d022 (diff)
downloadQMidiPlayer-bd165c0254b9095bb9e5ea54def56b6404033ebe.tar.xz
Add visualization renderer.
Add API for getting raw pitch bend values. Fix non-compliant RPN handling. The visualization renderer is still at the "proof-of-concept" stage. It's not very usable (yet).
Diffstat (limited to 'visualization/renderer')
-rw-r--r--visualization/renderer/CMakeLists.txt26
-rw-r--r--visualization/renderer/main.cpp22
-rw-r--r--visualization/renderer/qmppluginapistub.cpp198
-rw-r--r--visualization/renderer/qmppluginapistub.hpp85
-rw-r--r--visualization/renderer/qmpsettingsro.cpp167
-rw-r--r--visualization/renderer/qmpsettingsro.hpp73
-rw-r--r--visualization/renderer/qmpvisrendercore.cpp88
-rw-r--r--visualization/renderer/qmpvisrendercore.hpp44
8 files changed, 703 insertions, 0 deletions
diff --git a/visualization/renderer/CMakeLists.txt b/visualization/renderer/CMakeLists.txt
new file mode 100644
index 0000000..90a4704
--- /dev/null
+++ b/visualization/renderer/CMakeLists.txt
@@ -0,0 +1,26 @@
+set(qmpvisrender_SOURCES
+ qmpsettingsro.hpp
+ qmppluginapistub.hpp
+ qmpvisrendercore.hpp
+ main.cpp
+ qmpsettingsro.cpp
+ qmppluginapistub.cpp
+ qmpvisrendercore.cpp
+)
+
+set(CMAKE_AUTOMOC ON)
+
+include_directories(${PROJECT_SOURCE_DIR}/core/)
+include_directories(${PROJECT_SOURCE_DIR}/include/)
+
+add_executable(qmpvisrender
+ ${qmpvisrender_SOURCES}
+)
+
+target_link_libraries(qmpvisrender
+ Qt5::Core
+ qmpcore
+ ${CMAKE_DL_LIBS}
+)
+
+install(TARGETS qmpvisrender)
diff --git a/visualization/renderer/main.cpp b/visualization/renderer/main.cpp
new file mode 100644
index 0000000..ec4dd1d
--- /dev/null
+++ b/visualization/renderer/main.cpp
@@ -0,0 +1,22 @@
+#include <QProcess>
+#include <QCommandLineParser>
+
+#include "qmpvisrendercore.hpp"
+
+int main(int argc,char **argv)
+{
+ QCoreApplication::setApplicationName("qmpvisrender");
+ QCoreApplication a(argc,argv);
+ QCommandLineParser clp;
+ clp.setApplicationDescription("Renderer a visualization of a midi file.");
+ clp.addHelpOption();
+ clp.parse(a.arguments());
+ qmpVisRenderCore core;
+ core.loadVisualizationLibrary();
+ if(clp.positionalArguments().size())
+ core.setMIDIFile(clp.positionalArguments().front().toStdString().c_str());
+ core.startRender();
+ int retval=a.exec();
+ core.unloadVisualizationLibrary();
+ return retval;
+}
diff --git a/visualization/renderer/qmppluginapistub.cpp b/visualization/renderer/qmppluginapistub.cpp
new file mode 100644
index 0000000..d37e191
--- /dev/null
+++ b/visualization/renderer/qmppluginapistub.cpp
@@ -0,0 +1,198 @@
+#include "qmpmidiplay.hpp"
+#include "qmpvisrendercore.hpp"
+#include "qmpsettingsro.hpp"
+#include "qmppluginapistub.hpp"
+
+#include <QTextCodec>
+
+qmpPluginAPIStub::qmpPluginAPIStub(qmpVisRenderCore *_core):
+ core(_core)
+{
+}
+
+qmpPluginAPIStub::~qmpPluginAPIStub()
+{
+ core=nullptr;
+}
+
+uint32_t qmpPluginAPIStub::getDivision()
+{
+ return core->player->getDivision();
+}
+uint32_t qmpPluginAPIStub::getRawTempo(){return 0;}
+double qmpPluginAPIStub::getRealTempo(){return 0;}
+uint32_t qmpPluginAPIStub::getTimeSig(){return 0;}
+int qmpPluginAPIStub::getKeySig(){return 0;}
+uint32_t qmpPluginAPIStub::getNoteCount(){return 0;}
+uint32_t qmpPluginAPIStub::getMaxTick()
+{
+ return core->player->getMaxTick();
+}
+uint32_t qmpPluginAPIStub::getCurrentPolyphone(){return 0;}
+uint32_t qmpPluginAPIStub::getMaxPolyphone(){return 0;}
+uint32_t qmpPluginAPIStub::getCurrentTimeStamp(){return 0;}
+uint32_t qmpPluginAPIStub::getCurrentPlaybackPercentage(){return 0;}
+int qmpPluginAPIStub::getChannelCC(int ch, int cc){return 0;}
+int qmpPluginAPIStub::getChannelPreset(int ch){return 0;}
+void qmpPluginAPIStub::playerSeek(uint32_t percentage){}
+double qmpPluginAPIStub::getPitchBend(int ch){return 0;}
+void qmpPluginAPIStub::getPitchBendRaw(int ch,uint32_t *pb,uint32_t *pbr){}
+bool qmpPluginAPIStub::getChannelMask(int ch){return 0;}
+std::string qmpPluginAPIStub::getTitle()
+{
+ if(core->settings()->getOptionEnumIntOptName("Midi/TextEncoding")=="Unicode")
+ return std::string(core->player->getTitle());
+ return QTextCodec::codecForName(
+ core->settings()->getOptionEnumIntOptName("Midi/TextEncoding").c_str())->
+ toUnicode(core->player->getTitle()).toStdString();
+}
+std::wstring qmpPluginAPIStub::getWTitle()
+{
+ if(core->settings()->getOptionEnumIntOptName("Midi/TextEncoding")=="Unicode")
+ return QString(core->player->getTitle()).toStdWString();
+ return QTextCodec::codecForName(
+ core->settings()->getOptionEnumIntOptName("Midi/TextEncoding").c_str())->
+ toUnicode(core->player->getTitle()).toStdWString();
+}
+std::string qmpPluginAPIStub::getChannelPresetString(int ch){return std::string();}
+bool qmpPluginAPIStub::isDarkTheme(){return false;}
+void *qmpPluginAPIStub::getMainWindow(){return nullptr;}
+void qmpPluginAPIStub::discardCurrentEvent(){}
+void qmpPluginAPIStub::commitEventChange(SEvent d){}
+void qmpPluginAPIStub::callEventReaderCB(SEvent d){}
+void qmpPluginAPIStub::setFuncState(std::string name,bool state){}
+void qmpPluginAPIStub::setFuncEnabled(std::string name, bool enable)
+{}
+void qmpPluginAPIStub::registerFunctionality(qmpFuncBaseIntf *i, std::string name, std::string desc, const char *icon, int iconlen, bool checkable)
+{
+ if(name=="Visualization")
+ core->vf=i;
+}
+void qmpPluginAPIStub::unregisterFunctionality(std::string name)
+{
+ if(name=="Visualization")
+ core->vf=nullptr;
+}
+
+int qmpPluginAPIStub::registerUIHook(std::string e, ICallBack *cb, void *userdat){}
+int qmpPluginAPIStub::registerUIHook(std::string e, callback_t cb, void *userdat)
+{
+ if(e=="main.start")
+ core->startcb=cb;
+ return 0;
+}
+void qmpPluginAPIStub::unregisterUIHook(std::string e, int hook)
+{
+ if(e=="main.start")
+ core->startcb=nullptr;
+}
+
+void qmpPluginAPIStub::registerMidiOutDevice(qmpMidiOutDevice *dev, std::string name){}
+void qmpPluginAPIStub::unregisterMidiOutDevice(std::string name){}
+
+int qmpPluginAPIStub::registerEventReaderIntf(ICallBack *cb, void *userdata){}
+void qmpPluginAPIStub::unregisterEventReaderIntf(int intfhandle){}
+int qmpPluginAPIStub::registerEventHandlerIntf(ICallBack *cb, void *userdata){}
+void qmpPluginAPIStub::unregisterEventHandlerIntf(int intfhandle){}
+int qmpPluginAPIStub::registerFileReadFinishedHandlerIntf(ICallBack *cb, void *userdata){}
+void qmpPluginAPIStub::unregisterFileReadFinishedHandlerIntf(int intfhandle){}
+
+int qmpPluginAPIStub::registerEventHandler(callback_t cb, void *userdata, bool post){}
+void qmpPluginAPIStub::unregisterEventHandler(int id){}
+int qmpPluginAPIStub::registerEventReadHandler(callback_t cb, void *userdata)
+{
+ return core->player->registerEventReadHandler(cb,userdata);
+}
+void qmpPluginAPIStub::unregisterEventReadHandler(int id)
+{
+ core->player->unregisterEventReadHandler(id);
+}
+int qmpPluginAPIStub::registerFileReadFinishHook(callback_t cb, void *userdata)
+{
+ return core->player->registerFileReadFinishHook(cb,userdata);
+}
+void qmpPluginAPIStub::unregisterFileReadFinishHook(int id)
+{
+ core->player->unregisterFileReadFinishHook(id);
+}
+
+void qmpPluginAPIStub::registerFileReader(qmpFileReader *reader, std::string name){}
+void qmpPluginAPIStub::unregisterFileReader(std::string name){}
+
+void qmpPluginAPIStub::registerOptionInt(std::string tab, std::string desc, std::string key, int min, int max, int defaultval)
+{
+ core->settings()->registerOptionInt(tab,desc,key,min,max,defaultval);
+}
+int qmpPluginAPIStub::getOptionInt(std::string key)
+{
+ return core->settings()->getOptionInt(key);
+}
+void qmpPluginAPIStub::setOptionInt(std::string key, int val)
+{
+ core->settings()->setOptionInt(key,val);
+}
+
+void qmpPluginAPIStub::registerOptionUint(std::string tab, std::string desc, std::string key, unsigned min, unsigned max, unsigned defaultval)
+{
+ core->settings()->registerOptionUint(tab,desc,key,min,max,defaultval);
+}
+unsigned qmpPluginAPIStub::getOptionUint(std::string key)
+{
+ return core->settings()->getOptionUint(key);
+}
+void qmpPluginAPIStub::setOptionUint(std::string key, unsigned val)
+{
+ return core->settings()->setOptionUint(key,val);
+}
+
+void qmpPluginAPIStub::registerOptionBool(std::string tab, std::string desc, std::string key, bool defaultval)
+{
+ core->settings()->registerOptionBool(tab,desc,key,defaultval);
+}
+bool qmpPluginAPIStub::getOptionBool(std::string key)
+{
+ return core->settings()->getOptionBool(key);
+}
+void qmpPluginAPIStub::setOptionBool(std::string key, bool val)
+{
+ core->settings()->setOptionBool(key,val);
+}
+
+void qmpPluginAPIStub::registerOptionDouble(std::string tab, std::string desc, std::string key, double min, double max, double defaultval)
+{
+ core->settings()->registerOptionDouble(tab,desc,key,min,max,defaultval);
+}
+double qmpPluginAPIStub::getOptionDouble(std::string key)
+{
+ return core->settings()->getOptionDouble(key);
+}
+void qmpPluginAPIStub::setOptionDouble(std::string key, double val)
+{
+ core->settings()->setOptionDouble(key,val);
+}
+
+void qmpPluginAPIStub::registerOptionString(std::string tab, std::string desc, std::string key, std::string defaultval, bool ispath)
+{
+ core->settings()->registerOptionString(tab,desc,key,defaultval,ispath);
+}
+std::string qmpPluginAPIStub::getOptionString(std::string key)
+{
+ return core->settings()->getOptionString(key);
+}
+void qmpPluginAPIStub::setOptionString(std::string key, std::string val)
+{
+ core->settings()->setOptionString(key,val);
+}
+
+void qmpPluginAPIStub::registerOptionEnumInt(std::string tab, std::string desc, std::string key, std::vector<std::string> options, int defaultval)
+{
+ core->settings()->registerOptionEnumInt(tab,desc,key,options,defaultval);
+}
+int qmpPluginAPIStub::getOptionEnumInt(std::string key)
+{
+ return core->settings()->getOptionEnumInt(key);
+}
+void qmpPluginAPIStub::setOptionEnumInt(std::string key, int val)
+{
+ core->settings()->setOptionEnumInt(key,val);
+}
diff --git a/visualization/renderer/qmppluginapistub.hpp b/visualization/renderer/qmppluginapistub.hpp
new file mode 100644
index 0000000..d96cfca
--- /dev/null
+++ b/visualization/renderer/qmppluginapistub.hpp
@@ -0,0 +1,85 @@
+#ifndef QMPPLUGINAPISTUB_HPP
+#define QMPPLUGINAPISTUB_HPP
+
+#include "qmpcorepublic.hpp"
+
+class qmpVisRenderCore;
+class qmpPluginAPIStub:public qmpPluginAPI
+{
+public:
+ qmpPluginAPIStub(qmpVisRenderCore *_core);
+ ~qmpPluginAPIStub();
+ uint32_t getDivision();
+ uint32_t getRawTempo();
+ double getRealTempo();
+ uint32_t getTimeSig();
+ int getKeySig();
+ uint32_t getNoteCount();
+ uint32_t getMaxTick();
+ uint32_t getCurrentPolyphone();
+ uint32_t getMaxPolyphone();
+ uint32_t getCurrentTimeStamp();
+ uint32_t getCurrentPlaybackPercentage();
+ int getChannelCC(int ch,int cc);
+ int getChannelPreset(int ch);
+ void playerSeek(uint32_t percentage);
+ double getPitchBend(int ch);
+ void getPitchBendRaw(int ch,uint32_t *pb,uint32_t *pbr);
+ bool getChannelMask(int ch);
+ std::string getTitle();
+ std::wstring getWTitle();
+ std::string getChannelPresetString(int ch);
+ bool isDarkTheme();
+ void* getMainWindow();
+
+ void discardCurrentEvent();
+ void commitEventChange(SEvent d);
+ void callEventReaderCB(SEvent d);
+ void setFuncState(std::string name,bool state);
+ void setFuncEnabled(std::string name,bool enable);
+
+ void registerFunctionality(qmpFuncBaseIntf* i,std::string name,std::string desc,const char* icon,int iconlen,bool checkable);
+ void unregisterFunctionality(std::string name);
+ int registerUIHook(std::string e,ICallBack* cb,void* userdat);
+ int registerUIHook(std::string e,callback_t cb,void* userdat);
+ void unregisterUIHook(std::string e,int hook);
+ void registerMidiOutDevice(qmpMidiOutDevice* dev,std::string name);
+ void unregisterMidiOutDevice(std::string name);
+ int registerEventReaderIntf(ICallBack* cb,void* userdata);
+ void unregisterEventReaderIntf(int intfhandle);
+ int registerEventHandlerIntf(ICallBack* cb,void* userdata);
+ void unregisterEventHandlerIntf(int intfhandle);
+ int registerFileReadFinishedHandlerIntf(ICallBack* cb,void* userdata);
+ void unregisterFileReadFinishedHandlerIntf(int intfhandle);
+ int registerEventHandler(callback_t cb,void *userdata,bool post=false);
+ 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 registerFileReader(qmpFileReader* reader,std::string name);
+ void unregisterFileReader(std::string name);
+
+ void registerOptionInt(std::string tab,std::string desc,std::string key,int min,int max,int defaultval);
+ int getOptionInt(std::string key);
+ void setOptionInt(std::string key,int val);
+ void registerOptionUint(std::string tab,std::string desc,std::string key,unsigned min,unsigned max,unsigned defaultval);
+ unsigned getOptionUint(std::string key);
+ void setOptionUint(std::string key,unsigned val);
+ void registerOptionBool(std::string tab,std::string desc,std::string key,bool defaultval);
+ bool getOptionBool(std::string key);
+ void setOptionBool(std::string key,bool val);
+ void registerOptionDouble(std::string tab,std::string desc,std::string key,double min,double max,double defaultval);
+ double getOptionDouble(std::string key);
+ void setOptionDouble(std::string key,double val);
+ void registerOptionString(std::string tab,std::string desc,std::string key,std::string defaultval,bool ispath=false);
+ std::string getOptionString(std::string key);
+ void setOptionString(std::string key,std::string val);
+ void registerOptionEnumInt(std::string tab,std::string desc,std::string key,std::vector<std::string> options,int defaultval);
+ int getOptionEnumInt(std::string key);
+ void setOptionEnumInt(std::string key,int val);
+private:
+ qmpVisRenderCore* core;
+};
+
+#endif // QMPPLUGINAPISTUB_HPP
diff --git a/visualization/renderer/qmpsettingsro.cpp b/visualization/renderer/qmpsettingsro.cpp
new file mode 100644
index 0000000..cc6e0bf
--- /dev/null
+++ b/visualization/renderer/qmpsettingsro.cpp
@@ -0,0 +1,167 @@
+#include <QScopedPointer>
+#include <QSettings>
+
+#include "qmpsettingsro.hpp"
+
+qmpSettingsRO::qmpSettingsRO()
+{
+}
+
+void qmpSettingsRO::registerOptionInt(std::string tab,std::string desc,std::string key,int min,int max,int defaultval)
+{
+ Q_UNUSED(tab)
+ optionlist.push_back(key);
+ options[key]=qmpOptionR(desc,qmpOptionR::ParameterType::parameter_int,defaultval,min,max);
+}
+int qmpSettingsRO::getOptionInt(std::string key)
+{
+ if(options.find(key)!=options.end()&&options[key].type==qmpOptionR::ParameterType::parameter_int)
+ return settings.value(QString(key.c_str()),options[key].defaultval).toInt();
+ return options[key].defaultval.toInt();
+}
+void qmpSettingsRO::setOptionInt(std::string key,int val)
+{
+ if(options.find(key)!=options.end()&&options[key].type==qmpOptionR::ParameterType::parameter_int)
+ settings.insert(QString(key.c_str()),val);
+}
+
+void qmpSettingsRO::registerOptionUint(std::string tab,std::string desc,std::string key,unsigned min,unsigned max,unsigned defaultval)
+{
+ Q_UNUSED(tab)
+ optionlist.push_back(key);
+ options[key]=qmpOptionR(desc,qmpOptionR::ParameterType::parameter_uint,defaultval,min,max);
+}
+unsigned qmpSettingsRO::getOptionUint(std::string key)
+{
+ if(options.find(key)!=options.end()&&options[key].type==qmpOptionR::ParameterType::parameter_uint)
+ return settings.value(QString(key.c_str()),options[key].defaultval).toUInt();
+ return options[key].defaultval.toUInt();
+}
+void qmpSettingsRO::setOptionUint(std::string key,unsigned val)
+{
+ if(options.find(key)!=options.end()&&options[key].type==qmpOptionR::ParameterType::parameter_uint)
+ settings.insert(QString(key.c_str()),val);
+}
+
+void qmpSettingsRO::registerOptionBool(std::string tab,std::string desc,std::string key,bool defaultval)
+{
+ Q_UNUSED(tab)
+ optionlist.push_back(key);
+ options[key]=qmpOptionR(desc,qmpOptionR::ParameterType::parameter_bool,defaultval);
+}
+bool qmpSettingsRO::getOptionBool(std::string key)
+{
+ if(options.find(key)!=options.end()&&options[key].type==qmpOptionR::ParameterType::parameter_bool)
+ return settings.value(QString(key.c_str()),options[key].defaultval).toBool();
+ return options[key].defaultval.toBool();
+}
+void qmpSettingsRO::setOptionBool(std::string key,bool val)
+{
+ if(options.find(key)!=options.end()&&options[key].type==qmpOptionR::ParameterType::parameter_bool)
+ settings.insert(QString(key.c_str()),val);
+}
+
+void qmpSettingsRO::registerOptionDouble(std::string tab,std::string desc,std::string key,double min,double max,double defaultval)
+{
+ Q_UNUSED(tab)
+ optionlist.push_back(key);
+ options[key]=qmpOptionR(desc,qmpOptionR::ParameterType::parameter_double,defaultval,min,max);
+}
+double qmpSettingsRO::getOptionDouble(std::string key)
+{
+ if(options.find(key)!=options.end()&&options[key].type==qmpOptionR::ParameterType::parameter_double)
+ return settings.value(QString(key.c_str()),options[key].defaultval).toDouble();
+ return options[key].defaultval.toDouble();
+}
+void qmpSettingsRO::setOptionDouble(std::string key,double val)
+{
+ if(options.find(key)!=options.end()&&options[key].type==qmpOptionR::ParameterType::parameter_double)
+ settings.insert(QString(key.c_str()),val);
+}
+
+void qmpSettingsRO::registerOptionString(std::string tab,std::string desc,std::string key,std::string defaultval,bool is_url)
+{
+ Q_UNUSED(tab)
+ optionlist.push_back(key);
+ options[key]=qmpOptionR(desc,
+ is_url?qmpOptionR::ParameterType::parameter_url:qmpOptionR::ParameterType::parameter_str,
+ QString(defaultval.c_str()));
+}
+std::string qmpSettingsRO::getOptionString(std::string key)
+{
+ if(options.find(key)!=options.end()&&
+ (options[key].type==qmpOptionR::ParameterType::parameter_str||options[key].type==qmpOptionR::ParameterType::parameter_url))
+ return settings.value(QString(key.c_str()),options[key].defaultval).toString().toStdString();
+ return options[key].defaultval.toString().toStdString();
+}
+void qmpSettingsRO::setOptionString(std::string key,std::string val)
+{
+ if(options.find(key)!=options.end()&&
+ (options[key].type==qmpOptionR::ParameterType::parameter_str||options[key].type==qmpOptionR::ParameterType::parameter_url))
+ settings.insert(QString(key.c_str()),QString(val.c_str()));
+}
+
+void qmpSettingsRO::registerOptionEnumInt(std::string tab,std::string desc,std::string key,std::vector<std::string> enumlist,int defaultval)
+{
+ Q_UNUSED(tab)
+ optionlist.push_back(key);
+ options[key]=qmpOptionR(desc,qmpOptionR::ParameterType::parameter_enum,defaultval);
+ options[key].enumlist=enumlist;
+}
+int qmpSettingsRO::getOptionEnumInt(std::string key)
+{
+ if(options.find(key)!=options.end()&&options[key].type==qmpOptionR::ParameterType::parameter_enum)
+ {
+ std::string curitm=settings.value(QString(key.c_str()),options[key].defaultval).toString().toStdString();
+ auto curidx=std::find(options[key].enumlist.begin(),options[key].enumlist.end(),curitm);
+ if(curidx!=options[key].enumlist.end())
+ return static_cast<int>(curidx-options[key].enumlist.begin());
+ else
+ {
+ return options[key].defaultval.toInt();
+ }
+ }
+ return options[key].defaultval.toInt();
+}
+std::string qmpSettingsRO::getOptionEnumIntOptName(std::string key)
+{
+ if(options.find(key)!=options.end()&&options[key].type==qmpOptionR::ParameterType::parameter_enum)
+ {
+ std::string curitm=settings.value(QString(key.c_str()),options[key].defaultval).toString().toStdString();
+ auto curidx=std::find(options[key].enumlist.begin(),options[key].enumlist.end(),curitm);
+ if(curidx!=options[key].enumlist.end())
+ return curitm;
+ else
+ {
+ return options[key].enumlist[static_cast<size_t>(options[key].defaultval.toInt())];
+ }
+ }
+ return options[key].enumlist[static_cast<size_t>(options[key].defaultval.toInt())];
+}
+void qmpSettingsRO::setOptionEnumInt(std::string key,int val)
+{
+ if(options.find(key)!=options.end()&&options[key].type==qmpOptionR::ParameterType::parameter_enum)
+ {
+ if(static_cast<size_t>(val)<options[key].enumlist.size())
+ settings.insert(QString(key.c_str()),QString(options[key].enumlist[static_cast<size_t>(val)].c_str()));
+ }
+}
+void qmpSettingsRO::setOptionEnumIntOptName(std::string key,std::string valname)
+{
+ if(options.find(key)!=options.end()&&options[key].type==qmpOptionR::ParameterType::parameter_enum)
+ {
+ auto curidx=std::find(options[key].enumlist.begin(),options[key].enumlist.end(),valname);
+ if(curidx!=options[key].enumlist.end())
+ settings.insert(QString(key.c_str()),QString(valname.c_str()));
+ }
+}
+
+void qmpSettingsRO::load(const char *path)
+{
+ QScopedPointer<QSettings> qsettings(new QSettings(path,QSettings::Format::IniFormat));
+ settings.clear();
+ for(QString&k:qsettings->allKeys())
+ {
+ settings.insert(k,qsettings->value(k));
+ }
+}
diff --git a/visualization/renderer/qmpsettingsro.hpp b/visualization/renderer/qmpsettingsro.hpp
new file mode 100644
index 0000000..30ab9b6
--- /dev/null
+++ b/visualization/renderer/qmpsettingsro.hpp
@@ -0,0 +1,73 @@
+#ifndef QMPSETTINGSRO_H
+#define QMPSETTINGSRO_H
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include <QVariant>
+#include <QPointer>
+
+struct qmpOptionR
+{
+ enum ParameterType{
+ parameter_int=0,
+ parameter_uint,
+ parameter_bool,
+ parameter_double,
+ parameter_str,
+ parameter_enum,
+ parameter_url,
+ parameter_custom=0x100
+ };
+
+ std::string desc;
+ ParameterType type;
+ QVariant defaultval,minv,maxv;
+ std::vector<std::string> enumlist;
+
+ qmpOptionR(){}
+ qmpOptionR(
+ std::string _desc,
+ ParameterType _t,QVariant _def=QVariant(),
+ QVariant _min=QVariant(),QVariant _max=QVariant()):
+ desc(_desc),
+ type(_t),
+ defaultval(_def),
+ minv(_min),
+ maxv(_max){}
+};
+
+class qmpSettingsRO
+{
+public:
+ qmpSettingsRO();
+ void registerOptionInt(std::string tab,std::string desc,std::string key,int min,int max,int defaultval);
+ int getOptionInt(std::string key);
+ void setOptionInt(std::string key,int val);
+ void registerOptionUint(std::string tab,std::string desc,std::string key,unsigned min,unsigned max,unsigned defaultval);
+ unsigned getOptionUint(std::string key);
+ void setOptionUint(std::string key,unsigned val);
+ void registerOptionBool(std::string tab,std::string desc,std::string key,bool defaultval);
+ bool getOptionBool(std::string key);
+ void setOptionBool(std::string key,bool val);
+ void registerOptionDouble(std::string tab,std::string desc,std::string key,double min,double max,double defaultval);
+ double getOptionDouble(std::string key);
+ void setOptionDouble(std::string key,double val);
+ void registerOptionString(std::string tab,std::string desc,std::string key,std::string defaultval,bool is_url);
+ std::string getOptionString(std::string key);
+ void setOptionString(std::string key,std::string val);
+ void registerOptionEnumInt(std::string tab,std::string desc,std::string key,std::vector<std::string> enumlist,int defaultval);
+ int getOptionEnumInt(std::string key);
+ std::string getOptionEnumIntOptName(std::string key);
+ void setOptionEnumInt(std::string key,int val);
+ void setOptionEnumIntOptName(std::string key,std::string valname);
+
+ void load(const char* path);
+private:
+ std::map<std::string,qmpOptionR> options;
+ std::vector<std::string> optionlist;
+ QVariantMap settings;
+};
+
+#endif
diff --git a/visualization/renderer/qmpvisrendercore.cpp b/visualization/renderer/qmpvisrendercore.cpp
new file mode 100644
index 0000000..fb1a7ef
--- /dev/null
+++ b/visualization/renderer/qmpvisrendercore.cpp
@@ -0,0 +1,88 @@
+#include "qmpvisrendercore.hpp"
+#include "qmppluginapistub.hpp"
+#include "qmpsettingsro.hpp"
+#include "qmpmidiplay.hpp"
+#include "qmpcorepublic.hpp"
+
+#include <cassert>
+#include <dlfcn.h>
+
+#include <QProcess>
+#include <QDebug>
+#include <QThread>
+qmpVisRenderCore *qmpVisRenderCore::inst=nullptr;
+
+qmpVisRenderCore::qmpVisRenderCore():QObject(nullptr)
+{
+ inst=this;
+ player=new CMidiPlayer();
+ api=new qmpPluginAPIStub(this);
+ msettings=new qmpSettingsRO();
+ msettings->registerOptionEnumInt("MIDI","Text encoding","Midi/TextEncoding",{"Unicode","Big5","Big5-HKSCS","CP949","EUC-JP","EUC-KR","GB18030","KOI8-R","KOI8-U","Macintosh","Shift-JIS"},0);
+}
+
+void qmpVisRenderCore::loadVisualizationLibrary()
+{
+ mp=dlopen("libvisualization.so",RTLD_LAZY);
+ if(!mp)fprintf(stderr,"failed to load visualization module!\n");
+ GetInterface_func getintf=reinterpret_cast<GetInterface_func>(dlsym(mp,"qmpPluginGetInterface"));
+ SwitchMode_func switchmode=reinterpret_cast<SwitchMode_func>(dlsym(mp,"switchToRenderMode"));
+ vf=nullptr;
+ vp=getintf(api);
+ switchmode(&qmpVisRenderCore::framefunc,false);
+ vp->init();
+ msettings->load("/home/chrisoft/.config/qmprc");
+}
+
+void qmpVisRenderCore::unloadVisualizationLibrary()
+{
+ vp->deinit();
+ dlclose(mp);
+}
+
+void qmpVisRenderCore::setMIDIFile(const char *url)
+{
+ player->playerLoadFile(url);
+}
+
+void qmpVisRenderCore::startRender()
+{
+ assert(vf);
+ ffmpegproc=new QProcess();
+ ffmpegproc->setProgram("ffmpeg");
+ QStringList arguments;
+ arguments
+ <<"-f"<<"rawvideo"
+ <<"-pixel_format"<<"rgba"
+ <<"-video_size"<<"1600x900"
+ <<"-framerate"<<"60"
+ <<"-i"<<"pipe:";
+ arguments
+ <<"-vf"<<"vflip"
+ <<"-pix_fmt"<<"yuv420p"
+ <<"-c:v"<<"libx264"
+ <<"-preset"<<"fast"
+ <<"-crf"<<"22";
+ arguments<<"output.mp4";
+ ffmpegproc->setArguments(arguments);
+ ffmpegproc->start();
+ connect(ffmpegproc,QOverload<int,QProcess::ExitStatus>::of(&QProcess::finished),
+ [this](int x,QProcess::ExitStatus){qDebug("%d",x);qDebug()<<this->ffmpegproc->readAllStandardError();});
+ vf->show();
+ startcb(nullptr,nullptr);
+}
+
+void qmpVisRenderCore::framefunc(void *px, size_t sz)
+{
+ if(sz)
+ {
+ inst->ffmpegproc->write((const char*)px,sz);
+ while(inst->ffmpegproc->bytesToWrite()>1<<26)
+ {
+ inst->ffmpegproc->waitForBytesWritten();
+ QThread::yieldCurrentThread();
+ }
+ }
+ else
+ inst->ffmpegproc->closeWriteChannel();
+}
diff --git a/visualization/renderer/qmpvisrendercore.hpp b/visualization/renderer/qmpvisrendercore.hpp
new file mode 100644
index 0000000..0c024f1
--- /dev/null
+++ b/visualization/renderer/qmpvisrendercore.hpp
@@ -0,0 +1,44 @@
+#ifndef QMPVISRENDERCORE_HPP
+#define QMPVISRENDERCORE_HPP
+
+#include <cstddef>
+
+#include <QObject>
+#include "qmpcorepublic.hpp"
+
+class qmpPluginAPIStub;
+class CMidiPlayer;
+class qmpSettingsRO;
+
+class QProcess;
+
+class qmpVisRenderCore:public QObject
+{
+ Q_OBJECT
+public:
+ qmpVisRenderCore();
+ void loadVisualizationLibrary();
+ void unloadVisualizationLibrary();
+ void setMIDIFile(const char* url);
+ void startRender();
+
+ qmpSettingsRO* settings(){return msettings;}
+
+private:
+ qmpPluginIntf *vp;
+ qmpFuncBaseIntf *vf;
+ callback_t startcb;
+ void *mp;
+ qmpPluginAPIStub *api;
+ CMidiPlayer *player;
+ qmpSettingsRO *msettings;
+ QProcess *ffmpegproc;
+ typedef qmpPluginIntf*(*GetInterface_func)(qmpPluginAPI*);
+ typedef void(*SwitchMode_func)(void(*frameCallback)(void*,size_t),bool hidewindow);
+
+ friend class qmpPluginAPIStub;
+ static void framefunc(void* px,size_t sz);
+ static qmpVisRenderCore *inst;
+};
+
+#endif // QMPVISRENDERCORE_HPP