From bd165c0254b9095bb9e5ea54def56b6404033ebe Mon Sep 17 00:00:00 2001 From: Chris Xiong Date: Thu, 30 Apr 2020 01:12:38 +0800 Subject: 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). --- visualization/renderer/CMakeLists.txt | 26 ++++ visualization/renderer/main.cpp | 22 ++++ visualization/renderer/qmppluginapistub.cpp | 198 ++++++++++++++++++++++++++++ visualization/renderer/qmppluginapistub.hpp | 85 ++++++++++++ visualization/renderer/qmpsettingsro.cpp | 167 +++++++++++++++++++++++ visualization/renderer/qmpsettingsro.hpp | 73 ++++++++++ visualization/renderer/qmpvisrendercore.cpp | 88 +++++++++++++ visualization/renderer/qmpvisrendercore.hpp | 44 +++++++ 8 files changed, 703 insertions(+) create mode 100644 visualization/renderer/CMakeLists.txt create mode 100644 visualization/renderer/main.cpp create mode 100644 visualization/renderer/qmppluginapistub.cpp create mode 100644 visualization/renderer/qmppluginapistub.hpp create mode 100644 visualization/renderer/qmpsettingsro.cpp create mode 100644 visualization/renderer/qmpsettingsro.hpp create mode 100644 visualization/renderer/qmpvisrendercore.cpp create mode 100644 visualization/renderer/qmpvisrendercore.hpp (limited to 'visualization/renderer') 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 +#include + +#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 + +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 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 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 +#include + +#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 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(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(options[key].defaultval.toInt())]; + } + } + return options[key].enumlist[static_cast(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(val)(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(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 +#include +#include + +#include +#include + +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 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 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 options; + std::vector 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 +#include + +#include +#include +#include +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(dlsym(mp,"qmpPluginGetInterface")); + SwitchMode_func switchmode=reinterpret_cast(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::of(&QProcess::finished), + [this](int x,QProcess::ExitStatus){qDebug("%d",x);qDebug()<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 + +#include +#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 -- cgit v1.2.3