From a7407edaf81c685d4a389785a405a53a5de4b148 Mon Sep 17 00:00:00 2001 From: Chris Xiong Date: Tue, 12 May 2020 00:58:40 +0800 Subject: Format EVERYTHING. Hopefully this will make the source code less horrendous and actually readable. The command used was: ``` astyle --suffix=none --style=allman --attach-extern-c --attach-closing-while --indent-switches --indent-after-parens --pad-oper --pad-header --unpad-paren --align-pointer=name --recursive './*.cpp,*.hpp' ``` --- core/qmpmidioutfluid.cpp | 640 ++++--- core/qmpmidioutfluid.hpp | 148 +- core/qmpmidioutrtmidi.cpp | 636 ++++--- core/qmpmidioutrtmidi.hpp | 72 +- core/qmpmidiplay.cpp | 1157 +++++++----- core/qmpmidiplay.hpp | 301 +-- core/qmpmidiread.cpp | 552 +++--- include/qmpcorepublic.hpp | 336 ++-- midifmt-plugin/midifmtplugin.cpp | 183 +- midifmt-plugin/midifmtplugin.hpp | 64 +- qmidiplayer-desktop/main.cpp | 71 +- qmidiplayer-desktop/qdialskulpturestyle.cpp | 742 ++++---- qmidiplayer-desktop/qdialskulpturestyle.hpp | 10 +- qmidiplayer-desktop/qmpchanneleditor.cpp | 207 ++- qmidiplayer-desktop/qmpchanneleditor.hpp | 55 +- qmidiplayer-desktop/qmpchannelswindow.cpp | 612 +++--- qmidiplayer-desktop/qmpchannelswindow.hpp | 129 +- qmidiplayer-desktop/qmpcustomizewindow.cpp | 103 +- qmidiplayer-desktop/qmpcustomizewindow.hpp | 31 +- qmidiplayer-desktop/qmpdeviceprioritydialog.cpp | 141 +- qmidiplayer-desktop/qmpdeviceprioritydialog.hpp | 33 +- qmidiplayer-desktop/qmpdevpropdialog.cpp | 149 +- qmidiplayer-desktop/qmpdevpropdialog.hpp | 31 +- qmidiplayer-desktop/qmpefxwindow.cpp | 367 ++-- qmidiplayer-desktop/qmpefxwindow.hpp | 95 +- qmidiplayer-desktop/qmphelpwindow.cpp | 51 +- qmidiplayer-desktop/qmphelpwindow.hpp | 21 +- qmidiplayer-desktop/qmpinfowindow.cpp | 125 +- qmidiplayer-desktop/qmpinfowindow.hpp | 65 +- qmidiplayer-desktop/qmpmainwindow.cpp | 1399 +++++++------- qmidiplayer-desktop/qmpmainwindow.hpp | 459 +++-- qmidiplayer-desktop/qmpplistwindow.cpp | 532 +++--- qmidiplayer-desktop/qmpplistwindow.hpp | 91 +- qmidiplayer-desktop/qmpplugin.cpp | 582 ++++-- qmidiplayer-desktop/qmpplugin.hpp | 182 +- qmidiplayer-desktop/qmppresetselect.cpp | 205 ++- qmidiplayer-desktop/qmppresetselect.hpp | 41 +- qmidiplayer-desktop/qmpsettings.cpp | 320 ++-- qmidiplayer-desktop/qmpsettings.hpp | 131 +- qmidiplayer-desktop/qmpsettingswindow.cpp | 1013 +++++----- qmidiplayer-desktop/qmpsettingswindow.hpp | 162 +- qmidiplayer-lite/main.cpp | 10 +- qmidiplayer-lite/qmpcorewrapper.hpp | 106 +- qmidiplayer-lite/qmpmidiplay.cpp | 749 ++++---- qmidiplayer-lite/qmpmidiplay.hpp | 237 +-- qmidiplayer-lite/qmpmidiread.cpp | 525 +++--- sample-plugin/sampleplugin.cpp | 28 +- sample-plugin/sampleplugin.hpp | 34 +- simple-visualization/qmpkeyboardwindow.cpp | 107 +- simple-visualization/qmpkeyboardwindow.hpp | 34 +- simple-visualization/qmppianowidget.cpp | 105 +- simple-visualization/qmppianowidget.hpp | 28 +- simple-visualization/simplevisualization.cpp | 66 +- simple-visualization/simplevisualization.hpp | 42 +- visualization/extrasmeltutils.cpp | 657 ++++--- visualization/extrasmeltutils.hpp | 234 +-- visualization/qmpvirtualpiano3d.cpp | 426 +++-- visualization/qmpvirtualpiano3d.hpp | 20 +- visualization/qmpvisualization.cpp | 2249 +++++++++++++---------- visualization/qmpvisualization.hpp | 188 +- visualization/renderer/main.cpp | 80 +- visualization/renderer/qmppluginapistub.cpp | 220 ++- visualization/renderer/qmppluginapistub.hpp | 140 +- visualization/renderer/qmpsettingsro.cpp | 310 ++-- visualization/renderer/qmpsettingsro.hpp | 103 +- visualization/renderer/qmpvisrendercore.cpp | 463 ++--- visualization/renderer/qmpvisrendercore.hpp | 67 +- 67 files changed, 10767 insertions(+), 8705 deletions(-) diff --git a/core/qmpmidioutfluid.cpp b/core/qmpmidioutfluid.cpp index 649cb1c..bfa6016 100644 --- a/core/qmpmidioutfluid.cpp +++ b/core/qmpmidioutfluid.cpp @@ -4,375 +4,431 @@ #include "qmpmidioutfluid.hpp" qmpMidiOutFluid::qmpMidiOutFluid() { - settings=new_fluid_settings(); - synth=nullptr;adriver=nullptr; + settings = new_fluid_settings(); + synth = nullptr; + adriver = nullptr; } qmpMidiOutFluid::~qmpMidiOutFluid() { - delete_fluid_settings(settings); - settings=nullptr; + delete_fluid_settings(settings); + settings = nullptr; } void qmpMidiOutFluid::registerOptions(qmpPluginAPI *coreapi) { - default_driver=-1; - fluid_settings_t *fsettings=new_fluid_settings(); - auto insert_driver=[](void* d,const char*,const char* driver)->void{ - qmpMidiOutFluid *me=static_cast(d); - me->drivers.push_back(std::string(driver)); + default_driver = -1; + fluid_settings_t *fsettings = new_fluid_settings(); + auto insert_driver = [](void *d, const char *, const char *driver)->void + { + qmpMidiOutFluid *me = static_cast(d); + me->drivers.push_back(std::string(driver)); #ifdef WIN32 - if(std::string(driver)=="waveout") + if (std::string(driver) == "waveout") #else - if(std::string(driver)=="pulseaudio") - me->default_driver=static_cast(me->drivers.size()-1); + if (std::string(driver) == "pulseaudio") + me->default_driver = static_cast(me->drivers.size() - 1); #endif - }; - fluid_settings_foreach_option(fsettings,"audio.driver",this,insert_driver); - delete_fluid_settings(fsettings); - coreapi->registerOptionEnumInt("Audio","Audio Driver","FluidSynth/AudioDriver",drivers,default_driver); - coreapi->registerOptionInt("Audio","Audio Buffer Size","FluidSynth/BufSize",64,8192, + }; + fluid_settings_foreach_option(fsettings, "audio.driver", this, insert_driver); + delete_fluid_settings(fsettings); + coreapi->registerOptionEnumInt("Audio", "Audio Driver", "FluidSynth/AudioDriver", drivers, default_driver); + coreapi->registerOptionInt("Audio", "Audio Buffer Size", "FluidSynth/BufSize", 64, 8192, #ifdef WIN32 - 512 + 512 #else - 64 + 64 #endif - ); - coreapi->registerOptionInt("Audio","Audio Buffer Count","FluidSynth/BufCnt",2,64, + ); + coreapi->registerOptionInt("Audio", "Audio Buffer Count", "FluidSynth/BufCnt", 2, 64, #ifdef WIN32 - 8 + 8 #else - 16 + 16 #endif - ); - coreapi->registerOptionEnumInt("Audio","Sample Format","FluidSynth/SampleFormat",{"16bits","float"},0); - coreapi->registerOptionInt("Audio","Sample Rate","FluidSynth/SampleRate",8000,96000,48000); - coreapi->registerOptionInt("Audio","Max Polyphony","FluidSynth/Polyphony",1,65535,256); - coreapi->registerOptionInt("Audio","CPU Cores","FluidSynth/Threads",1,256,1); - coreapi->registerOptionBool("Audio","Auto Bank Select Mode","FluidSynth/AutoBS",true); - coreapi->registerOptionEnumInt("Audio","Bank Select Mode","FluidSynth/BankSelect",{"GM","GS","XG","MMA"},1); + ); + coreapi->registerOptionEnumInt("Audio", "Sample Format", "FluidSynth/SampleFormat", {"16bits", "float"}, 0); + coreapi->registerOptionInt("Audio", "Sample Rate", "FluidSynth/SampleRate", 8000, 96000, 48000); + coreapi->registerOptionInt("Audio", "Max Polyphony", "FluidSynth/Polyphony", 1, 65535, 256); + coreapi->registerOptionInt("Audio", "CPU Cores", "FluidSynth/Threads", 1, 256, 1); + coreapi->registerOptionBool("Audio", "Auto Bank Select Mode", "FluidSynth/AutoBS", true); + coreapi->registerOptionEnumInt("Audio", "Bank Select Mode", "FluidSynth/BankSelect", {"GM", "GS", "XG", "MMA"}, 1); } void qmpMidiOutFluid::deviceInit() { - synth=new_fluid_synth(settings); - if(!synth){fputs("Error creating fluidsynth instance!",stderr);return;} - fluid_set_log_function(FLUID_DBG,nullptr,nullptr); - fluid_set_log_function(FLUID_INFO,nullptr,nullptr); - fluid_set_log_function(FLUID_WARN,nullptr,nullptr); - fluid_set_log_function(FLUID_ERR,fluid_default_log_function,nullptr); - fluid_set_log_function(FLUID_PANIC,fluid_default_log_function,nullptr); - adriver=new_fluid_audio_driver(settings,synth); - if(!adriver) - { - fputs("Error creating fluidsynth audio driver!",stderr); - delete_fluid_synth(synth);synth=nullptr; - return; - } - fluid_synth_set_chorus(synth,3,2.0,0.3,8.0, - FLUID_CHORUS_MOD_SINE); - bnk.clear();pst.clear(); -} -void qmpMidiOutFluid::deviceDeinit(){deviceDeinit(false);} + synth = new_fluid_synth(settings); + if (!synth) + { + fputs("Error creating fluidsynth instance!", stderr); + return; + } + fluid_set_log_function(FLUID_DBG, nullptr, nullptr); + fluid_set_log_function(FLUID_INFO, nullptr, nullptr); + fluid_set_log_function(FLUID_WARN, nullptr, nullptr); + fluid_set_log_function(FLUID_ERR, fluid_default_log_function, nullptr); + fluid_set_log_function(FLUID_PANIC, fluid_default_log_function, nullptr); + adriver = new_fluid_audio_driver(settings, synth); + if (!adriver) + { + fputs("Error creating fluidsynth audio driver!", stderr); + delete_fluid_synth(synth); + synth = nullptr; + return; + } + fluid_synth_set_chorus(synth, 3, 2.0, 0.3, 8.0, FLUID_CHORUS_MOD_SINE); + bnk.clear(); + pst.clear(); +} +void qmpMidiOutFluid::deviceDeinit() +{ + deviceDeinit(false); +} void qmpMidiOutFluid::deviceDeinit(bool freshsettings) { - if(!synth||!adriver)return; - delete_fluid_audio_driver(adriver); - delete_fluid_synth(synth); - synth=nullptr;adriver=nullptr; - bnk.clear();pst.clear(); - if(freshsettings) - { - delete_fluid_settings(settings); - settings=new_fluid_settings(); - } -} -void qmpMidiOutFluid::basicMessage(uint8_t type,uint8_t p1,uint8_t p2) -{ - uint8_t chan=type&0x0F; - switch(type&0xF0) - { - case 0x80: - fluid_synth_noteoff(synth,chan,p1); - break; - case 0x90: - if(p2)fluid_synth_noteon(synth,chan,p1,p2); - else fluid_synth_noteoff(synth,chan,p1); - break; - case 0xB0: - fluid_synth_cc(synth,chan,p1,p2); - break; - case 0xC0: - fluid_synth_program_change(synth,chan,p1); - break; - case 0xE0: - fluid_synth_pitch_bend(synth,chan,(p1|p2<<7)&0x3fff); - break; - } -} -void qmpMidiOutFluid::extendedMessage(uint32_t length,const char *data) -{ - int rlen=0; - fluid_synth_sysex(synth,data,int(length),nullptr,&rlen,nullptr,0); -} -void qmpMidiOutFluid::rpnMessage(uint8_t ch,uint16_t type,uint16_t val) -{ - if(type==0)fluid_synth_pitch_wheel_sens(synth,ch,val>>7); - else - { - fluid_synth_cc(synth,ch,0x64,type&0x7F); - fluid_synth_cc(synth,ch,0x65,type>>7); - fluid_synth_cc(synth,ch,0x06,val>>7); - fluid_synth_cc(synth,ch,0x26,val&0x7F); - } -} -void qmpMidiOutFluid::nrpnMessage(uint8_t ch,uint16_t type,uint16_t val) -{ - fluid_synth_cc(synth,ch,0x62,type&0x7F); - fluid_synth_cc(synth,ch,0x63,type>>7); - fluid_synth_cc(synth,ch,0x06,val>>7); - fluid_synth_cc(synth,ch,0x26,val&0x7F); + if (!synth || !adriver) + return; + delete_fluid_audio_driver(adriver); + delete_fluid_synth(synth); + synth = nullptr; + adriver = nullptr; + bnk.clear(); + pst.clear(); + if (freshsettings) + { + delete_fluid_settings(settings); + settings = new_fluid_settings(); + } +} +void qmpMidiOutFluid::basicMessage(uint8_t type, uint8_t p1, uint8_t p2) +{ + uint8_t chan = type & 0x0F; + switch (type & 0xF0) + { + case 0x80: + fluid_synth_noteoff(synth, chan, p1); + break; + case 0x90: + if (p2) + fluid_synth_noteon(synth, chan, p1, p2); + else + fluid_synth_noteoff(synth, chan, p1); + break; + case 0xB0: + fluid_synth_cc(synth, chan, p1, p2); + break; + case 0xC0: + fluid_synth_program_change(synth, chan, p1); + break; + case 0xE0: + fluid_synth_pitch_bend(synth, chan, (p1 | p2 << 7) & 0x3fff); + break; + } +} +void qmpMidiOutFluid::extendedMessage(uint32_t length, const char *data) +{ + int rlen = 0; + fluid_synth_sysex(synth, data, int(length), nullptr, &rlen, nullptr, 0); +} +void qmpMidiOutFluid::rpnMessage(uint8_t ch, uint16_t type, uint16_t val) +{ + if (type == 0) + fluid_synth_pitch_wheel_sens(synth, ch, val >> 7); + else + { + fluid_synth_cc(synth, ch, 0x64, type & 0x7F); + fluid_synth_cc(synth, ch, 0x65, type >> 7); + fluid_synth_cc(synth, ch, 0x06, val >> 7); + fluid_synth_cc(synth, ch, 0x26, val & 0x7F); + } +} +void qmpMidiOutFluid::nrpnMessage(uint8_t ch, uint16_t type, uint16_t val) +{ + fluid_synth_cc(synth, ch, 0x62, type & 0x7F); + fluid_synth_cc(synth, ch, 0x63, type >> 7); + fluid_synth_cc(synth, ch, 0x06, val >> 7); + fluid_synth_cc(synth, ch, 0x26, val & 0x7F); } void qmpMidiOutFluid::panic(uint8_t ch) { - fluid_synth_cc(synth,ch,64,0); - fluid_synth_pitch_bend(synth,ch,8192); - fluid_synth_all_notes_off(synth,ch); + fluid_synth_cc(synth, ch, 64, 0); + fluid_synth_pitch_bend(synth, ch, 8192); + fluid_synth_all_notes_off(synth, ch); } void qmpMidiOutFluid::reset(uint8_t ch) { - if(!~ch){fluid_synth_system_reset(synth);return;} - this->panic(ch); - for(int i=0;i<128;++i) - fluid_synth_cc(synth,ch,i,0); - if(ch==9) - fluid_synth_cc(synth,ch,0,127); - else - fluid_synth_cc(synth,ch,0,0); - fluid_synth_cc(synth,ch,7,100); - fluid_synth_cc(synth,ch,8,64); - fluid_synth_cc(synth,ch,10,64); - fluid_synth_cc(synth,ch,11,127); - fluid_synth_pitch_wheel_sens(synth,ch,2); -} -void qmpMidiOutFluid::onMapped(uint8_t,int) -{ -} -void qmpMidiOutFluid::onUnmapped(uint8_t,int) -{ -} -std::vector> qmpMidiOutFluid::getBankList() -{ - return bnk; -} -std::vector> qmpMidiOutFluid::getPresets(uint16_t bank) -{ - std::vector> ret; - if(pst.find(bank)==pst.end())return ret; - for(uint8_t i=0;i<128;++i) - { - if(pst[bank][i].length()) - ret.emplace_back(i,pst[bank][i]); - } - return ret; -} -std::string qmpMidiOutFluid::getPresetName(uint16_t bank,uint8_t preset) -{ - if(pst.find(bank)==pst.end())return ""; - //should consult fluidsynth instead? (4 bank mapping methods) - return pst[bank][preset]; -} -bool qmpMidiOutFluid::getChannelPreset(int ch,uint16_t *bank,uint8_t *preset,std::string &presetname) -{ - if(!synth)return false; - fluid_preset_t* chpreset=fluid_synth_get_channel_preset(synth,ch); - if(!chpreset) - { - *bank=*preset=-1; - presetname="---"; - return true; - } - *bank=fluid_preset_get_banknum(chpreset); - *preset=fluid_preset_get_num(chpreset); - presetname=fluid_preset_get_name(chpreset); - return true; -} -uint8_t qmpMidiOutFluid::getInitialCCValue(uint8_t cc,uint8_t) -{ - switch(cc) - { - case 11:return 127; - case 7:return 100; - case 8:case 10:case 71:case 72: - case 73:case 74:case 75:case 76: - case 77:case 78:return 64; - case 129:return 2; - default:return 0; - } -} -void qmpMidiOutFluid::setOptStr(const char *opt,const char *val) -{ - fluid_settings_setstr(settings,opt,val); -} -void qmpMidiOutFluid::setOptInt(const char *opt,int val) -{ - fluid_settings_setint(settings,opt,val); -} -void qmpMidiOutFluid::setOptNum(const char *opt,double val) -{ - fluid_settings_setnum(settings,opt,val); + if (!~ch) + { + fluid_synth_system_reset(synth); + return; + } + this->panic(ch); + + for (int i = 0; i < 128; ++i) + fluid_synth_cc(synth, ch, i, 0); + + if (ch == 9) + fluid_synth_cc(synth, ch, 0, 127); + else + fluid_synth_cc(synth, ch, 0, 0); + + fluid_synth_cc(synth, ch, 7, 100); + fluid_synth_cc(synth, ch, 8, 64); + fluid_synth_cc(synth, ch, 10, 64); + fluid_synth_cc(synth, ch, 11, 127); + fluid_synth_pitch_wheel_sens(synth, ch, 2); +} +void qmpMidiOutFluid::onMapped(uint8_t, int) +{ +} +void qmpMidiOutFluid::onUnmapped(uint8_t, int) +{ +} +std::vector> qmpMidiOutFluid::getBankList() +{ + return bnk; +} +std::vector> qmpMidiOutFluid::getPresets(uint16_t bank) +{ + std::vector> ret; + if (pst.find(bank) == pst.end()) + return ret; + for (uint8_t i = 0; i < 128; ++i) + { + if (pst[bank][i].length()) + ret.emplace_back(i, pst[bank][i]); + } + return ret; +} +std::string qmpMidiOutFluid::getPresetName(uint16_t bank, uint8_t preset) +{ + if (pst.find(bank) == pst.end()) + return ""; + //should consult fluidsynth instead? (4 bank mapping methods) + return pst[bank][preset]; +} +bool qmpMidiOutFluid::getChannelPreset(int ch, uint16_t *bank, uint8_t *preset, std::string &presetname) +{ + if (!synth) + return false; + fluid_preset_t *chpreset = fluid_synth_get_channel_preset(synth, ch); + if (!chpreset) + { + *bank = *preset = -1; + presetname = "---"; + return true; + } + *bank = fluid_preset_get_banknum(chpreset); + *preset = fluid_preset_get_num(chpreset); + presetname = fluid_preset_get_name(chpreset); + return true; +} +uint8_t qmpMidiOutFluid::getInitialCCValue(uint8_t cc, uint8_t) +{ + switch (cc) + { + case 11: + return 127; + case 7: + return 100; + case 8: + case 10: + case 71: + case 72: + case 73: + case 74: + case 75: + case 76: + case 77: + case 78: + return 64; + case 129: + return 2; + default: + return 0; + } +} +void qmpMidiOutFluid::setOptStr(const char *opt, const char *val) +{ + fluid_settings_setstr(settings, opt, val); +} +void qmpMidiOutFluid::setOptInt(const char *opt, int val) +{ + fluid_settings_setint(settings, opt, val); +} +void qmpMidiOutFluid::setOptNum(const char *opt, double val) +{ + fluid_settings_setnum(settings, opt, val); } void qmpMidiOutFluid::loadSFont(const char *path) { - if(synth)fluid_synth_sfload(synth,path,1); - update_preset_list(); + if (synth) + fluid_synth_sfload(synth, path, 1); + update_preset_list(); } int qmpMidiOutFluid::getSFCount() { - return synth?fluid_synth_sfcount(synth):0; + return synth ? fluid_synth_sfcount(synth) : 0; } void qmpMidiOutFluid::update_preset_list() { - bnk.clear();pst.clear(); - for(int i=getSFCount()-1;i>=0;--i) - { - fluid_sfont_t* psf=fluid_synth_get_sfont(synth,i); - fluid_preset_t* preset; - fluid_sfont_iteration_start(psf); - while(preset=fluid_sfont_iteration_next(psf)) - { - uint16_t b=fluid_preset_get_banknum(preset); - uint8_t p=fluid_preset_get_num(preset); - if(bnk.empty()||bnk.back().first!=b) - bnk.emplace_back(b,""); - if(pst[b].empty())pst[b].resize(128); - pst[b][p]=std::string(fluid_preset_get_name(preset)); - if(!pst[b][p].length())pst[b][p]=" "; - } - } - std::sort(bnk.begin(),bnk.end()); - bnk.erase(std::unique(bnk.begin(),bnk.end()),bnk.end()); + bnk.clear(); + pst.clear(); + for (int i = getSFCount() - 1; i >= 0; --i) + { + fluid_sfont_t *psf = fluid_synth_get_sfont(synth, i); + fluid_preset_t *preset; + fluid_sfont_iteration_start(psf); + while ((preset = fluid_sfont_iteration_next(psf))) + { + uint16_t b = fluid_preset_get_banknum(preset); + uint8_t p = fluid_preset_get_num(preset); + if (bnk.empty() || bnk.back().first != b) + bnk.emplace_back(b, ""); + if (pst[b].empty()) + pst[b].resize(128); + pst[b][p] = std::string(fluid_preset_get_name(preset)); + if (!pst[b][p].length()) + pst[b][p] = " "; + } + } + std::sort(bnk.begin(), bnk.end()); + bnk.erase(std::unique(bnk.begin(), bnk.end()), bnk.end()); } int qmpMidiOutFluid::getPolyphone() { - return synth?fluid_synth_get_active_voice_count(synth):0; + return synth ? fluid_synth_get_active_voice_count(synth) : 0; } int qmpMidiOutFluid::getMaxPolyphone() { - return synth?fluid_synth_get_polyphony(synth):0; + return synth ? fluid_synth_get_polyphony(synth) : 0; } void qmpMidiOutFluid::setGain(double gain) { - if(settings)fluid_settings_setnum(settings,"synth.gain",gain); -} -void qmpMidiOutFluid::getChannelInfo(int ch,int *b,int *p,char *s) -{ - if(!synth)return; - fluid_preset_t* chpreset=fluid_synth_get_channel_preset(synth,ch); - if(!chpreset) - { - *b=*p=-1; - strcpy(s,"---"); - return; - } - *b=fluid_preset_get_banknum(chpreset); - *p=fluid_preset_get_num(chpreset); - strncpy(s,fluid_preset_get_name(chpreset),256); -} -void qmpMidiOutFluid::getReverbPara(double *r,double *d,double *w,double *l) -{ - if(!synth)return; - *r=fluid_synth_get_reverb_roomsize(synth); - *d=fluid_synth_get_reverb_damp(synth); - *w=fluid_synth_get_reverb_width(synth); - *l=fluid_synth_get_reverb_level(synth); -} -void qmpMidiOutFluid::setReverbPara(int e,double r,double d,double w,double l) -{ - if(!synth)return; - fluid_synth_set_reverb_on(synth,e); - fluid_synth_set_reverb(synth,r,d,w,l); -} -void qmpMidiOutFluid::getChorusPara(int *fb,double *l,double *r,double *d,int *type) -{ - if(!synth)return; - *fb=fluid_synth_get_chorus_nr(synth); - *l=fluid_synth_get_chorus_level(synth); - *r=fluid_synth_get_chorus_speed(synth); - *d=fluid_synth_get_chorus_depth(synth); - *type=fluid_synth_get_chorus_type(synth); -} -void qmpMidiOutFluid::setChorusPara(int e,int fb,double l,double r,double d,int type) -{ - if(!synth)return; - fluid_synth_set_chorus_on(synth,e); - fluid_synth_set_chorus(synth,fb,l,r,d,type); + if (settings) + fluid_settings_setnum(settings, "synth.gain", gain); +} +void qmpMidiOutFluid::getChannelInfo(int ch, int *b, int *p, char *s) +{ + if (!synth) + return; + fluid_preset_t *chpreset = fluid_synth_get_channel_preset(synth, ch); + if (!chpreset) + { + *b = *p = -1; + strcpy(s, "---"); + return; + } + *b = fluid_preset_get_banknum(chpreset); + *p = fluid_preset_get_num(chpreset); + strncpy(s, fluid_preset_get_name(chpreset), 256); +} +void qmpMidiOutFluid::getReverbPara(double *r, double *d, double *w, double *l) +{ + if (!synth) + return; + *r = fluid_synth_get_reverb_roomsize(synth); + *d = fluid_synth_get_reverb_damp(synth); + *w = fluid_synth_get_reverb_width(synth); + *l = fluid_synth_get_reverb_level(synth); +} +void qmpMidiOutFluid::setReverbPara(int e, double r, double d, double w, double l) +{ + if (!synth) + return; + fluid_synth_set_reverb_on(synth, e); + fluid_synth_set_reverb(synth, r, d, w, l); +} +void qmpMidiOutFluid::getChorusPara(int *fb, double *l, double *r, double *d, int *type) +{ + if (!synth) + return; + *fb = fluid_synth_get_chorus_nr(synth); + *l = fluid_synth_get_chorus_level(synth); + *r = fluid_synth_get_chorus_speed(synth); + *d = fluid_synth_get_chorus_depth(synth); + *type = fluid_synth_get_chorus_type(synth); +} +void qmpMidiOutFluid::setChorusPara(int e, int fb, double l, double r, double d, int type) +{ + if (!synth) + return; + fluid_synth_set_chorus_on(synth, e); + fluid_synth_set_chorus(synth, fb, l, r, d, type); } -qmpFileRendererFluid::qmpFileRendererFluid(const char *_fn,const char *_ofn) +qmpFileRendererFluid::qmpFileRendererFluid(const char *_fn, const char *_ofn) { - settings=new_fluid_settings(); - fluid_settings_setstr(settings,"audio.file.name",_ofn); - fn=std::string(_fn); - finished=false; + settings = new_fluid_settings(); + fluid_settings_setstr(settings, "audio.file.name", _ofn); + fn = std::string(_fn); + finished = false; } qmpFileRendererFluid::~qmpFileRendererFluid() { - if(player||synth||settings)renderDeinit(); + if (player || synth || settings) + renderDeinit(); } void qmpFileRendererFluid::renderInit() { - synth=new_fluid_synth(settings); - player=new_fluid_player(synth); - fluid_player_add(player,fn.c_str()); + synth = new_fluid_synth(settings); + player = new_fluid_player(synth); + fluid_player_add(player, fn.c_str()); } void qmpFileRendererFluid::renderDeinit() { - delete_fluid_player(player); - delete_fluid_synth(synth); - delete_fluid_settings(settings); - player=nullptr;synth=nullptr;settings=nullptr; + delete_fluid_player(player); + delete_fluid_synth(synth); + delete_fluid_settings(settings); + player = nullptr; + synth = nullptr; + settings = nullptr; } void qmpFileRendererFluid::renderWorker() { - fluid_file_renderer_t* renderer=new_fluid_file_renderer(synth); - fluid_player_play(player); - while(fluid_player_get_status(player)==FLUID_PLAYER_PLAYING) - if(fluid_file_renderer_process_block(renderer)!=FLUID_OK)break; - delete_fluid_file_renderer(renderer); - finished=true; + fluid_file_renderer_t *renderer = new_fluid_file_renderer(synth); + fluid_player_play(player); + while (fluid_player_get_status(player) == FLUID_PLAYER_PLAYING) + if (fluid_file_renderer_process_block(renderer) != FLUID_OK) + break; + delete_fluid_file_renderer(renderer); + finished = true; } -void qmpFileRendererFluid::setOptStr(const char *opt,const char *val) +void qmpFileRendererFluid::setOptStr(const char *opt, const char *val) { - fluid_settings_setstr(settings,opt,val); + fluid_settings_setstr(settings, opt, val); } -void qmpFileRendererFluid::setOptInt(const char *opt,int val) +void qmpFileRendererFluid::setOptInt(const char *opt, int val) { - fluid_settings_setint(settings,opt,val); + fluid_settings_setint(settings, opt, val); } -void qmpFileRendererFluid::setOptNum(const char *opt,double val) +void qmpFileRendererFluid::setOptNum(const char *opt, double val) { - fluid_settings_setnum(settings,opt,val); + fluid_settings_setnum(settings, opt, val); } void qmpFileRendererFluid::loadSFont(const char *path) { - if(synth)fluid_synth_sfload(synth,path,1); + if (synth) + fluid_synth_sfload(synth, path, 1); } bool qmpFileRendererFluid::isFinished() { - return finished; + return finished; } void qmpFileRendererFluid::setGain(double gain) { - if(settings)fluid_settings_setnum(settings,"synth.gain",gain); + if (settings) + fluid_settings_setnum(settings, "synth.gain", gain); } -void qmpFileRendererFluid::setReverbPara(int e,double r,double d,double w,double l) +void qmpFileRendererFluid::setReverbPara(int e, double r, double d, double w, double l) { - if(!synth)return; - fluid_synth_set_reverb_on(synth,e); - fluid_synth_set_reverb(synth,r,d,w,l); + if (!synth) + return; + fluid_synth_set_reverb_on(synth, e); + fluid_synth_set_reverb(synth, r, d, w, l); } -void qmpFileRendererFluid::setChorusPara(int e,int fb,double l,double r,double d,int type) +void qmpFileRendererFluid::setChorusPara(int e, int fb, double l, double r, double d, int type) { - if(!synth)return; - fluid_synth_set_chorus_on(synth,e); - fluid_synth_set_chorus(synth,fb,l,r,d,type); + if (!synth) + return; + fluid_synth_set_chorus_on(synth, e); + fluid_synth_set_chorus(synth, fb, l, r, d, type); } diff --git a/core/qmpmidioutfluid.hpp b/core/qmpmidioutfluid.hpp index 63963ee..acefb68 100644 --- a/core/qmpmidioutfluid.hpp +++ b/core/qmpmidioutfluid.hpp @@ -8,85 +8,85 @@ #include class IFluidSettings { - public: - virtual void setOptStr(const char* opt,const char* val)=0; - virtual void setOptInt(const char* opt,int val)=0; - virtual void setOptNum(const char* opt,double val)=0; - virtual void loadSFont(const char* path)=0; - virtual void setGain(double gain)=0; - virtual void setReverbPara(int e,double r,double d,double w,double l)=0; - virtual void setChorusPara(int e,int fb,double l,double r,double d,int type)=0; +public: + virtual void setOptStr(const char *opt, const char *val) = 0; + virtual void setOptInt(const char *opt, int val) = 0; + virtual void setOptNum(const char *opt, double val) = 0; + virtual void loadSFont(const char *path) = 0; + virtual void setGain(double gain) = 0; + virtual void setReverbPara(int e, double r, double d, double w, double l) = 0; + virtual void setChorusPara(int e, int fb, double l, double r, double d, int type) = 0; }; -class qmpMidiOutFluid:public qmpMidiOutDevice,public IFluidSettings +class qmpMidiOutFluid: public qmpMidiOutDevice, public IFluidSettings { - private: - fluid_settings_t* settings; - fluid_synth_t* synth; - fluid_audio_driver_t* adriver; - std::vector> bnk; - std::unordered_map> pst; - qmpPluginAPI* coreapi; - std::vector drivers; - int default_driver=-1; - void update_preset_list(); - public: - qmpMidiOutFluid(); - ~qmpMidiOutFluid(); - void registerOptions(qmpPluginAPI *coreapi); - void deviceInit(); - void deviceDeinit(); - void deviceDeinit(bool freshsettings); - void basicMessage(uint8_t type,uint8_t p1,uint8_t p2); - void extendedMessage(uint32_t length,const char *data); - void rpnMessage(uint8_t ch,uint16_t type,uint16_t val); - void nrpnMessage(uint8_t ch,uint16_t type,uint16_t val); - void panic(uint8_t ch); - void reset(uint8_t ch); - void onMapped(uint8_t ch,int refcnt); - void onUnmapped(uint8_t ch,int refcnt); - std::vector> getBankList(); - std::vector> getPresets(uint16_t bank); - std::string getPresetName(uint16_t bank,uint8_t preset); - bool getChannelPreset(int ch,uint16_t *bank,uint8_t *preset,std::string &presetname); - uint8_t getInitialCCValue(uint8_t cc,uint8_t ch); - //FluidSynth specific stuff - void setOptStr(const char* opt,const char* val); - void setOptInt(const char* opt,int val); - void setOptNum(const char* opt,double val); - void loadSFont(const char* path); - int getSFCount(); +private: + fluid_settings_t *settings; + fluid_synth_t *synth; + fluid_audio_driver_t *adriver; + std::vector> bnk; + std::unordered_map> pst; + qmpPluginAPI *coreapi; + std::vector drivers; + int default_driver = -1; + void update_preset_list(); +public: + qmpMidiOutFluid(); + ~qmpMidiOutFluid(); + void registerOptions(qmpPluginAPI *coreapi); + void deviceInit(); + void deviceDeinit(); + void deviceDeinit(bool freshsettings); + void basicMessage(uint8_t type, uint8_t p1, uint8_t p2); + void extendedMessage(uint32_t length, const char *data); + void rpnMessage(uint8_t ch, uint16_t type, uint16_t val); + void nrpnMessage(uint8_t ch, uint16_t type, uint16_t val); + void panic(uint8_t ch); + void reset(uint8_t ch); + void onMapped(uint8_t ch, int refcnt); + void onUnmapped(uint8_t ch, int refcnt); + std::vector> getBankList(); + std::vector> getPresets(uint16_t bank); + std::string getPresetName(uint16_t bank, uint8_t preset); + bool getChannelPreset(int ch, uint16_t *bank, uint8_t *preset, std::string &presetname); + uint8_t getInitialCCValue(uint8_t cc, uint8_t ch); + //FluidSynth specific stuff + void setOptStr(const char *opt, const char *val); + void setOptInt(const char *opt, int val); + void setOptNum(const char *opt, double val); + void loadSFont(const char *path); + int getSFCount(); - int getPolyphone(); - int getMaxPolyphone(); - void setGain(double gain); - void getChannelInfo(int ch,int *b,int *p,char *s); - void getReverbPara(double *r,double *d,double *w,double *l); - void setReverbPara(int e,double r,double d,double w,double l); - void getChorusPara(int *fb,double *l,double *r,double *d,int *type); - void setChorusPara(int e,int fb,double l,double r,double d,int type); + int getPolyphone(); + int getMaxPolyphone(); + void setGain(double gain); + void getChannelInfo(int ch, int *b, int *p, char *s); + void getReverbPara(double *r, double *d, double *w, double *l); + void setReverbPara(int e, double r, double d, double w, double l); + void getChorusPara(int *fb, double *l, double *r, double *d, int *type); + void setChorusPara(int e, int fb, double l, double r, double d, int type); }; -class qmpFileRendererFluid:public IFluidSettings +class qmpFileRendererFluid: public IFluidSettings { - private: - fluid_settings_t* settings; - fluid_synth_t* synth; - fluid_player_t* player; - bool finished; - std::string fn; - public: - qmpFileRendererFluid(const char* _fn,const char* _ofn); - ~qmpFileRendererFluid(); - void renderInit(); - void renderDeinit(); - void renderWorker(); - void setOptStr(const char* opt,const char* val); - void setOptInt(const char* opt,int val); - void setOptNum(const char* opt,double val); - void loadSFont(const char *path); - bool isFinished(); - void setGain(double gain); - void setReverbPara(int e,double r,double d,double w,double l); - void setChorusPara(int e,int fb,double l,double r,double d,int type); +private: + fluid_settings_t *settings; + fluid_synth_t *synth; + fluid_player_t *player; + bool finished; + std::string fn; +public: + qmpFileRendererFluid(const char *_fn, const char *_ofn); + ~qmpFileRendererFluid(); + void renderInit(); + void renderDeinit(); + void renderWorker(); + void setOptStr(const char *opt, const char *val); + void setOptInt(const char *opt, int val); + void setOptNum(const char *opt, double val); + void loadSFont(const char *path); + bool isFinished(); + void setGain(double gain); + void setReverbPara(int e, double r, double d, double w, double l); + void setChorusPara(int e, int fb, double l, double r, double d, int type); }; #endif // QMPMIDIOUTFLUID_H diff --git a/core/qmpmidioutrtmidi.cpp b/core/qmpmidioutrtmidi.cpp index 2f7125e..04594e4 100644 --- a/core/qmpmidioutrtmidi.cpp +++ b/core/qmpmidioutrtmidi.cpp @@ -7,353 +7,405 @@ #include "RtMidi.h" #include "qmpmidioutrtmidi.hpp" -void split(std::string s,char c,std::deque& v) +void split(std::string s, char c, std::deque &v) { - v.clear(); - for(size_t anch=0;;) - { - std::string sec; - if(s.find(c,anch)==std::string::npos) - sec=s.substr(anch); - else sec=s.substr(anch,s.find(c,anch)-anch); - if(!sec.empty())v.push_back(sec); - if(s.find(c,anch)==std::string::npos)break; - anch=s.find(c,anch)+1; - } + v.clear(); + for (size_t anch = 0;;) + { + std::string sec; + if (s.find(c, anch) == std::string::npos) + sec = s.substr(anch); + else + sec = s.substr(anch, s.find(c, anch) - anch); + if (!sec.empty()) + v.push_back(sec); + if (s.find(c, anch) == std::string::npos) + break; + anch = s.find(c, anch) + 1; + } } -qmpDeviceInitializer* qmpDeviceInitializer::parse(const char* path) +qmpDeviceInitializer *qmpDeviceInitializer::parse(const char *path) { - qmpDeviceInitializer *ret=new qmpDeviceInitializer(); - ret->initseq.eventList.clear(); - memset(ret->sinitv,0xFF,sizeof(ret->sinitv)); + qmpDeviceInitializer *ret = new qmpDeviceInitializer(); + ret->initseq.eventList.clear(); + memset(ret->sinitv, 0xFF, sizeof(ret->sinitv)); - bool st_inmapping=false; - char buf[1024]; - int ln=0; - int cmsb=-1,clsb=-1; + bool st_inmapping = false; + char buf[1024]; + int ln = 0; + int cmsb = -1, clsb = -1; #define err(e) {delete ret;return fprintf(stderr,"line %d: %s",ln,e),nullptr;} - FILE* f=fopen(path,"r"); - if(!f)err("file not found") + FILE *f = fopen(path, "r"); + if (!f) + err("file not found") - //writing such a bad parser makes me want my money for - //the credits from "compiler principles" back... - auto h2d=[](char c)->char{return 'F'>=c&&c>='A'?c-'A'+10:'9'>=c&&c>='0'?c-'0':-1;}; - auto hh2d=[](const char *c)->int - { - if(!c||!*c||strlen(c)>2)return -1; - int x=-1,r; - r=sscanf(c,"%x",&x); - (x<0||x>0xff)&&(x=-1); - return r==1?x:-1; - }; - while(fgets(buf,1024,f)) - { - ++ln; - if(buf[0]=='#')continue; - std::string b(buf); - while(b.length()&&b.back()=='\n')b.pop_back(); - std::deque tok; - split(b,' ',tok); - if(!tok.size())continue; - if(tok.front()=="MAP") - { - if(st_inmapping) - err("invalid command") - st_inmapping=true; - } - else if(tok.front()=="ENDMAP") - { - if(!st_inmapping) - err("invalid command") - st_inmapping=false; - } - else if(tok.front()=="X") - { - if(st_inmapping) - err("invalid command") - tok.pop_front(); - std::string sysx; - for(auto&i:tok)sysx+=i; - SEvent ev; - ev.type=0xF0; - ev.str=""; - for(auto i=sysx.begin();i!=sysx.end();++i) - { - char hn=h2d((char)toupper(*i)); - if(hn<0)err("invalid sysex") - if(++i==sysx.end())err("invalid sysex") - char ln=h2d((char)toupper(*i)); - ev.str.push_back((char)(hn<<4|ln)); - } - ret->initseq.appendEvent(ev); - } - else if(tok.front()=="C") - { - if(st_inmapping) - err("invalid command") - if(tok.size()!=4)err("invalid control") - int ch=hh2d(tok[1].c_str()); - int cc=hh2d(tok[2].c_str()); - int cv=hh2d(tok[3].c_str()); - if(!~cc||!~cv)err("invalid control parameters") - if(ch==0xff) - { - for(int i=0;i<16;++i) - { - SEvent e; - e.type=(uint8_t)(0xB0|i); - e.p1=(uint8_t)cc; - e.p2=(uint8_t)cv; - ret->initseq.appendEvent(e); - } - } - else if(ch>=0&&ch<0x10) - { - SEvent e; - e.type=(uint8_t)(0xB0|ch); - e.p1=(uint8_t)cc; - e.p2=(uint8_t)cv; - ret->initseq.appendEvent(e); - } - else err("invalid channel") - } - else if(tok.front()=="IV") - { - if(st_inmapping) - err("invalid command") - int ci=0; - tok.pop_front(); - for(auto&tk:tok) - { - int v=0,rep=1; - if(tk.find(',')!=std::string::npos) - sscanf(tk.c_str(),"%x,%d",&v,&rep); - else sscanf(tk.c_str(),"%x",&v); - if(v>0xff||v<0)err("invalid init vector value") - for(int i=0;i=130)err("invalid init vector") - ret->initv[ci++]=(uint8_t)v; - } - } - } - else if(tok.front()=="SIV") - { - if(st_inmapping) - err("invalid command") - int ch=hh2d(tok[1].c_str()); - int cc=hh2d(tok[2].c_str()); - int cv=hh2d(tok[3].c_str()); - ret->sinitv[ch][cc]=uint8_t(cv); - } - else if(st_inmapping) - { - if(b.front()=='['&&b.back()==']') - { - b=b.substr(1,b.length()-2); - split(b,':',tok); - if(tok.size()<3)err("invalid bank") - cmsb=strtol(tok[0].c_str(),nullptr,10); - clsb=strtol(tok[1].c_str(),nullptr,10); - ret->banks[cmsb<<7|clsb]=BankStore{{},tok[2]}; - } - else if(b.find('=')!=std::string::npos) - { - if(!~cmsb||!~clsb)err("inst outside a bank") - split(b,'=',tok); - if(tok.size()<2)err("invalid inst") - int p=strtol(tok[0].c_str(),nullptr,10); - ret->banks[cmsb<<7|clsb].presets[p]=tok[1]; - } - else err("invalid mapping line") - } - } + //writing such a bad parser makes me want my money for + //the credits from "compiler principles" back... + auto h2d = [](char c)->char + { + return 'F' >= c && c >= 'A' ? + c - 'A' + 10 : + '9' >= c && c >= '0' ? c - '0' : -1; + }; + auto hh2d = [](const char *c)->int + { + if (!c || !*c || strlen(c) > 2) + return -1; + int x = -1, r; + r = sscanf(c, "%x", &x); + (x < 0 || x > 0xff) &&(x = -1); + return r == 1 ? x : -1; + }; + while (fgets(buf, 1024, f)) + { + ++ln; + if (buf[0] == '#') + continue; + std::string b(buf); + while (b.length() && b.back() == '\n') + b.pop_back(); + std::deque tok; + split(b, ' ', tok); + if (!tok.size()) + continue; + if (tok.front() == "MAP") + { + if (st_inmapping) + err("invalid command") + st_inmapping = true; + } + else if (tok.front() == "ENDMAP") + { + if (!st_inmapping) + err("invalid command") + st_inmapping = false; + } + else if (tok.front() == "X") + { + if (st_inmapping) + err("invalid command") + tok.pop_front(); + std::string sysx; + for (auto &i : tok) + sysx += i; + SEvent ev; + ev.type = 0xF0; + ev.str = ""; + for (auto i = sysx.begin(); i != sysx.end(); ++i) + { + char hn = h2d((char)toupper(*i)); + if (hn < 0) + err("invalid sysex") + if (++i == sysx.end()) + err("invalid sysex") + char ln = h2d((char)toupper(*i)); + ev.str.push_back((char)(hn << 4 | ln)); + } + ret->initseq.appendEvent(ev); + } + else if (tok.front() == "C") + { + if (st_inmapping) + err("invalid command") + if (tok.size() != 4) + err("invalid control") + int ch = hh2d(tok[1].c_str()); + int cc = hh2d(tok[2].c_str()); + int cv = hh2d(tok[3].c_str()); + if (!~cc || !~cv) + err("invalid control parameters") + if (ch == 0xff) + { + for (int i = 0; i < 16; ++i) + { + SEvent e; + e.type = (uint8_t)(0xB0 | i); + e.p1 = (uint8_t)cc; + e.p2 = (uint8_t)cv; + ret->initseq.appendEvent(e); + } + } + else if (ch >= 0 && ch < 0x10) + { + SEvent e; + e.type = (uint8_t)(0xB0 | ch); + e.p1 = (uint8_t)cc; + e.p2 = (uint8_t)cv; + ret->initseq.appendEvent(e); + } + else err("invalid channel") + } + else if (tok.front() == "IV") + { + if (st_inmapping) + err("invalid command") + int ci = 0; + tok.pop_front(); + for (auto &tk : tok) + { + int v = 0, rep = 1; + if (tk.find(',') != std::string::npos) + sscanf(tk.c_str(), "%x,%d", &v, &rep); + else sscanf(tk.c_str(), "%x", &v); + if (v > 0xff || v < 0) + err("invalid init vector value") + for (int i = 0; i < rep; ++i) + { + if (ci >= 130) + err("invalid init vector") + ret->initv[ci++] = (uint8_t)v; + } + } + } + else if (tok.front() == "SIV") + { + if (st_inmapping) + err("invalid command") + int ch = hh2d(tok[1].c_str()); + int cc = hh2d(tok[2].c_str()); + int cv = hh2d(tok[3].c_str()); + ret->sinitv[ch][cc] = uint8_t(cv); + } + else if (st_inmapping) + { + if (b.front() == '[' && b.back() == ']') + { + b = b.substr(1, b.length() - 2); + split(b, ':', tok); + if (tok.size() < 3) + err("invalid bank") + cmsb = strtol(tok[0].c_str(), nullptr, 10); + clsb = strtol(tok[1].c_str(), nullptr, 10); + ret->banks[cmsb << 7 | clsb] = BankStore{{}, tok[2]}; + } + else if (b.find('=') != std::string::npos) + { + if (!~cmsb || !~clsb) + err("inst outside a bank") + split(b, '=', tok); + if (tok.size() < 2) + err("invalid inst") + int p = strtol(tok[0].c_str(), nullptr, 10); + ret->banks[cmsb << 7 | clsb].presets[p] = tok[1]; + } + else err("invalid mapping line") + } + } #undef err - fclose(f); - return ret; + fclose(f); + return ret; } qmpMidiOutRtMidi::qmpMidiOutRtMidi(unsigned _portid) { - portid=_portid; - outport=nullptr; - devinit=nullptr; + portid = _portid; + outport = nullptr; + devinit = nullptr; } qmpMidiOutRtMidi::~qmpMidiOutRtMidi() { - if(!outport)return; - if(devinit){delete devinit;devinit=nullptr;} - if(outport->isPortOpen())outport->closePort(); - delete outport;outport=nullptr; + if (!outport) + return; + if (devinit) + { + delete devinit; + devinit = nullptr; + } + if (outport->isPortOpen()) + outport->closePort(); + delete outport; + outport = nullptr; } void qmpMidiOutRtMidi::deviceInit() { - try - { - outport=new RtMidiOut(); - reset(0xFF); - } - catch(RtMidiError &e) - { - fprintf(stderr,"Cannot create RtMidi Output instance: %s\n",e.what()); - outport=nullptr; - } + try + { + outport = new RtMidiOut(); + reset(0xFF); + } + catch (RtMidiError &e) + { + fprintf(stderr, "Cannot create RtMidi Output instance: %s\n", e.what()); + outport = nullptr; + } } void qmpMidiOutRtMidi::deviceDeinit() { - if(!outport||!outport->isPortOpen())return; - outport->closePort(); + if (!outport || !outport->isPortOpen()) + return; + outport->closePort(); } -void qmpMidiOutRtMidi::basicMessage(uint8_t type,uint8_t p1,uint8_t p2) +void qmpMidiOutRtMidi::basicMessage(uint8_t type, uint8_t p1, uint8_t p2) { - if(!outport||!outport->isPortOpen())return; - std::vectormsg; - msg.push_back(type); - msg.push_back(p1); - if(((type&0xF0)!=0xC0)&&((type&0xF0)!=0xD0)) - msg.push_back(p2); - try - { - outport->sendMessage(&msg); - } - catch(RtMidiError &e) - { - fprintf(stderr,"Failed to send midi message: %s\n",e.what()); - } + if (!outport || !outport->isPortOpen()) + return; + std::vectormsg; + msg.push_back(type); + msg.push_back(p1); + if (((type & 0xF0) != 0xC0) && ((type & 0xF0) != 0xD0)) + msg.push_back(p2); + try + { + outport->sendMessage(&msg); + } + catch (RtMidiError &e) + { + fprintf(stderr, "Failed to send midi message: %s\n", e.what()); + } } -void qmpMidiOutRtMidi::extendedMessage(uint32_t length,const char *data) +void qmpMidiOutRtMidi::extendedMessage(uint32_t length, const char *data) { - if(!outport||!outport->isPortOpen())return; - std::vectormsg(data,data+length); - try - { - outport->sendMessage(&msg); - } - catch(RtMidiError &e) - { - fprintf(stderr,"Failed to send midi message: %s\n",e.what()); - } + if (!outport || !outport->isPortOpen()) + return; + std::vectormsg(data, data + length); + try + { + outport->sendMessage(&msg); + } + catch (RtMidiError &e) + { + fprintf(stderr, "Failed to send midi message: %s\n", e.what()); + } } -void qmpMidiOutRtMidi::rpnMessage(uint8_t ch,uint16_t type,uint16_t val) +void qmpMidiOutRtMidi::rpnMessage(uint8_t ch, uint16_t type, uint16_t val) { - basicMessage(0xB0|ch,0x64,type&0x7F); - basicMessage(0xB0|ch,0x65,type>>7); - basicMessage(0xB0|ch,0x06,val>>7); - basicMessage(0xB0|ch,0x26,val&0x7F); + basicMessage(0xB0 | ch, 0x64, type & 0x7F); + basicMessage(0xB0 | ch, 0x65, type >> 7); + basicMessage(0xB0 | ch, 0x06, val >> 7); + basicMessage(0xB0 | ch, 0x26, val & 0x7F); } -void qmpMidiOutRtMidi::nrpnMessage(uint8_t ch,uint16_t type,uint16_t val) +void qmpMidiOutRtMidi::nrpnMessage(uint8_t ch, uint16_t type, uint16_t val) { - basicMessage(0xB0|ch,0x62,type&0x7F); - basicMessage(0xB0|ch,0x63,type>>7); - basicMessage(0xB0|ch,0x06,val>>7); - basicMessage(0xB0|ch,0x26,val&0x7F); + basicMessage(0xB0 | ch, 0x62, type & 0x7F); + basicMessage(0xB0 | ch, 0x63, type >> 7); + basicMessage(0xB0 | ch, 0x06, val >> 7); + basicMessage(0xB0 | ch, 0x26, val & 0x7F); } void qmpMidiOutRtMidi::panic(uint8_t ch) { - //maybe all notes off is more close to panic? - basicMessage(0xE0|ch,0x0,0x40); - basicMessage(0xB0|ch,123,0); + //maybe all notes off is more close to panic? + basicMessage(0xE0 | ch, 0x0, 0x40); + basicMessage(0xB0 | ch, 123, 0); } void qmpMidiOutRtMidi::reset(uint8_t ch) { - if(ch==0xFF) - { - if(devinit) - for(auto&msg:devinit->initseq.eventList) - { - if((msg.type&0xF0)==0xF0) - extendedMessage(msg.str.length(),msg.str.data()); - else - basicMessage(msg.type,msg.p1,msg.p2); - } - } - else - { - basicMessage(0xB0|ch,121,0); - basicMessage(0xB0|ch,123,0); - } + if (ch == 0xFF) + { + if (devinit) + for (auto &msg : devinit->initseq.eventList) + { + if ((msg.type & 0xF0) == 0xF0) + extendedMessage(msg.str.length(), msg.str.data()); + else + basicMessage(msg.type, msg.p1, msg.p2); + } + } + else + { + basicMessage(0xB0 | ch, 121, 0); + basicMessage(0xB0 | ch, 123, 0); + } } -void qmpMidiOutRtMidi::onMapped(uint8_t,int) +void qmpMidiOutRtMidi::onMapped(uint8_t, int) { - if(!outport)deviceInit(); - if(outport->isPortOpen())return; - try - { - outport->openPort(portid); - } - catch(RtMidiError &e) - { - fprintf(stderr,"Device initialization failure: %s\n",e.what()); - } + if (!outport) + deviceInit(); + if (outport->isPortOpen()) + return; + try + { + outport->openPort(portid); + } + catch (RtMidiError &e) + { + fprintf(stderr, "Device initialization failure: %s\n", e.what()); + } } -void qmpMidiOutRtMidi::onUnmapped(uint8_t ch,int refcnt) +void qmpMidiOutRtMidi::onUnmapped(uint8_t ch, int refcnt) { - panic(ch); - if(!refcnt&&outport)outport->closePort(); + panic(ch); + if (!refcnt && outport) + outport->closePort(); } -std::vector> qmpMidiOutRtMidi::getBankList() +std::vector> qmpMidiOutRtMidi::getBankList() { - if(!devinit)return{}; - std::vector> ret; - for(auto&i:devinit->banks) - ret.push_back({i.first,i.second.bankname}); - std::sort(ret.begin(),ret.end(),[](std::pair&a,std::pair&b){return a.first> ret; + for (auto &i : devinit->banks) + ret.push_back({i.first, i.second.bankname}); + std::sort(ret.begin(), ret.end(), [](std::pair &a, std::pair &b) + { + return a.first < b.first; + }); + return ret; } -std::vector> qmpMidiOutRtMidi::getPresets(uint16_t bank) +std::vector> qmpMidiOutRtMidi::getPresets(uint16_t bank) { - if(!devinit)return{}; - if(devinit->banks.find(bank)==devinit->banks.end())return{}; - std::vector> ret; - for(auto&i:devinit->banks[bank].presets) - ret.push_back({i.first,i.second}); - std::sort(ret.begin(),ret.end(),[](std::pair&a,std::pair&b){return a.firstbanks.find(bank) == devinit->banks.end()) + return{}; + std::vector> ret; + for (auto &i : devinit->banks[bank].presets) + ret.push_back({i.first, i.second}); + std::sort(ret.begin(), ret.end(), [](std::pair &a, std::pair &b) + { + return a.first < b.first; + }); + return ret; } -std::string qmpMidiOutRtMidi::getPresetName(uint16_t bank,uint8_t preset) +std::string qmpMidiOutRtMidi::getPresetName(uint16_t bank, uint8_t preset) { - if(!devinit)return""; - if(devinit->banks.find(bank)!=devinit->banks.end()) - if(devinit->banks[bank].presets.find(preset)!=devinit->banks[bank].presets.end()) - return devinit->banks[bank].presets[preset]; - return""; + if (!devinit) + return std::string(); + if (devinit->banks.find(bank) != devinit->banks.end()) + if (devinit->banks[bank].presets.find(preset) != devinit->banks[bank].presets.end()) + return devinit->banks[bank].presets[preset]; + return std::string(); } -bool qmpMidiOutRtMidi::getChannelPreset(int ch,uint16_t *bank,uint8_t *preset,std::string &presetname) +bool qmpMidiOutRtMidi::getChannelPreset(int ch, uint16_t *bank, uint8_t *preset, std::string &presetname) { - //This ain't a state-tracking device - return false; + //This ain't a state-tracking device + return false; } -uint8_t qmpMidiOutRtMidi::getInitialCCValue(uint8_t cc,uint8_t ch) +uint8_t qmpMidiOutRtMidi::getInitialCCValue(uint8_t cc, uint8_t ch) { - if(!devinit||cc>=130)return 0;//Nope! - if(ch<16&&devinit->sinitv[ch][cc]!=0xFF) - return devinit->sinitv[ch][cc]; - return devinit->initv[cc]; + if (!devinit || cc >= 130) + return 0; + if (ch < 16 && devinit->sinitv[ch][cc] != 0xFF) + return devinit->sinitv[ch][cc]; + return devinit->initv[cc]; } -void qmpMidiOutRtMidi::setInitializerFile(const char* path) +void qmpMidiOutRtMidi::setInitializerFile(const char *path) { - if(devinit)delete devinit; - devinit=qmpDeviceInitializer::parse(path); - reset(0xFF); + if (devinit) + delete devinit; + devinit = qmpDeviceInitializer::parse(path); + reset(0xFF); } -std::vector> qmpRtMidiManager::devices; -std::vector> qmpRtMidiManager::getDevices() +std::vector> qmpRtMidiManager::devices; +std::vector> qmpRtMidiManager::getDevices() { - if(devices.size())return devices; - RtMidiOut *dummy; - try{dummy=new RtMidiOut();} - catch(RtMidiError &e) - { - fprintf(stderr,"Failed to initialize the dummy device: %s\n",e.what()); - return{}; - } - for(unsigned i=0;igetPortCount();++i) - devices.push_back(std::make_pair(new qmpMidiOutRtMidi(i),dummy->getPortName(i))); - delete dummy; - return devices; + if (devices.size()) + return devices; + RtMidiOut *dummy; + try + { + dummy = new RtMidiOut(); + } + catch (RtMidiError &e) + { + fprintf(stderr, "Failed to initialize the dummy device: %s\n", e.what()); + return{}; + } + for (unsigned i = 0; i < dummy->getPortCount(); ++i) + devices.push_back(std::make_pair(new qmpMidiOutRtMidi(i), dummy->getPortName(i))); + delete dummy; + return devices; } diff --git a/core/qmpmidioutrtmidi.hpp b/core/qmpmidioutrtmidi.hpp index 45662ba..8276cce 100644 --- a/core/qmpmidioutrtmidi.hpp +++ b/core/qmpmidioutrtmidi.hpp @@ -6,53 +6,53 @@ #include "../include/qmpcorepublic.hpp" struct qmpDeviceInitializer { - CMidiTrack initseq; - struct BankStore - { - std::unordered_map presets; - std::string bankname; - }; - std::unordered_map banks; - uint8_t initv[130]; - uint8_t sinitv[16][130]; + CMidiTrack initseq; + struct BankStore + { + std::unordered_map presets; + std::string bankname; + }; + std::unordered_map banks; + uint8_t initv[130]; + uint8_t sinitv[16][130]; - static qmpDeviceInitializer* parse(const char* path); + static qmpDeviceInitializer *parse(const char *path); }; class RtMidiOut; -class qmpMidiOutRtMidi:public qmpMidiOutDevice +class qmpMidiOutRtMidi : public qmpMidiOutDevice { private: - unsigned portid; - RtMidiOut* outport; - qmpDeviceInitializer* devinit; + unsigned portid; + RtMidiOut *outport; + qmpDeviceInitializer *devinit; public: - qmpMidiOutRtMidi(unsigned _portid); - ~qmpMidiOutRtMidi(); - void deviceInit(); - void deviceDeinit(); - void basicMessage(uint8_t type,uint8_t p1,uint8_t p2); - void extendedMessage(uint32_t length,const char *data); - void rpnMessage(uint8_t ch,uint16_t type,uint16_t val); - void nrpnMessage(uint8_t ch,uint16_t type,uint16_t val); - void panic(uint8_t ch); - void reset(uint8_t ch); - void onMapped(uint8_t ch,int refcnt); - void onUnmapped(uint8_t ch,int refcnt); - std::vector> getBankList(); - std::vector> getPresets(uint16_t bank); - std::string getPresetName(uint16_t bank,uint8_t preset); - bool getChannelPreset(int ch,uint16_t *bank,uint8_t *preset,std::string &presetname); - uint8_t getInitialCCValue(uint8_t cc,uint8_t ch); + qmpMidiOutRtMidi(unsigned _portid); + ~qmpMidiOutRtMidi(); + void deviceInit(); + void deviceDeinit(); + void basicMessage(uint8_t type, uint8_t p1, uint8_t p2); + void extendedMessage(uint32_t length, const char *data); + void rpnMessage(uint8_t ch, uint16_t type, uint16_t val); + void nrpnMessage(uint8_t ch, uint16_t type, uint16_t val); + void panic(uint8_t ch); + void reset(uint8_t ch); + void onMapped(uint8_t ch, int refcnt); + void onUnmapped(uint8_t ch, int refcnt); + std::vector> getBankList(); + std::vector> getPresets(uint16_t bank); + std::string getPresetName(uint16_t bank, uint8_t preset); + bool getChannelPreset(int ch, uint16_t *bank, uint8_t *preset, std::string &presetname); + uint8_t getInitialCCValue(uint8_t cc, uint8_t ch); - void setInitializerFile(const char* path); + void setInitializerFile(const char *path); }; class qmpRtMidiManager { - private: - static std::vector> devices; - public: - static std::vector> getDevices(); +private: + static std::vector> devices; +public: + static std::vector> getDevices(); }; #endif // QMPMIDIMAPPERS_H diff --git a/core/qmpmidiplay.cpp b/core/qmpmidiplay.cpp index a354d6e..c987e01 100644 --- a/core/qmpmidiplay.cpp +++ b/core/qmpmidiplay.cpp @@ -9,609 +9,778 @@ #include uint64_t pf; #endif -CMidiPlayer* CMidiPlayer::ref=nullptr; +CMidiPlayer *CMidiPlayer::ref = nullptr; bool CMidiPlayer::processEvent(const SEvent *e) { - SEvent fe(*e); - fe.flags&=0xfe; - if(tceptr>=eorder.size()-1||getEvent(tceptr+1)->time>e->time) - fe.flags|=0x01; - for(int i=0;i<16;++i)if(eventHandlerCB[i]) - eventHandlerCB[i]->callBack((void*)&fe,eventHandlerCBuserdata[i]); - for(auto i=event_handlers.begin();i!=event_handlers.end();++i) - if(!std::get<2>(i->second)) - std::get<0>(i->second)((void*)e,std::get<1>(i->second)); - uint8_t ch=e->type&0x0F; - if((e->type&0xF0)<0xF0) - levtt[ch]=std::chrono::system_clock::now(); - switch(e->type&0xF0) - { - case 0x80://Note off - return true; - case 0x90://Note on - if((mute>>ch)&1&&e->p2)return false;//muted - if(solo&&!((solo>>ch)&1)&&e->p2)return false;//excluded by solo flags - return true; - case 0xB0://CC - if(e->p1==100)rpnid[ch]=e->p2; - if(e->p1==6)rpnval[ch]=e->p2; - if(~rpnid[ch]&&~rpnval[ch]) - { - if(rpnid[ch]==0) - { - mididev[mappedoutput[ch]].dev->rpnMessage(ch,0,rpnval[ch]<<7); - pbr[ch]=rpnval[ch]; - } - rpnid[ch]=rpnval[ch]=-1; - } - chstatus[ch][e->p1]=e->p2; - return true; - case 0xC0://PC - chstatus[ch][128]=e->p1; - return true; - case 0xE0://PW - pbv[ch]=(e->p1|(e->p2<<7))&0x3FFF; - return true; - case 0xF0://Meta/SysEx - if((e->type&0x0F)==0x0F) - { - switch(e->p1) - { - case 0x51: - { - ctempo=0; + SEvent fe(*e); + fe.flags &= 0xfe; + if (tceptr >= eorder.size() - 1 || getEvent(tceptr + 1)->time > e->time) + fe.flags |= 0x01; + for (int i = 0; i < 16; ++i) + if (eventHandlerCB[i]) + eventHandlerCB[i]->callBack((void *)&fe, eventHandlerCBuserdata[i]); + for (auto i = event_handlers.begin(); i != event_handlers.end(); ++i) + if (!std::get<2>(i->second)) + std::get<0>(i->second)((void *)e, std::get<1>(i->second)); + uint8_t ch = e->type & 0x0F; + if ((e->type & 0xF0) < 0xF0) + levtt[ch] = std::chrono::system_clock::now(); + switch (e->type & 0xF0) + { + case 0x80://Note off + return true; + case 0x90://Note on + if ((mute >> ch) & 1 && e->p2) + return false; //muted + if (solo && !((solo >> ch) & 1) && e->p2) + return false; //excluded by solo flags + return true; + case 0xB0://CC + if (e->p1 == 100) + rpnid[ch] = e->p2; + if (e->p1 == 6) + rpnval[ch] = e->p2; + if (~rpnid[ch] && ~rpnval[ch]) + { + if (rpnid[ch] == 0) + { + mididev[mappedoutput[ch]].dev->rpnMessage(ch, 0, rpnval[ch] << 7); + pbr[ch] = rpnval[ch]; + } + rpnid[ch] = rpnval[ch] = -1; + } + chstatus[ch][e->p1] = e->p2; + return true; + case 0xC0://PC + chstatus[ch][128] = e->p1; + return true; + case 0xE0://PW + pbv[ch] = (e->p1 | (e->p2 << 7)) & 0x3FFF; + return true; + case 0xF0://Meta/SysEx + if ((e->type & 0x0F) == 0x0F) + { + switch (e->p1) + { + case 0x51: + { + ctempo = 0; #if (__BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__)||defined(_WIN32) - std::string x(e->str); - std::reverse(x.begin(),x.end()); - memcpy(&ctempo,x.data(),3); + std::string x(e->str); + std::reverse(x.begin(), x.end()); + memcpy(&ctempo, x.data(), 3); #else - memcpy(&ctempo,e->str.data(),3); - ctempo>>=8; + memcpy(&ctempo, e->str.data(), 3); + ctempo >>= 8; #endif - dpt=ctempo*1000./divs; - ttime=std::chrono::high_resolution_clock::now(); - ttick=getTick(); - } - break; - case 0x58: - ctsn=(uint32_t)e->str[0]; - ctsd=1<<((uint32_t)e->str[1]); - break; - case 0x59: - if(e->str.length()==2) - cks=(e->str[0]<<8u)|e->str[1]; - break; - case 0x01:case 0x02:case 0x03: - case 0x04:case 0x05:case 0x06: - case 0x07: - //if(e->str)puts(e->str); - break; - } - } - if(((e->type&0x0F)==0x00||(e->type&0x0F)==07)&&sendSysEx) - for(auto& i:mididev) - if(i.refcnt) - i.dev->extendedMessage(uint32_t(e->str.length()),e->str.c_str()); - return false; - } - return false; + dpt = ctempo * 1000. / divs; + ttime = std::chrono::high_resolution_clock::now(); + ttick = getTick(); + } + break; + case 0x58: + ctsn = (uint32_t)e->str[0]; + ctsd = 1 << ((uint32_t)e->str[1]); + break; + case 0x59: + if (e->str.length() == 2) + cks = (e->str[0] << 8u) | e->str[1]; + break; + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + //if(e->str)puts(e->str); + break; + } + } + if (((e->type & 0x0F) == 0x00 || (e->type & 0x0F) == 07) && sendSysEx) + for (auto &i : mididev) + if (i.refcnt) + i.dev->extendedMessage(uint32_t(e->str.length()), e->str.c_str()); + return false; + } + return false; } void CMidiPlayer::processEventStub(const SEvent *e) { - switch(e->type&0xF0) - { - case 0xB0://CC - if(e->p1==100)rpnid[e->type&0x0F]=e->p2; - if(e->p1==6)rpnval[e->type&0x0F]=e->p2; - if(~rpnid[e->type&0x0F]&&~rpnval[e->type&0x0F]) - { - if(rpnid[e->type&0x0F]==0)ccc[e->type&0x0F][134]=rpnval[e->type&0x0F]; - rpnval[e->type&0x0F]=-1; - } - ccc[e->type&0x0F][e->p1]=e->p2; - break; - case 0xC0://PC - ccc[e->type&0x0F][128]=e->p1; - break; - case 0xD0://CP - ccc[e->type&0x0F][129]=e->p1; - break; - case 0xE0://PW - ccc[e->type&0x0F][130]=(e->p1|(e->p2<<7))&0x3FFF; - break; - case 0xF0://Meta/SysEx - if((e->type&0x0F)==0x0F) - { - switch(e->p1) - { - case 0x51: - { - ctempo=0; + switch (e->type & 0xF0) + { + case 0xB0://CC + if (e->p1 == 100) + rpnid[e->type & 0x0F] = e->p2; + if (e->p1 == 6) + rpnval[e->type & 0x0F] = e->p2; + if (~rpnid[e->type & 0x0F] && ~rpnval[e->type & 0x0F]) + { + if (rpnid[e->type & 0x0F] == 0) + ccc[e->type & 0x0F][134] = rpnval[e->type & 0x0F]; + rpnval[e->type & 0x0F] = -1; + } + ccc[e->type & 0x0F][e->p1] = e->p2; + break; + case 0xC0://PC + ccc[e->type & 0x0F][128] = e->p1; + break; + case 0xD0://CP + ccc[e->type & 0x0F][129] = e->p1; + break; + case 0xE0://PW + ccc[e->type & 0x0F][130] = (e->p1 | (e->p2 << 7)) & 0x3FFF; + break; + case 0xF0://Meta/SysEx + if ((e->type & 0x0F) == 0x0F) + { + switch (e->p1) + { + case 0x51: + { + ctempo = 0; #if (__BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__)||defined(_WIN32) - std::string x(e->str); - std::reverse(x.begin(),x.end()); - memcpy(&ctempo,x.data(),3); + std::string x(e->str); + std::reverse(x.begin(), x.end()); + memcpy(&ctempo, x.data(), 3); #else - memcpy(&ctempo,e->str.data(),3); - ctempo>>=8; + memcpy(&ctempo, e->str.data(), 3); + ctempo >>= 8; #endif - dpt=ctempo*1000./divs; - ccc[0][131]=ctempo; - } - break; - case 0x58: - ccc[0][132]=(e->str[0]<<24u)|(e->str[1]<<16u); - break; - case 0x59: - if(e->str.length()>=2) - ccc[0][133]=(e->str[0]<<8u)|e->str[1]; - break; - } - } - break; - } + dpt = ctempo * 1000. / divs; + ccc[0][131] = ctempo; + } + break; + case 0x58: + ccc[0][132] = (e->str[0] << 24u) | (e->str[1] << 16u); + break; + case 0x59: + if (e->str.length() >= 2) + ccc[0][133] = (e->str[0] << 8u) | e->str[1]; + break; + } + } + break; + } } #ifdef _WIN32 void w32usleep(uint64_t t) { - uint64_t st=0,ct=0; - timeBeginPeriod(1); - QueryPerformanceCounter((LARGE_INTEGER*)&st); - do{ - if(t>10000+(ct-st)*1000000/pf)Sleep((t-(ct-st)*1000000/pf)/2000); - else if(t>5000+(ct-st)*1000000/pf)Sleep(1); - else std::this_thread::yield(); - QueryPerformanceCounter((LARGE_INTEGER*)&ct); - }while((ct-st)*1000000 10000 + (ct - st) * 1000000 / pf) + Sleep((t - (ct - st) * 1000000 / pf) / 2000); + else if (t > 5000 + (ct - st) * 1000000 / pf) + Sleep(1); + else + std::this_thread::yield(); + QueryPerformanceCounter((LARGE_INTEGER *)&ct); + } while ((ct - st) * 1000000 < t * pf); + timeEndPeriod(1); } #endif -SEvent* CMidiPlayer::getEvent(uint32_t id) +SEvent *CMidiPlayer::getEvent(uint32_t id) { - size_t t=eorder[id].first,e=eorder[id].second; - return &midiFile->tracks[t].eventList[e]; + size_t t = eorder[id].first, e = eorder[id].second; + return &midiFile->tracks[t].eventList[e]; } void CMidiPlayer::prePlayInit() { - playerPanic(true); - for(size_t i=0;ireset(0xFF); + playerPanic(true); + for (size_t i = 0; i < mididev.size(); ++i) + if (mididev[i].refcnt) + mididev[i].dev->reset(0xFF); } void CMidiPlayer::playEvents() { - static uint32_t _lrtick;_lrtick=0; - ttick=getEvent(0)->time;ttime=std::chrono::high_resolution_clock::now(); - for(ct=getEvent(0)->time;tceptrtime; - ttick=getTick(); - ttime=high_resolution_clock::now(); - continue; - } - high_resolution_clock::time_point b=high_resolution_clock::now(); - if(getTick()-_lrtick>divs){ - _lrtick=getTick(); - //double _dt=(getTick()-ttick)*dpt-duration_cast((b-ttime)).count(); - //<0: slower than expected, >0: faster than expected - //fprintf(stderr,"@ tick %u, dtime %.6fus",getTick(),_dt/1000.); - } - for(;!tcstop&&midiReaders&&tceptrtime;++tceptr) - { - if(processEvent(getEvent(tceptr))) - { - SEvent* e=getEvent(tceptr); - mididev[mappedoutput[e->type&0x0F]].dev->basicMessage(e->type,e->p1,e->p2); - } - for(auto i=event_handlers.begin();i!=event_handlers.end();++i) - if(std::get<2>(i->second)) - std::get<0>(i->second)((void*)getEvent(tceptr),std::get<1>(i->second)); - } - if(tcstop||!midiReaders||tceptr>=ecnt)break; - high_resolution_clock::time_point a=high_resolution_clock::now(); - auto sendtime=a-b; - if(sendtime.count()<(getEvent(tceptr)->time-ct)*dpt) - { - double ns_sleep=(getEvent(tceptr)->time-ct)*dpt-sendtime.count(); - double correction=(getTick()-ttick)*dpt-(b-ttime).count(); - if(correction>0)correction=0; + static uint32_t _lrtick; + _lrtick = 0; + ttick = getEvent(0)->time; + ttime = std::chrono::high_resolution_clock::now(); + for (ct = getEvent(0)->time; tceptr < ecnt;) + { + using namespace std::chrono; + while (tcpaused) + std::this_thread::sleep_for(milliseconds(100)); + if (resumed) + { + resumed = false; + ct = getEvent(tceptr)->time; + ttick = getTick(); + ttime = high_resolution_clock::now(); + continue; + } + high_resolution_clock::time_point b = high_resolution_clock::now(); + if (getTick() - _lrtick > divs) + { + _lrtick = getTick(); + //double _dt=(getTick()-ttick)*dpt-duration_cast((b-ttime)).count(); + //<0: slower than expected, >0: faster than expected + //fprintf(stderr,"@ tick %u, dtime %.6fus",getTick(),_dt/1000.); + } + for (; !tcstop && midiReaders && tceptr < ecnt && ct == getEvent(tceptr)->time; ++tceptr) + { + if (processEvent(getEvent(tceptr))) + { + SEvent *e = getEvent(tceptr); + mididev[mappedoutput[e->type & 0x0F]].dev->basicMessage(e->type, e->p1, e->p2); + } + for (auto i = event_handlers.begin(); i != event_handlers.end(); ++i) + if (std::get<2>(i->second)) + std::get<0>(i->second)((void *)getEvent(tceptr), std::get<1>(i->second)); + } + if (tcstop || !midiReaders || tceptr >= ecnt) + break; + high_resolution_clock::time_point a = high_resolution_clock::now(); + auto sendtime = a - b; + if (sendtime.count() < (getEvent(tceptr)->time - ct)*dpt) + { + double ns_sleep = (getEvent(tceptr)->time - ct) * dpt - sendtime.count(); + double correction = (getTick() - ttick) * dpt - (b - ttime).count(); + if (correction > 0) + correction = 0; #ifdef _WIN32 - w32usleep((uint64_t)(((getEvent(tceptr)->time-ct)*dpt-sendtime.count())/1000)); + w32usleep((uint64_t)(((getEvent(tceptr)->time - ct)*dpt - sendtime.count()) / 1000)); #else - std::this_thread::sleep_for(std::chrono::nanoseconds((uint64_t)(ns_sleep+correction))); + std::this_thread::sleep_for(std::chrono::nanoseconds((uint64_t)(ns_sleep + correction))); #endif - } - if(tcstop||!midiReaders)break; - ct=getEvent(tceptr)->time; - } - if(tceptr>=ecnt) - finished=1; + } + if (tcstop || !midiReaders) + break; + ct = getEvent(tceptr)->time; + } + if (tceptr >= ecnt) + finished = 1; } void CMidiPlayer::fileTimer1Pass() { - ftime=.0;ctempo=0x7A120;dpt=ctempo*1000./divs; - for(uint32_t eptr=0,ct=getEvent(0)->time;eptrtime) - processEventStub(getEvent(eptr++)); - if(eptr>=ecnt)break; - ftime+=(getEvent(eptr)->time-ct)*dpt/1e9; - ct=getEvent(eptr)->time; - } + ftime = .0; + ctempo = 0x7A120; + dpt = ctempo * 1000. / divs; + for (uint32_t eptr = 0, ct = getEvent(0)->time; eptr < ecnt;) + { + while (eptr < ecnt && ct == getEvent(eptr)->time) + processEventStub(getEvent(eptr++)); + if (eptr >= ecnt) + break; + ftime += (getEvent(eptr)->time - ct) * dpt / 1e9; + ct = getEvent(eptr)->time; + } } void CMidiPlayer::fileTimer2Pass() { - double ctime=.0;uint32_t c=1;ctempo=0x7A120;dpt=ctempo*1000./divs; - memset(stamps,0,sizeof(stamps));memset(ccstamps,0,sizeof(ccstamps)); - memset(ccc,0,sizeof(ccc));memset(rpnid,0xFF,sizeof(rpnid));memset(rpnval,0xFF,sizeof(rpnval)); - for(int i=0;i<16;++i) - { - memset(ccc[i],0xFF,128*sizeof(uint32_t)); - ccc[i][131]=ctempo;ccc[i][132]=0x04021808; - ccc[i][133]=0;ccc[i][134]=2; - } - for(int i=0;i<16;++i)for(int j=0;j<135;++j) - ccstamps[0][i][j]=ccc[i][j]; - for(uint32_t eptr=0,ct=getEvent(0)->time;eptrtime) - processEventStub(getEvent(eptr++)); - if(eptr>=ecnt)break; - ctime+=(getEvent(eptr)->time-ct)*dpt/1e9; - while(ctime>ftime*c/100.) - { - for(int i=0;i<16;++i)for(int j=0;j<135;++j) - ccstamps[c][i][j]=ccc[i][j]; - stamps[c++]=eptr; - if(c>100)break; - } - ct=getEvent(eptr)->time; - } - while(c<101) - { - for(int i=0;i<16;++i)for(int j=0;j<135;++j) - ccstamps[c][i][j]=ccc[i][j]; - stamps[c++]=ecnt; - } + double ctime = .0; + uint32_t c = 1; + ctempo = 0x7A120; + dpt = ctempo * 1000. / divs; + memset(stamps, 0, sizeof(stamps)); + memset(ccstamps, 0, sizeof(ccstamps)); + memset(ccc, 0, sizeof(ccc)); + memset(rpnid, 0xFF, sizeof(rpnid)); + memset(rpnval, 0xFF, sizeof(rpnval)); + for (int i = 0; i < 16; ++i) + { + memset(ccc[i], 0xFF, 128 * sizeof(uint32_t)); + ccc[i][131] = ctempo; + ccc[i][132] = 0x04021808; + ccc[i][133] = 0; + ccc[i][134] = 2; + } + for (int i = 0; i < 16; ++i) + for (int j = 0; j < 135; ++j) + ccstamps[0][i][j] = ccc[i][j]; + for (uint32_t eptr = 0, ct = getEvent(0)->time; eptr < ecnt;) + { + while (eptr < ecnt && ct == getEvent(eptr)->time) + processEventStub(getEvent(eptr++)); + if (eptr >= ecnt) + break; + ctime += (getEvent(eptr)->time - ct) * dpt / 1e9; + while (ctime > ftime * c / 100.) + { + for (int i = 0; i < 16; ++i) + for (int j = 0; j < 135; ++j) + ccstamps[c][i][j] = ccc[i][j]; + stamps[c++] = eptr; + if (c > 100) + break; + } + ct = getEvent(eptr)->time; + } + while (c < 101) + { + for (int i = 0; i < 16; ++i) + for (int j = 0; j < 135; ++j) + ccstamps[c][i][j] = ccc[i][j]; + stamps[c++] = ecnt; + } } CMidiPlayer::CMidiPlayer() { - midiReaders=new CMidiFileReaderCollection(); - resumed=false;midiFile=nullptr; - waitvoice=true; - event_handlers_id=event_read_handlers_id=file_read_finish_hooks_id=0; - memset(eventHandlerCB,0,sizeof(eventHandlerCB)); - memset(eventHandlerCBuserdata,0,sizeof(eventHandlerCBuserdata)); - memset(eventReaderCB,0,sizeof(eventReaderCB)); - memset(eventReaderCBuserdata,0,sizeof(eventReaderCBuserdata)); - memset(fileReadFinishCB,0,sizeof(fileReadFinishCB)); - memset(fileReadFinishCBuserdata,0,sizeof(fileReadFinishCBuserdata)); - memset(mappedoutput,0xff,sizeof(mappedoutput)); - memset(chstatus,0,sizeof(chstatus)); - for(int i=0;i<16;++i) - memset(chstatus[i],0xff,128*sizeof(uint8_t)); + midiReaders = new CMidiFileReaderCollection(); + resumed = false; + midiFile = nullptr; + waitvoice = true; + event_handlers_id = event_read_handlers_id = file_read_finish_hooks_id = 0; + memset(eventHandlerCB, 0, sizeof(eventHandlerCB)); + memset(eventHandlerCBuserdata, 0, sizeof(eventHandlerCBuserdata)); + memset(eventReaderCB, 0, sizeof(eventReaderCB)); + memset(eventReaderCBuserdata, 0, sizeof(eventReaderCBuserdata)); + memset(fileReadFinishCB, 0, sizeof(fileReadFinishCB)); + memset(fileReadFinishCBuserdata, 0, sizeof(fileReadFinishCBuserdata)); + memset(mappedoutput, 0xff, sizeof(mappedoutput)); + memset(chstatus, 0, sizeof(chstatus)); + for (int i = 0; i < 16; ++i) + memset(chstatus[i], 0xff, 128 * sizeof(uint8_t)); #ifdef _WIN32 - QueryPerformanceFrequency((LARGE_INTEGER*)&pf); + QueryPerformanceFrequency((LARGE_INTEGER *)&pf); #endif - ref=this; + ref = this; } CMidiPlayer::~CMidiPlayer() { - if(midiFile)delete midiFile;delete midiReaders; + if (midiFile) + delete midiFile; + delete midiReaders; } void CMidiPlayer::playerPanic(bool reset) { - for(auto& i:mididev) - if(i.refcnt) - { - for(uint8_t j=0;j<16;++j) - reset?i.dev->reset(j):i.dev->panic(j); - } -} -bool CMidiPlayer::playerLoadFile(const char* fn) -{ - notes=0;if(midiFile)delete midiFile; - midiFile=midiReaders->readFile(fn); - if(!midiFile||!midiFile->valid)return false; - divs=midiFile->divs;maxtk=ecnt=0; - for(CMidiTrack& i:midiFile->tracks) - { - ecnt+=i.eventList.size(); - if(i.eventList.size()) - maxtk=std::max(maxtk,i.eventList.back().time); - } - for(int i=0;i<16;++i)if(fileReadFinishCB[i]) - fileReadFinishCB[i]->callBack(nullptr,fileReadFinishCBuserdata[i]); - for(auto i=file_read_finish_hooks.begin();i!=file_read_finish_hooks.end();++i) - i->second.first(nullptr,i->second.second); - eorder.clear(); - for(size_t i=0;itracks.size();++i) - for(size_t j=0;jtracks[i].eventList.size();++j) - eorder.push_back(std::make_pair(i,j)); - std::sort(eorder.begin(),eorder.end(), - [this](std::pair &a,std::pair &b)->bool{ - return midiFile->tracks[a.first].eventList[a.second]< - midiFile->tracks[b.first].eventList[b.second]; - } - ); - fileTimer1Pass(); - fileTimer2Pass(); - return true; + for (auto &i : mididev) + if (i.refcnt) + { + for (uint8_t j = 0; j < 16; ++j) + reset ? i.dev->reset(j) : i.dev->panic(j); + } +} +bool CMidiPlayer::playerLoadFile(const char *fn) +{ + notes = 0; + if (midiFile) + delete midiFile; + midiFile = midiReaders->readFile(fn); + if (!midiFile || !midiFile->valid) + return false; + divs = midiFile->divs; + maxtk = ecnt = 0; + for (CMidiTrack &i : midiFile->tracks) + { + ecnt += i.eventList.size(); + if (i.eventList.size()) + maxtk = std::max(maxtk, i.eventList.back().time); + } + for (int i = 0; i < 16; ++i) + if (fileReadFinishCB[i]) + fileReadFinishCB[i]->callBack(nullptr, fileReadFinishCBuserdata[i]); + for (auto i = file_read_finish_hooks.begin(); i != file_read_finish_hooks.end(); ++i) + i->second.first(nullptr, i->second.second); + eorder.clear(); + for (size_t i = 0; i < midiFile->tracks.size(); ++i) + for (size_t j = 0; j < midiFile->tracks[i].eventList.size(); ++j) + eorder.push_back(std::make_pair(i, j)); + std::sort(eorder.begin(), eorder.end(), + [this](std::pair &a, std::pair &b)->bool + { + return midiFile->tracks[a.first].eventList[a.second] < + midiFile->tracks[b.first].eventList[b.second]; + }); + fileTimer1Pass(); + fileTimer2Pass(); + return true; } void CMidiPlayer::playerInit() { - ctempo=0x7A120;ctsn=4;ctsd=4;cks=0;dpt=ctempo*1000./divs; - tceptr=0;tcstop=false;tcpaused=0;finished=0;mute=solo=0; - for(int i=0;i<16;++i)pbr[i]=2,pbv[i]=8192; - sendSysEx=true;memset(rpnid,0xFF,sizeof(rpnid));memset(rpnval,0xFF,sizeof(rpnval)); - memset(chstatus,0,sizeof(chstatus)); - for(int i=0;i<16;++i) - memset(chstatus[i],0xff,128*sizeof(uint8_t)); + ctempo = 0x7A120; + ctsn = 4; + ctsd = 4; + cks = 0; + dpt = ctempo * 1000. / divs; + tceptr = 0; + tcstop = false; + tcpaused = 0; + finished = 0; + mute = solo = 0; + for (int i = 0; i < 16; ++i) + pbr[i] = 2, pbv[i] = 8192; + sendSysEx = true; + memset(rpnid, 0xFF, sizeof(rpnid)); + memset(rpnval, 0xFF, sizeof(rpnval)); + memset(chstatus, 0, sizeof(chstatus)); + for (int i = 0; i < 16; ++i) + memset(chstatus[i], 0xff, 128 * sizeof(uint8_t)); } void CMidiPlayer::playerDeinit() { - tceptr=0;tcstop=true;tcpaused=0; - delete midiFile;midiFile=nullptr; + tceptr = 0; + tcstop = true; + tcpaused = 0; + delete midiFile; + midiFile = nullptr; } void CMidiPlayer::playerThread() { - prePlayInit(); - playEvents(); + prePlayInit(); + playEvents(); } -void CMidiPlayer::sendSysX(bool send){sendSysEx=send;} -uint32_t CMidiPlayer::getStamp(int id){return stamps[id];} -uint32_t CMidiPlayer::getTCeptr(){return tceptr;} -void CMidiPlayer::setTCeptr(uint32_t ep,uint32_t st) -{ - resumed=true; - if(ep==ecnt)tcstop=true;else tceptr=ep; - for(int i=0;i<16;++i) - { - qmpMidiOutDevice* dest=mididev[mappedoutput[i]].dev; - for(int j=0;j<120;++j) - { - if(~ccstamps[st][i][j]) - { - dest->basicMessage(0xB0|i,j,ccstamps[st][i][j]); - chstatus[i][j]=ccstamps[st][i][j]; - } - } - dest->basicMessage(0xC0|i,ccstamps[st][i][128],0); - chstatus[i][128]=ccstamps[st][i][128]; - dest->rpnMessage(i,0,ccstamps[st][i][134]<<7); - pbr[i]=ccstamps[st][i][134]; - ctempo=ccstamps[st][0][131];dpt=ctempo*1000./divs; - ctsn=ccstamps[st][0][132]>>24;ctsd=1<<((ccstamps[st][0][132]>>16)&0xFF); - cks=ccstamps[st][0][133]; - } -} -double CMidiPlayer::getFtime(){return ftime;} -void CMidiPlayer::getCurrentTimeSignature(int *n,int *d){*n=ctsn;*d=ctsd;} -int CMidiPlayer::getCurrentKeySignature(){return cks;} -uint32_t CMidiPlayer::getFileNoteCount(){return notes;} -uint32_t CMidiPlayer::getFileStandard(){return midiFile?midiFile->std:0;} -const char* CMidiPlayer::getTitle(){return midiFile?midiFile->title:"";} -const char* CMidiPlayer::getCopyright(){return midiFile?midiFile->copyright:"";} -double CMidiPlayer::getTempo(){return 60./(ctempo/1e6);} -uint32_t CMidiPlayer::getTick(){return ct;} -uint32_t CMidiPlayer::getRawTempo(){return ctempo;} -uint32_t CMidiPlayer::getDivision(){return divs;} -uint32_t CMidiPlayer::getMaxTick(){return maxtk;} -double CMidiPlayer::getPitchBend(int ch){return((int)pbv[ch]-8192)/8192.*pbr[ch];} -double CMidiPlayer::getPitchBendRaw(int ch,uint32_t *pb,uint32_t *pbr) -{ - if(pb)*pb=this->pbv[ch]; - if(pbr)*pbr=this->pbr[ch]; -} -uint32_t CMidiPlayer::getTCpaused(){return tcpaused;} -void CMidiPlayer::setTCpaused(uint32_t ps){tcpaused=ps;} -uint32_t CMidiPlayer::isFinished(){return finished;} -bool CMidiPlayer::stopFlag(){return tcstop;} -void CMidiPlayer::setResumed(){resumed=true;} +void CMidiPlayer::sendSysX(bool send) +{ + sendSysEx = send; +} +uint32_t CMidiPlayer::getStamp(int id) +{ + return stamps[id]; +} +uint32_t CMidiPlayer::getTCeptr() +{ + return tceptr; +} +void CMidiPlayer::setTCeptr(uint32_t ep, uint32_t st) +{ + resumed = true; + if (ep == ecnt) + tcstop = true; + else tceptr = ep; + for (int i = 0; i < 16; ++i) + { + qmpMidiOutDevice *dest = mididev[mappedoutput[i]].dev; + for (int j = 0; j < 120; ++j) + { + if (~ccstamps[st][i][j]) + { + dest->basicMessage(0xB0 | i, j, ccstamps[st][i][j]); + chstatus[i][j] = ccstamps[st][i][j]; + } + } + dest->basicMessage(0xC0 | i, ccstamps[st][i][128], 0); + chstatus[i][128] = ccstamps[st][i][128]; + dest->rpnMessage(i, 0, ccstamps[st][i][134] << 7); + pbr[i] = ccstamps[st][i][134]; + ctempo = ccstamps[st][0][131]; + dpt = ctempo * 1000. / divs; + ctsn = ccstamps[st][0][132] >> 24; + ctsd = 1 << ((ccstamps[st][0][132] >> 16) & 0xFF); + cks = ccstamps[st][0][133]; + } +} +double CMidiPlayer::getFtime() +{ + return ftime; +} +void CMidiPlayer::getCurrentTimeSignature(int *n, int *d) +{ + *n = ctsn; + *d = ctsd; +} +int CMidiPlayer::getCurrentKeySignature() +{ + return cks; +} +uint32_t CMidiPlayer::getFileNoteCount() +{ + return notes; +} +uint32_t CMidiPlayer::getFileStandard() +{ + return midiFile ? midiFile->std : 0; +} +const char *CMidiPlayer::getTitle() +{ + return midiFile ? midiFile->title : ""; +} +const char *CMidiPlayer::getCopyright() +{ + return midiFile ? midiFile->copyright : ""; +} +double CMidiPlayer::getTempo() +{ + return 60. / (ctempo / 1e6); +} +uint32_t CMidiPlayer::getTick() +{ + return ct; +} +uint32_t CMidiPlayer::getRawTempo() +{ + return ctempo; +} +uint32_t CMidiPlayer::getDivision() +{ + return divs; +} +uint32_t CMidiPlayer::getMaxTick() +{ + return maxtk; +} +double CMidiPlayer::getPitchBend(int ch) +{ + return ((int)pbv[ch] - 8192) / 8192.*pbr[ch]; +} +double CMidiPlayer::getPitchBendRaw(int ch, uint32_t *pb, uint32_t *pbr) +{ + if (pb) + *pb = this->pbv[ch]; + if (pbr) + *pbr = this->pbr[ch]; +} +uint32_t CMidiPlayer::getTCpaused() +{ + return tcpaused; +} +void CMidiPlayer::setTCpaused(uint32_t ps) +{ + tcpaused = ps; +} +uint32_t CMidiPlayer::isFinished() +{ + return finished; +} +bool CMidiPlayer::stopFlag() +{ + return tcstop; +} +void CMidiPlayer::setResumed() +{ + resumed = true; +} -void CMidiPlayer::setChannelPreset(int ch,int b,int p) +void CMidiPlayer::setChannelPreset(int ch, int b, int p) { - chstatus[ch][128]=p; - chstatus[ch][0]=b>>7;chstatus[ch][32]=b&0x7F; - qmpMidiOutDevice* d=mididev[mappedoutput[ch]].dev; - d->basicMessage(0xB0|ch,0x00,b>>7); - d->basicMessage(0xB0|ch,0x20,b&0x7F); - d->basicMessage(0xC0|ch,p,0); + chstatus[ch][128] = p; + chstatus[ch][0] = b >> 7; + chstatus[ch][32] = b & 0x7F; + qmpMidiOutDevice *d = mididev[mappedoutput[ch]].dev; + d->basicMessage(0xB0 | ch, 0x00, b >> 7); + d->basicMessage(0xB0 | ch, 0x20, b & 0x7F); + d->basicMessage(0xC0 | ch, p, 0); } void CMidiPlayer::dumpFile() { - if(!midiFile)return; - for(CMidiTrack &i:midiFile->tracks) - for(SEvent &j:i.eventList) - if(j.str.length()) - printf("type %x #%d @%d p1 %d p2 %d str %s\n",j.type, - j.iid,j.time,j.p1,j.p2,j.str.c_str()); - else - printf("type %x #%d @%d p1 %d p2 %d\n",j.type,j.iid, - j.time,j.p1,j.p2); + if (!midiFile) + return; + for (CMidiTrack &i : midiFile->tracks) + for (SEvent &j : i.eventList) + if (j.str.length()) + printf("type %x #%d @%d p1 %d p2 %d str %s\n", j.type, + j.iid, j.time, j.p1, j.p2, j.str.c_str()); + else + printf("type %x #%d @%d p1 %d p2 %d\n", j.type, j.iid, + j.time, j.p1, j.p2); } //16MSB..LSB1 void CMidiPlayer::setBit(uint16_t &n, uint16_t bn, uint16_t b) -{n^=(((~b)+1)^n)&(1<>ch)&1)||(solo&&!((solo>>ch)&1));} -uint16_t CMidiPlayer::getCC(int ch,int id) { - if(chstatus[ch][id]==0xff) - return getChannelOutputDevice(ch)->getInitialCCValue(uint8_t(id),uint8_t(ch)); - return chstatus[ch][id]; + return ((mute >> ch) & 1) || (solo && !((solo >> ch) & 1)); +} +uint16_t CMidiPlayer::getCC(int ch, int id) +{ + if (chstatus[ch][id] == 0xff) + return getChannelOutputDevice(ch)->getInitialCCValue(uint8_t(id), uint8_t(ch)); + return chstatus[ch][id]; } -void CMidiPlayer::setCC(int ch,int id,int val) +void CMidiPlayer::setCC(int ch, int id, int val) { - chstatus[ch][id]=val; - mididev[mappedoutput[ch]].dev->basicMessage(0xB0|ch,id,val); + chstatus[ch][id] = val; + mididev[mappedoutput[ch]].dev->basicMessage(0xB0 | ch, id, val); } -void CMidiPlayer::registerMidiOutDevice(qmpMidiOutDevice* dev,std::string name) +void CMidiPlayer::registerMidiOutDevice(qmpMidiOutDevice *dev, std::string name) { - SMidiDev d; - d.dev=dev;d.name=name; - d.refcnt=0; - mididev.push_back(d); + SMidiDev d; + d.dev = dev; + d.name = name; + d.refcnt = 0; + mididev.push_back(d); } void CMidiPlayer::unregisterMidiOutDevice(std::string name) { - for(auto i=mididev.begin();i!=mididev.end();++i) - if(i->name==name) - { - i->dev->deviceDeinit(); - mididev.erase(i); - break; - } + for (auto i = mididev.begin(); i != mididev.end(); ++i) + if (i->name == name) + { + i->dev->deviceDeinit(); + mididev.erase(i); + break; + } } std::vector CMidiPlayer::getMidiOutDevices() { - std::vector ret; - for(auto &i:mididev) - ret.push_back(i.name); - return ret; + std::vector ret; + for (auto &i : mididev) + ret.push_back(i.name); + return ret; } int CMidiPlayer::getChannelOutput(int ch) { - return mappedoutput[ch]; -} -qmpMidiOutDevice* CMidiPlayer::getChannelOutputDevice(int ch) -{ - return mididev[mappedoutput[ch]].dev; -} -void CMidiPlayer::setChannelOutput(int ch,int outid) -{ - int origoutput=mappedoutput[ch]; - if(origoutput==outid) - return; - SMidiDev& dnew=mididev[outid]; - dnew.dev->onMapped(ch,++dnew.refcnt); - for(int i=0;i<124;++i) - { - if(i!=6&&i!=38&&i!=100&&i!=101)//avoid sending RPN/NRPN - { - unsigned st=chstatus[ch][i]; - if(!~st) - st=dnew.dev->getInitialCCValue(i,ch); - dnew.dev->basicMessage(0xB0|ch,i,chstatus[ch][i]); - } - } - dnew.dev->basicMessage(0xC0|ch,~chstatus[ch][128]?chstatus[ch][128]:dnew.dev->getInitialCCValue(128,ch),0); - mappedoutput[ch]=outid; - if(~origoutput) - { - SMidiDev& dold=mididev[origoutput]; - dold.dev->onUnmapped(ch,--dold.refcnt); - } -} -const std::chrono::system_clock::time_point* CMidiPlayer::getLastEventTS() -{return levtt;} -int CMidiPlayer::setEventHandlerCB(ICallBack *cb,void *userdata) -{ - for(int i=0;i<16;++i) - { - if(eventHandlerCB[i]==cb)return i; - if(eventHandlerCB[i]==nullptr) - { - eventHandlerCB[i]=cb;eventHandlerCBuserdata[i]=userdata; - return i; - } - } - return -1; + return mappedoutput[ch]; +} +qmpMidiOutDevice *CMidiPlayer::getChannelOutputDevice(int ch) +{ + return mididev[mappedoutput[ch]].dev; +} +void CMidiPlayer::setChannelOutput(int ch, int outid) +{ + int origoutput = mappedoutput[ch]; + if (origoutput == outid) + return; + SMidiDev &dnew = mididev[outid]; + dnew.dev->onMapped(ch, ++dnew.refcnt); + for (int i = 0; i < 124; ++i) + { + if (i != 6 && i != 38 && i != 100 && i != 101) //avoid sending RPN/NRPN + { + unsigned st = chstatus[ch][i]; + if (!~st) + st = dnew.dev->getInitialCCValue(i, ch); + dnew.dev->basicMessage(0xB0 | ch, i, chstatus[ch][i]); + } + } + dnew.dev->basicMessage(0xC0 | ch, ~chstatus[ch][128] ? chstatus[ch][128] : dnew.dev->getInitialCCValue(128, ch), 0); + mappedoutput[ch] = outid; + if (~origoutput) + { + SMidiDev &dold = mididev[origoutput]; + dold.dev->onUnmapped(ch, --dold.refcnt); + } +} +const std::chrono::system_clock::time_point *CMidiPlayer::getLastEventTS() +{ + return levtt; +} +int CMidiPlayer::setEventHandlerCB(ICallBack *cb, void *userdata) +{ + for (int i = 0; i < 16; ++i) + { + if (eventHandlerCB[i] == cb) + return i; + if (eventHandlerCB[i] == nullptr) + { + eventHandlerCB[i] = cb; + eventHandlerCBuserdata[i] = userdata; + return i; + } + } + return -1; } void CMidiPlayer::unsetEventHandlerCB(int id) -{eventHandlerCB[id]=nullptr;eventHandlerCBuserdata[id]=nullptr;} -int CMidiPlayer::setEventReaderCB(ICallBack *cb,void *userdata) -{ - for(int i=0;i<16;++i) - { - if(eventReaderCB[i]==cb)return i; - if(eventReaderCB[i]==nullptr) - { - eventReaderCB[i]=cb;eventReaderCBuserdata[i]=userdata; - return i; - } - } - return -1; +{ + eventHandlerCB[id] = nullptr; + eventHandlerCBuserdata[id] = nullptr; +} +int CMidiPlayer::setEventReaderCB(ICallBack *cb, void *userdata) +{ + for (int i = 0; i < 16; ++i) + { + if (eventReaderCB[i] == cb) + return i; + if (eventReaderCB[i] == nullptr) + { + eventReaderCB[i] = cb; + eventReaderCBuserdata[i] = userdata; + return i; + } + } + return -1; } void CMidiPlayer::unsetEventReaderCB(int id) -{eventReaderCB[id]=nullptr;eventReaderCBuserdata[id]=nullptr;} -int CMidiPlayer::setFileReadFinishedCB(ICallBack *cb,void *userdata) -{ - for(int i=0;i<16;++i) - { - if(fileReadFinishCB[i]==cb)return i; - if(fileReadFinishCB[i]==nullptr) - { - fileReadFinishCB[i]=cb;fileReadFinishCBuserdata[i]=userdata; - return i; - } - } - return -1; +{ + eventReaderCB[id] = nullptr; + eventReaderCBuserdata[id] = nullptr; +} +int CMidiPlayer::setFileReadFinishedCB(ICallBack *cb, void *userdata) +{ + for (int i = 0; i < 16; ++i) + { + if (fileReadFinishCB[i] == cb) + return i; + if (fileReadFinishCB[i] == nullptr) + { + fileReadFinishCB[i] = cb; + fileReadFinishCBuserdata[i] = userdata; + return i; + } + } + return -1; } void CMidiPlayer::unsetFileReadFinishedCB(int id) -{fileReadFinishCB[id]=nullptr;fileReadFinishCBuserdata[id]=nullptr;} -int CMidiPlayer::registerEventHandler(callback_t cb,void *userdata,bool post) { - int ret; - event_handlers[ret=event_handlers_id++]=std::make_tuple(cb,userdata,post); - return ret; + fileReadFinishCB[id] = nullptr; + fileReadFinishCBuserdata[id] = nullptr; +} +int CMidiPlayer::registerEventHandler(callback_t cb, void *userdata, bool post) +{ + int ret; + event_handlers[ret = event_handlers_id++] = std::make_tuple(cb, userdata, post); + return ret; } void CMidiPlayer::unregisterEventHandler(int id) { - event_handlers.find(id)!=event_handlers.end()&&event_handlers.erase(id); + event_handlers.find(id) != event_handlers.end() &&event_handlers.erase(id); } -int CMidiPlayer::registerEventReadHandler(callback_t cb,void *userdata) +int CMidiPlayer::registerEventReadHandler(callback_t cb, void *userdata) { - int ret; - event_read_handlers[ret=event_read_handlers_id++]=std::make_pair(cb,userdata); - return ret; + int ret; + event_read_handlers[ret = event_read_handlers_id++] = std::make_pair(cb, userdata); + return ret; } void CMidiPlayer::unregisterEventReadHandler(int id) { - event_read_handlers.find(id)!=event_read_handlers.end()&&event_read_handlers.erase(id); + event_read_handlers.find(id) != event_read_handlers.end() &&event_read_handlers.erase(id); } -int CMidiPlayer::registerFileReadFinishHook(callback_t cb,void *userdata) +int CMidiPlayer::registerFileReadFinishHook(callback_t cb, void *userdata) { - int ret; - file_read_finish_hooks[ret=file_read_finish_hooks_id++]=std::make_pair(cb,userdata); - return ret; + int ret; + file_read_finish_hooks[ret = file_read_finish_hooks_id++] = std::make_pair(cb, userdata); + return ret; } void CMidiPlayer::unregisterFileReadFinishHook(int id) { - file_read_finish_hooks.find(id)!=file_read_finish_hooks.end()&&file_read_finish_hooks.erase(id); + file_read_finish_hooks.find(id) != file_read_finish_hooks.end() &&file_read_finish_hooks.erase(id); +} +void CMidiPlayer::registerReader(qmpFileReader *reader, std::string name) +{ + midiReaders->registerReader(reader, name); } -void CMidiPlayer::registerReader(qmpFileReader *reader,std::string name) -{midiReaders->registerReader(reader,name);} void CMidiPlayer::unregisterReader(std::string name) -{midiReaders->unregisterReader(name);} +{ + midiReaders->unregisterReader(name); +} void CMidiPlayer::callEventReaderCB(SEvent d) { - if((d.type&0xF0)==0x90)++notes; - for(int i=0;i<16;++i)if(eventReaderCB[i]) - eventReaderCB[i]->callBack(&d,eventReaderCBuserdata[i]); - for(auto i=event_read_handlers.begin();i!=event_read_handlers.end();++i) - i->second.first(&d,i->second.second); + if ((d.type & 0xF0) == 0x90) + ++notes; + for (int i = 0; i < 16; ++i) + if (eventReaderCB[i]) + eventReaderCB[i]->callBack(&d, eventReaderCBuserdata[i]); + for (auto i = event_read_handlers.begin(); i != event_read_handlers.end(); ++i) + i->second.first(&d, i->second.second); } void CMidiPlayer::discardCurrentEvent() { - if(midiReaders->getCurrentReader()) - midiReaders->getCurrentReader()->discardCurrentEvent(); + if (midiReaders->getCurrentReader()) + midiReaders->getCurrentReader()->discardCurrentEvent(); } void CMidiPlayer::commitEventChange(SEvent d) { - if(midiReaders->getCurrentReader()) - midiReaders->getCurrentReader()->commitEventChange(d); + if (midiReaders->getCurrentReader()) + midiReaders->getCurrentReader()->commitEventChange(d); } -CMidiPlayer* CMidiPlayer::getInstance(){return ref;} +CMidiPlayer *CMidiPlayer::getInstance() +{ + return ref; +} diff --git a/core/qmpmidiplay.hpp b/core/qmpmidiplay.hpp index 471c1db..b6a40d9 100644 --- a/core/qmpmidiplay.hpp +++ b/core/qmpmidiplay.hpp @@ -11,169 +11,170 @@ #define QMP_MAIN #include "qmpcorepublic.hpp" class CMidiPlayer; -class CSMFReader:public qmpFileReader +class CSMFReader : public qmpFileReader { - private: - CMidiFile* ret; - CMidiTrack* curTrack; - uint32_t fmt,trk; - FILE *f; - bool eventdiscarded; - uint32_t byteread,curt,curid; +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); + 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 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,waitvoice; - 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; - 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; + 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, waitvoice; + 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; + 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); + 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); - uint32_t isFinished(); - bool stopFlag(); - void setResumed(); + //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); + 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); - double getPitchBendRaw(int ch,uint32_t *pb,uint32_t *pbr); - const char* getTitle(); - const char* getCopyright(); + 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); + double getPitchBendRaw(int ch, uint32_t *pb, uint32_t *pbr); + const char *getTitle(); + const char *getCopyright(); - void sendSysX(bool send); + 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 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 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); + void discardCurrentEvent(); + void commitEventChange(SEvent d); - static CMidiPlayer* getInstance(); + static CMidiPlayer *getInstance(); }; #endif diff --git a/core/qmpmidiread.cpp b/core/qmpmidiread.cpp index c7d11f2..b3d4efe 100644 --- a/core/qmpmidiread.cpp +++ b/core/qmpmidiread.cpp @@ -7,248 +7,315 @@ #include #include #include +#include #include "qmpmidiplay.hpp" -static const char* GM1SysX="\xF0\x7E\x7F\x09\x01\xF7"; -static const char* GM2SysX="\xF0\x7E\x7F\x09\x03\xF7"; -static const char* GSSysEx="\xF0\x41\x10\x42\x12\x40\x00\x7F\x00\x41\xF7"; -static const char* XGSysEx="\xF0\x43\x10\x4C\x00\x00\x7E\x00\xF7"; +static const char *GM1SysX = "\xF0\x7E\x7F\x09\x01\xF7"; +static const char *GM2SysX = "\xF0\x7E\x7F\x09\x03\xF7"; +static const char *GSSysEx = "\xF0\x41\x10\x42\x12\x40\x00\x7F\x00\x41\xF7"; +static const char *XGSysEx = "\xF0\x43\x10\x4C\x00\x00\x7E\x00\xF7"; #define assert(x) if(!(x))this->error(false,"assertion failure @ qmpmidiread.cpp:%d",__LINE__) -void CSMFReader::error(int fatal,const char* format,...) +void CSMFReader::error(int fatal, const char *format, ...) { - va_list ap;char buf[1024],bufr[1024]; - va_start(ap,format);vsnprintf(buf,1024,format,ap);va_end(ap); - snprintf(bufr,1024,"%s at %#lx",buf,ftell(f)); - if(fatal)throw std::runtime_error(bufr); - else fprintf(stderr,"CSMFReader W: %s.\n",bufr); + va_list ap; + char buf[1024], bufr[1024]; + va_start(ap, format); + vsnprintf(buf, 1024, format, ap); + va_end(ap); + snprintf(bufr, 1024, "%s at %#lx", buf, ftell(f)); + if (fatal) + throw std::runtime_error(bufr); + else fprintf(stderr, "CSMFReader W: %s.\n", bufr); } uint8_t CSMFReader::read_u8() { - uint8_t ret=0; - int t=fgetc(f); - if(!~t)error(1,"Unexpected EOF"); - ret=(uint8_t)t; - return ret; + uint8_t ret = 0; + int t = fgetc(f); + if (!~t) + error(1, "Unexpected EOF"); + ret = (uint8_t)t; + return ret; } uint16_t CSMFReader::read_u16() { - uint16_t ret=0; - size_t sz=fread(&ret,2,1,f); - if(sz<1)error(1,"Unexpected EOF"); + uint16_t ret = 0; + size_t sz = fread(&ret, 2, 1, f); + if (sz < 1) + error(1, "Unexpected EOF"); #if defined(_MSC_VER)&&defined(_WIN32) - ret=_byteswap_ushort(ret); + ret = _byteswap_ushort(ret); #elif __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__ - ret=__builtin_bswap16(ret); + ret = __builtin_bswap16(ret); #endif - return ret; + return ret; } uint32_t CSMFReader::read_u32() { - uint32_t ret=0; - size_t sz=fread(&ret,4,1,f); - if(sz<1)error(1,"Unexpected EOF"); + uint32_t ret = 0; + size_t sz = fread(&ret, 4, 1, f); + if (sz < 1) + error(1, "Unexpected EOF"); #if defined(_MSC_VER)&&defined(_WIN32) - ret=_byteswap_ulong(ret); + ret = _byteswap_ulong(ret); #elif __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__ - ret=__builtin_bswap32(ret); + ret = __builtin_bswap32(ret); #endif - return ret; + return ret; } uint32_t CSMFReader::read_varlen() { - uint32_t ret=0,c=0; - int t; - do - { - t=fgetc(f); - if(!~t)error(1,"Unexpected EOF"); - if(++c>4)error(1,"Variable length type overflow"); - ret<<=7;ret|=(t&0x7F); - }while(t&0x80); - return ret; + uint32_t ret = 0, c = 0; + int t; + do + { + t = fgetc(f); + if (!~t) + error(1, "Unexpected EOF"); + if (++c > 4) + error(1, "Variable length type overflow"); + ret <<= 7; + ret |= (t & 0x7F); + } while (t & 0x80); + return ret; } int CSMFReader::read_event()//returns 0 if End of Track encountered { - uint32_t delta=read_varlen();curt+=delta; - uint8_t type=read_u8();uint32_t p1,p2; - static uint8_t lasttype;eventdiscarded=false; - if(!(type&0x80)){fseek(f,-1,SEEK_CUR);type=lasttype;} - switch(type&0xF0) - { - case 0x80://Note Off - case 0x90://Note On - case 0xA0://Note Aftertouch - case 0xB0://Controller Change - case 0xE0://Pitch wheel - p1=read_u8();p2=read_u8(); - curTrack->appendEvent(SEvent(curid,curt,type,p1,p2)); - break; - case 0xC0://Patch Change - case 0xD0://Channel Aftertouch - p1=read_u8(); - curTrack->appendEvent(SEvent(curid,curt,type,p1,0)); - break; - case 0xF0: - if((type&0x0F)==0x0F)//Meta Event - { - uint8_t metatype=read_u8(); - uint32_t len=read_varlen();char* str=nullptr; - if(len<=1024&&len>0)str=new char[len+8]; - if(str)fread(str,1,len,f);else fseek(f,len,SEEK_CUR); - std::string sstr; - if(str){str[len]='\0';sstr=std::string(str,len);} - switch(metatype) - { - case 0x00://Sequence Number - assert(len==2||len==0); - break; - case 0x20://Channel Prefix - assert(len==1); - break; - case 0x2F://End of Track - assert(len==0); - return 0; - case 0x51://Set Tempo - assert(len==3); - curTrack->appendEvent(SEvent(curid,curt,type,metatype,0,sstr)); - break; - case 0x54://SMTPE offset, not handled. - assert(len==5); - break; - case 0x58://Time signature - assert(len==4); - curTrack->appendEvent(SEvent(curid,curt,type,metatype,0,sstr)); - break; - case 0x59://Key signature - assert(len==2); - curTrack->appendEvent(SEvent(curid,curt,type,metatype,0,sstr)); - break; - case 0x01:case 0x02:case 0x03: - case 0x04:case 0x05:case 0x06: - case 0x07:case 0x7F:default://text-like meta - { - curTrack->appendEvent(SEvent(curid,curt,type,metatype,0,sstr)); - if(str&&metatype==0x03&&!ret->title) - { - ret->title=new char[len+8]; - strcpy(ret->title,str); - } - if(str&&metatype==0x02&&!ret->copyright) - { - ret->copyright=new char[len+8]; - strcpy(ret->copyright,str); - } - } - } - if(str)delete[] str; - } - else if((type&0x0F)==0x00||(type&0x0F)==0x07)//SysEx - { - uint32_t len=read_varlen();char* str=nullptr; - str=new char[len+8]; - if((type&0x0F)==0x00) - { - str[0]=char(0xF0);++len; - size_t sz=fread(str+1,1,len-1,f); - if(szappendEvent(SEvent(curid,curt,type,0,0,std::string(str,len))); - if(!strcmp(str,GM1SysX))ret->std=1; - if(!strcmp(str,GM2SysX))ret->std=2; - if(!strcmp(str,GSSysEx))ret->std=3; - if(!strcmp(str,XGSysEx))ret->std=4; - delete[] str; - } - else error(0,"Unknown event type %#x",type); - break; - default: - error(0,"Unknown event type %#x",type); - } - lasttype=type;++curid; - if(curTrack->eventList.size()) - { - SEvent& le=curTrack->eventList.back(); - CMidiPlayer::getInstance()->callEventReaderCB(le); - } - return 1; + uint32_t delta = read_varlen(); + curt += delta; + uint8_t type = read_u8(); + uint32_t p1, p2; + static uint8_t lasttype; + eventdiscarded = false; + if (!(type & 0x80)) + { + fseek(f, -1, SEEK_CUR); + type = lasttype; + } + switch (type & 0xF0) + { + case 0x80://Note Off + case 0x90://Note On + case 0xA0://Note Aftertouch + case 0xB0://Controller Change + case 0xE0://Pitch wheel + p1 = read_u8(); + p2 = read_u8(); + curTrack->appendEvent(SEvent(curid, curt, type, p1, p2)); + break; + case 0xC0://Patch Change + case 0xD0://Channel Aftertouch + p1 = read_u8(); + curTrack->appendEvent(SEvent(curid, curt, type, p1, 0)); + break; + case 0xF0: + if ((type & 0x0F) == 0x0F) //Meta Event + { + uint8_t metatype = read_u8(); + uint32_t len = read_varlen(); + char *str = nullptr; + if (len <= 1024 && len > 0) + str = new char[len + 8]; + if (str) + fread(str, 1, len, f); + else + fseek(f, len, SEEK_CUR); + std::string sstr; + if (str) + { + str[len] = '\0'; + sstr = std::string(str, len); + } + switch (metatype) + { + case 0x00://Sequence Number + assert(len == 2 || len == 0); + break; + case 0x20://Channel Prefix + assert(len == 1); + break; + case 0x2F://End of Track + assert(len == 0); + return 0; + case 0x51://Set Tempo + assert(len == 3); + curTrack->appendEvent(SEvent(curid, curt, type, metatype, 0, sstr)); + break; + case 0x54://SMTPE offset, not handled. + assert(len == 5); + break; + case 0x58://Time signature + assert(len == 4); + curTrack->appendEvent(SEvent(curid, curt, type, metatype, 0, sstr)); + break; + case 0x59://Key signature + assert(len == 2); + curTrack->appendEvent(SEvent(curid, curt, type, metatype, 0, sstr)); + break; + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x7F: + default://text-like meta + { + curTrack->appendEvent(SEvent(curid, curt, type, metatype, 0, sstr)); + if (str && metatype == 0x03 && !ret->title) + { + ret->title = new char[len + 8]; + strcpy(ret->title, str); + } + if (str && metatype == 0x02 && !ret->copyright) + { + ret->copyright = new char[len + 8]; + strcpy(ret->copyright, str); + } + } + } + if (str) + delete[] str; + } + else if ((type & 0x0F) == 0x00 || (type & 0x0F) == 0x07) //SysEx + { + uint32_t len = read_varlen(); + char *str = nullptr; + str = new char[len + 8]; + if ((type & 0x0F) == 0x00) + { + str[0] = char(0xF0); + ++len; + size_t sz = fread(str + 1, 1, len - 1, f); + if (sz < len - 1) + error(1, "Unexpected EOF"); + } + else + { + size_t sz = fread(str, 1, len, f); + if (sz < len) + error(1, "Unexpected EOF"); + } + curTrack->appendEvent(SEvent(curid, curt, type, 0, 0, std::string(str, len))); + if (!strcmp(str, GM1SysX)) + ret->std = 1; + if (!strcmp(str, GM2SysX)) + ret->std = 2; + if (!strcmp(str, GSSysEx)) + ret->std = 3; + if (!strcmp(str, XGSysEx)) + ret->std = 4; + delete[] str; + } + else + error(0, "Unknown event type %#x", type); + break; + default: + error(0, "Unknown event type %#x", type); + } + lasttype = type; + ++curid; + if (curTrack->eventList.size()) + { + SEvent &le = curTrack->eventList.back(); + CMidiPlayer::getInstance()->callEventReaderCB(le); + } + return 1; } void CSMFReader::read_track() { - ret->tracks.push_back(CMidiTrack()); - curTrack=&ret->tracks.back(); - uint32_t chnklen=read_u32();byteread=ftell(f);curt=0;curid=0; - while(read_event()); - byteread=ftell(f)-byteread; - if(bytereadchnklen) - error(1,"Read past end of track"); + ret->tracks.push_back(CMidiTrack()); + curTrack = &ret->tracks.back(); + uint32_t chnklen = read_u32(); + byteread = ftell(f); + curt = 0; + curid = 0; + while (read_event()); + byteread = ftell(f) - byteread; + if (byteread < chnklen) + { + error(0, "Extra bytes after EOT event"); + for (; byteread < chnklen; ++byteread) + fgetc(f); + } + if (byteread > chnklen) + error(1, "Read past end of track"); } void CSMFReader::read_header() { - uint32_t chnklen=read_u32();byteread=ftell(f); - if(chnklen<6)error(1,"Header chunk too short"); - if(chnklen>6)error(0,"Header chunk length longer than expected. Ignoring extra bytes"); - fmt=read_u16();trk=read_u16();ret->divs=read_u16(); - if(ret->divs&0x8000)error(1,"SMTPE format is not supported"); - for(byteread=ftell(f)-byteread;byteread 6) + error(0, "Header chunk length longer than expected. Ignoring extra bytes"); + fmt = read_u16(); + trk = read_u16(); + ret->divs = read_u16(); + if (ret->divs & 0x8000) + error(1, "SMTPE format is not supported"); + for (byteread = ftell(f) - byteread; byteread < chnklen; ++byteread) + fgetc(f); } uint32_t CSMFReader::read_chunk(int is_header) { - char hdr[6]; - fread(hdr,1,4,f); - if(feof(f))error(1,"Unexpected EOF"); - if(is_header) - { - if(!strncmp(hdr,"RIFF",4)) - { - fseek(f,4,SEEK_CUR); - fread(hdr,1,4,f); - if(strncmp(hdr,"RMID",4)){error(1,"Wrong file type in RIFF container");} - fseek(f,8,SEEK_CUR); - fread(hdr,1,4,f); - } - if(strncmp(hdr,"MThd",4)){error(1,"Wrong MIDI header.");} - else return read_header(),0; - } - else - if(strncmp(hdr,"MTrk",4)) - { - error(0,"Wrong track chunk header. Ignoring the entire chunk."); - uint32_t chnklen=read_u32();fseek(f,chnklen,SEEK_CUR);return 0; - } - else return read_track(),1; - return 0; + char hdr[6]; + fread(hdr, 1, 4, f); + if (feof(f)) + error(1, "Unexpected EOF"); + if (is_header) + { + if (!strncmp(hdr, "RIFF", 4)) + { + fseek(f, 4, SEEK_CUR); + fread(hdr, 1, 4, f); + if (strncmp(hdr, "RMID", 4)) + error(1, "Wrong file type in RIFF container"); + fseek(f, 8, SEEK_CUR); + fread(hdr, 1, 4, f); + } + if (strncmp(hdr, "MThd", 4)) + error(1, "Wrong MIDI header."); + else return read_header(), 0; + } + else if (strncmp(hdr, "MTrk", 4)) + { + error(0, "Wrong track chunk header. Ignoring the entire chunk."); + uint32_t chnklen = read_u32(); + fseek(f, chnklen, SEEK_CUR); + return 0; + } + else + return read_track(), 1; + return 0; } CSMFReader::CSMFReader() { - f=nullptr; + f = nullptr; } -CMidiFile* CSMFReader::readFile(const char* fn) +CMidiFile *CSMFReader::readFile(const char *fn) { - ret=new CMidiFile; - ret->title=ret->copyright=nullptr;ret->std=0;ret->valid=1; - try - { - if(!(f=fopen(fn,"rb"))) - throw std::runtime_error("Can't open file"); - read_chunk(1); - for(uint32_t i=0;ivalid=0;if(f)fclose(f);f=nullptr; - } - return ret; + ret = new CMidiFile; + ret->title = ret->copyright = nullptr; + ret->std = 0; + ret->valid = 1; + try + { + if (!(f = fopen(fn, "rb"))) + throw std::runtime_error("Can't open file"); + read_chunk(1); + for (uint32_t i = 0; i < trk; i += read_chunk(0)); + fclose(f); + f = nullptr; + } + catch (std::runtime_error &e) + { + fprintf(stderr, "CSMFReader E: %s is not a supported file. Cause: %s.\n", fn, e.what()); + ret->valid = 0; + if (f) + fclose(f); + f = nullptr; + } + return ret; } CSMFReader::~CSMFReader() { @@ -256,54 +323,65 @@ CSMFReader::~CSMFReader() void CSMFReader::discardCurrentEvent() { - if(eventdiscarded)return;eventdiscarded=true; - curTrack->eventList.pop_back(); + if (eventdiscarded) + return; + eventdiscarded = true; + curTrack->eventList.pop_back(); } void CSMFReader::commitEventChange(SEvent d) { - curTrack->eventList.back().time=d.time; - curTrack->eventList.back().type=d.type; - curTrack->eventList.back().p1=d.p1; - curTrack->eventList.back().p2=d.p2; + curTrack->eventList.back().time = d.time; + curTrack->eventList.back().type = d.type; + curTrack->eventList.back().p1 = d.p1; + curTrack->eventList.back().p2 = d.p2; } CMidiFileReaderCollection::CMidiFileReaderCollection() { - readers.clear();currentReader=nullptr; - registerReader(new CSMFReader(),"Default SMF Reader"); + readers.clear(); + currentReader = nullptr; + registerReader(new CSMFReader(), "Default SMF Reader"); } CMidiFileReaderCollection::~CMidiFileReaderCollection() { - delete readers[0].first; + delete readers[0].first; } -void CMidiFileReaderCollection::registerReader(qmpFileReader* reader,std::string name) +void CMidiFileReaderCollection::registerReader(qmpFileReader *reader, std::string name) { - for(unsigned i=0;isecond==name) - { - readers.erase(i); - return; - } + for (auto i = readers.begin(); i != readers.end(); ++i) + if (i->second == name) + { + readers.erase(i); + return; + } } -CMidiFile* CMidiFileReaderCollection::readFile(const char* fn) +CMidiFile *CMidiFileReaderCollection::readFile(const char *fn) { - CMidiFile *file=nullptr; - for(unsigned i=0;inotes=0; - CMidiFile* t=readers[i].first->readFile(fn); - if(t->valid){file=t;break;} - else delete t; - } - currentReader=nullptr; - return file; + CMidiFile *file = nullptr; + for (unsigned i = 0; i < readers.size(); ++i) + { + currentReader = readers[i].first; + CMidiPlayer::getInstance()->notes = 0; + CMidiFile *t = readers[i].first->readFile(fn); + if (t->valid) + { + file = t; + break; + } + else + delete t; + } + currentReader = nullptr; + return file; +} +qmpFileReader *CMidiFileReaderCollection::getCurrentReader() +{ + return currentReader; } -qmpFileReader* CMidiFileReaderCollection::getCurrentReader() -{return currentReader;} diff --git a/include/qmpcorepublic.hpp b/include/qmpcorepublic.hpp index c6caed5..8376af8 100644 --- a/include/qmpcorepublic.hpp +++ b/include/qmpcorepublic.hpp @@ -13,193 +13,221 @@ //MIDI Event structure struct SEvent { - uint32_t iid,time; - uint8_t type,p1,p2; - uint8_t flags; - std::string str; - SEvent(){time=iid=0;type=p1=p2=0;flags=0;str="";} - SEvent(uint32_t _iid,uint32_t _t,uint8_t _tp,uint8_t _p1,uint8_t _p2,const char* s=nullptr) - { - iid=_iid;time=_t;type=_tp; - p1=_p1;p2=_p2;flags=0; - if(s)str=std::string(s);else str=""; - } - SEvent(uint32_t _iid,uint32_t _t,uint8_t _tp,uint8_t _p1,uint8_t _p2,std::string s): - iid(_iid),time(_t),type(_tp),p1(_p1),p2(_p2),str(s){} - friend bool operator <(const SEvent& a,const SEvent& b){return a.time-b.time?a.time eventList; - void appendEvent(SEvent e){eventList.push_back(e);} - SEvent& operator[](size_t sub){return eventList[sub];} +class CMidiTrack +{ +public: + std::vector eventList; + void appendEvent(SEvent e) + { + eventList.push_back(e); + } + SEvent &operator[](size_t sub) + { + return eventList[sub]; + } }; //MIDI File class -class CMidiFile{ - public: - bool valid; - char *title,*copyright; - std::vector tracks; - uint32_t std,divs; - ~CMidiFile() - { - if(title)delete[] title; - if(copyright)delete[] copyright; - } +class CMidiFile +{ +public: + bool valid; + char *title, *copyright; + std::vector tracks; + uint32_t std, divs; + ~CMidiFile() + { + if (title)delete[] title; + if (copyright)delete[] copyright; + } }; //Generic callback function that can be used for hooking the core. //"userdata" is set when you register the callback function. //Deprecated. Removing in 0.9.x. class ICallBack { - public: - ICallBack(){} - virtual void callBack(const void* callerdata,void* userdata)=0; - virtual ~ICallBack(){} +public: + ICallBack() {} + virtual void callBack(const void *callerdata, void *userdata) = 0; + virtual ~ICallBack() {} }; //alternative callback function type -typedef std::function callback_t; +typedef std::function callback_t; //MIDI file reader interface. Use this to implement your file importer. class qmpFileReader { - public: - qmpFileReader(){} - virtual ~qmpFileReader(){} - virtual CMidiFile* readFile(const char* fn)=0; - virtual void discardCurrentEvent()=0; - virtual void commitEventChange(SEvent d)=0; +public: + qmpFileReader() {} + virtual ~qmpFileReader() {} + virtual CMidiFile *readFile(const char *fn) = 0; + virtual void discardCurrentEvent() = 0; + virtual void commitEventChange(SEvent d) = 0; }; //Functionality interface. class qmpFuncBaseIntf { - public: - qmpFuncBaseIntf(){} - virtual void show()=0; - virtual void close()=0; - virtual ~qmpFuncBaseIntf(){} +public: + qmpFuncBaseIntf() {} + virtual void show() = 0; + virtual void close() = 0; + virtual ~qmpFuncBaseIntf() {} }; //Midi mapper plugin interface. class qmpMidiOutDevice { - public: - qmpMidiOutDevice(){} - virtual void deviceInit()=0; - virtual void deviceDeinit()=0; - virtual void basicMessage(uint8_t type,uint8_t p1,uint8_t p2)=0; - virtual void extendedMessage(uint32_t length,const char* data)=0; - virtual void rpnMessage(uint8_t ch,uint16_t type,uint16_t val)=0; - virtual void nrpnMessage(uint8_t ch,uint16_t type,uint16_t val)=0; - virtual void panic(uint8_t ch)=0; - virtual void reset(uint8_t ch)=0; - virtual void onMapped(uint8_t ch,int refcnt)=0; - virtual void onUnmapped(uint8_t ch,int refcnt)=0; - virtual std::vector> getBankList()=0; - virtual std::vector> getPresets(uint16_t bank)=0; - virtual std::string getPresetName(uint16_t bank,uint8_t preset)=0; - virtual bool getChannelPreset(int ch,uint16_t *bank,uint8_t *preset,std::string &presetname)=0; - virtual uint8_t getInitialCCValue(uint8_t cc,uint8_t ch)=0; - virtual ~qmpMidiOutDevice(){} +public: + qmpMidiOutDevice() {} + virtual void deviceInit() = 0; + virtual void deviceDeinit() = 0; + virtual void basicMessage(uint8_t type, uint8_t p1, uint8_t p2) = 0; + virtual void extendedMessage(uint32_t length, const char *data) = 0; + virtual void rpnMessage(uint8_t ch, uint16_t type, uint16_t val) = 0; + virtual void nrpnMessage(uint8_t ch, uint16_t type, uint16_t val) = 0; + virtual void panic(uint8_t ch) = 0; + virtual void reset(uint8_t ch) = 0; + virtual void onMapped(uint8_t ch, int refcnt) = 0; + virtual void onUnmapped(uint8_t ch, int refcnt) = 0; + virtual std::vector> getBankList() = 0; + virtual std::vector> getPresets(uint16_t bank) = 0; + virtual std::string getPresetName(uint16_t bank, uint8_t preset) = 0; + virtual bool getChannelPreset(int ch, uint16_t *bank, uint8_t *preset, std::string &presetname) = 0; + virtual uint8_t getInitialCCValue(uint8_t cc, uint8_t ch) = 0; + virtual ~qmpMidiOutDevice() {} }; //Main plugin interface. class qmpPluginIntf { - public: - qmpPluginIntf(){} - virtual ~qmpPluginIntf(){} - virtual void init(){} - virtual void deinit(){} - virtual const char* pluginGetName(){return "";} - virtual const char* pluginGetVersion(){return "";} +public: + qmpPluginIntf() {} + virtual ~qmpPluginIntf() {} + virtual void init() {} + virtual void deinit() {} + virtual const char *pluginGetName() + { + return ""; + } + virtual const char *pluginGetVersion() + { + return ""; + } }; #ifdef QMP_MAIN -extern "C"{ +extern "C" { #endif //The API class provided by the core. Plugins use this class to interact with //the core. -class qmpPluginAPI -{ - public: - virtual ~qmpPluginAPI(){} - virtual uint32_t getDivision()=0; - virtual uint32_t getRawTempo()=0; - virtual double getRealTempo()=0; - virtual uint32_t getTimeSig()=0; - virtual int getKeySig()=0; - virtual uint32_t getNoteCount()=0; - virtual uint32_t getMaxTick()=0; - virtual uint32_t getCurrentPolyphone()=0; - virtual uint32_t getMaxPolyphone()=0; - virtual uint32_t getCurrentTimeStamp()=0; - virtual uint32_t getCurrentPlaybackPercentage()=0; - virtual int getChannelCC(int ch,int cc)=0; - virtual int getChannelPreset(int ch)=0; - virtual void playerSeek(uint32_t percentage)=0; - virtual double getPitchBend(int ch)=0; - virtual void getPitchBendRaw(int ch,uint32_t *pb,uint32_t *pbr)=0; - virtual bool getChannelMask(int ch)=0; - virtual std::string getTitle()=0; - virtual std::wstring getWTitle()=0; - virtual std::string getChannelPresetString(int ch)=0; - virtual bool isDarkTheme()=0; - virtual void* getMainWindow()=0; + class qmpPluginAPI + { + public: + virtual ~qmpPluginAPI() {} + virtual uint32_t getDivision() = 0; + virtual uint32_t getRawTempo() = 0; + virtual double getRealTempo() = 0; + virtual uint32_t getTimeSig() = 0; + virtual int getKeySig() = 0; + virtual uint32_t getNoteCount() = 0; + virtual uint32_t getMaxTick() = 0; + virtual uint32_t getCurrentPolyphone() = 0; + virtual uint32_t getMaxPolyphone() = 0; + virtual uint32_t getCurrentTimeStamp() = 0; + virtual uint32_t getCurrentPlaybackPercentage() = 0; + virtual int getChannelCC(int ch, int cc) = 0; + virtual int getChannelPreset(int ch) = 0; + virtual void playerSeek(uint32_t percentage) = 0; + virtual double getPitchBend(int ch) = 0; + virtual void getPitchBendRaw(int ch, uint32_t *pb, uint32_t *pbr) = 0; + virtual bool getChannelMask(int ch) = 0; + virtual std::string getTitle() = 0; + virtual std::wstring getWTitle() = 0; + virtual std::string getChannelPresetString(int ch) = 0; + virtual bool isDarkTheme() = 0; + virtual void *getMainWindow() = 0; - //WARNING!!: This function should be called from event reader callbacks only and - //it is somehow dangerous -- other plugins might be unaware of the removal of the - //event. The design might be modified afterward. - virtual void discardCurrentEvent()=0; - //WARNING!!: This function should be called from event reader callbacks only and - //it is somehow dangerous -- other plugins might be unaware of the event change. - //The design might be modified afterward. - virtual void commitEventChange(SEvent d)=0; - //This function should be called from a file reader when it has read a new event - virtual void callEventReaderCB(SEvent d)=0; - virtual void setFuncState(std::string name,bool state)=0; - virtual void setFuncEnabled(std::string name,bool enable)=0; + //WARNING!!: This function should be called from event reader callbacks only and + //it is somehow dangerous -- other plugins might be unaware of the removal of the + //event. The design might be modified afterward. + virtual void discardCurrentEvent() = 0; + //WARNING!!: This function should be called from event reader callbacks only and + //it is somehow dangerous -- other plugins might be unaware of the event change. + //The design might be modified afterward. + virtual void commitEventChange(SEvent d) = 0; + //This function should be called from a file reader when it has read a new event + virtual void callEventReaderCB(SEvent d) = 0; + virtual void setFuncState(std::string name, bool state) = 0; + virtual void setFuncEnabled(std::string name, bool enable) = 0; - virtual void registerFunctionality(qmpFuncBaseIntf* i,std::string name,std::string desc,const char* icon,int iconlen,bool checkable)=0; - virtual void unregisterFunctionality(std::string name)=0; - virtual int registerUIHook(std::string e,ICallBack* cb,void* userdat)=0; - virtual int registerUIHook(std::string e,callback_t cb,void* userdat)=0; - virtual void unregisterUIHook(std::string e,int hook)=0; - virtual void registerMidiOutDevice(qmpMidiOutDevice* dev,std::string name)=0; - virtual void unregisterMidiOutDevice(std::string name)=0; - virtual int registerEventReaderIntf(ICallBack* cb,void* userdata)=0; - virtual void unregisterEventReaderIntf(int intfhandle)=0; - virtual int registerEventHandlerIntf(ICallBack* cb,void* userdata)=0; - virtual void unregisterEventHandlerIntf(int intfhandle)=0; - virtual int registerFileReadFinishedHandlerIntf(ICallBack* cb,void* userdata)=0; - virtual void unregisterFileReadFinishedHandlerIntf(int intfhandle)=0; - virtual int registerEventHandler(callback_t cb,void *userdata,bool post=false)=0; - virtual void unregisterEventHandler(int id)=0; - virtual int registerEventReadHandler(callback_t cb,void *userdata)=0; - virtual void unregisterEventReadHandler(int id)=0; - virtual int registerFileReadFinishHook(callback_t cb,void *userdata)=0; - virtual void unregisterFileReadFinishHook(int id)=0; - virtual void registerFileReader(qmpFileReader* reader,std::string name)=0; - virtual void unregisterFileReader(std::string name)=0; + virtual void registerFunctionality(qmpFuncBaseIntf *i, std::string name, std::string desc, const char *icon, int iconlen, bool checkable) = 0; + virtual void unregisterFunctionality(std::string name) = 0; + virtual int registerUIHook(std::string e, ICallBack *cb, void *userdat) = 0; + virtual int registerUIHook(std::string e, callback_t cb, void *userdat) = 0; + virtual void unregisterUIHook(std::string e, int hook) = 0; + virtual void registerMidiOutDevice(qmpMidiOutDevice *dev, std::string name) = 0; + virtual void unregisterMidiOutDevice(std::string name) = 0; + virtual int registerEventReaderIntf(ICallBack *cb, void *userdata) = 0; + virtual void unregisterEventReaderIntf(int intfhandle) = 0; + virtual int registerEventHandlerIntf(ICallBack *cb, void *userdata) = 0; + virtual void unregisterEventHandlerIntf(int intfhandle) = 0; + virtual int registerFileReadFinishedHandlerIntf(ICallBack *cb, void *userdata) = 0; + virtual void unregisterFileReadFinishedHandlerIntf(int intfhandle) = 0; + virtual int registerEventHandler(callback_t cb, void *userdata, bool post = false) = 0; + virtual void unregisterEventHandler(int id) = 0; + virtual int registerEventReadHandler(callback_t cb, void *userdata) = 0; + virtual void unregisterEventReadHandler(int id) = 0; + virtual int registerFileReadFinishHook(callback_t cb, void *userdata) = 0; + virtual void unregisterFileReadFinishHook(int id) = 0; + virtual void registerFileReader(qmpFileReader *reader, std::string name) = 0; + virtual void unregisterFileReader(std::string name) = 0; - //if desc=="", the option won't be visible in the settings form. - //it will only show up in the configuration file. - virtual void registerOptionInt(std::string tab,std::string desc,std::string key,int min,int max,int defaultval)=0; - virtual int getOptionInt(std::string key)=0; - virtual void setOptionInt(std::string key,int val)=0; - virtual void registerOptionUint(std::string tab,std::string desc,std::string key,unsigned min,unsigned max,unsigned defaultval)=0; - virtual unsigned getOptionUint(std::string key)=0; - virtual void setOptionUint(std::string key,unsigned val)=0; - virtual void registerOptionBool(std::string tab,std::string desc,std::string key,bool defaultval)=0; - virtual bool getOptionBool(std::string key)=0; - virtual void setOptionBool(std::string key,bool val)=0; - virtual void registerOptionDouble(std::string tab,std::string desc,std::string key,double min,double max,double defaultval)=0; - virtual double getOptionDouble(std::string key)=0; - virtual void setOptionDouble(std::string key,double val)=0; - virtual void registerOptionString(std::string tab,std::string desc,std::string key,std::string defaultval,bool ispath=false)=0; - virtual std::string getOptionString(std::string key)=0; - virtual void setOptionString(std::string key,std::string val)=0; - virtual void registerOptionEnumInt(std::string tab,std::string desc,std::string key,std::vector options,int defaultval)=0; - virtual int getOptionEnumInt(std::string key)=0; - virtual void setOptionEnumInt(std::string key,int val)=0; -}; + //if desc=="", the option won't be visible in the settings form. + //it will only show up in the configuration file. + virtual void registerOptionInt(std::string tab, std::string desc, std::string key, int min, int max, int defaultval) = 0; + virtual int getOptionInt(std::string key) = 0; + virtual void setOptionInt(std::string key, int val) = 0; + virtual void registerOptionUint(std::string tab, std::string desc, std::string key, unsigned min, unsigned max, unsigned defaultval) = 0; + virtual unsigned getOptionUint(std::string key) = 0; + virtual void setOptionUint(std::string key, unsigned val) = 0; + virtual void registerOptionBool(std::string tab, std::string desc, std::string key, bool defaultval) = 0; + virtual bool getOptionBool(std::string key) = 0; + virtual void setOptionBool(std::string key, bool val) = 0; + virtual void registerOptionDouble(std::string tab, std::string desc, std::string key, double min, double max, double defaultval) = 0; + virtual double getOptionDouble(std::string key) = 0; + virtual void setOptionDouble(std::string key, double val) = 0; + virtual void registerOptionString(std::string tab, std::string desc, std::string key, std::string defaultval, bool ispath = false) = 0; + virtual std::string getOptionString(std::string key) = 0; + virtual void setOptionString(std::string key, std::string val) = 0; + virtual void registerOptionEnumInt(std::string tab, std::string desc, std::string key, std::vector options, int defaultval) = 0; + virtual int getOptionEnumInt(std::string key) = 0; + virtual void setOptionEnumInt(std::string key, int val) = 0; + }; #ifdef QMP_MAIN } #endif @@ -208,7 +236,7 @@ class qmpPluginAPI //as its entry point. A pointer to the core API is also passed to the plugin //through the parameter. This function should return a pointer to a class //that implementes the plugin pinterface (qmpPluginIntf). -typedef qmpPluginIntf*(*qmpPluginEntry)(qmpPluginAPI*); +typedef qmpPluginIntf *(*qmpPluginEntry)(qmpPluginAPI *); //The following symbol only presents in plugins. Its purpose is to help the core reject incompatible plugins. -typedef const char*(*qmpPluginAPIRevEntry)(); +typedef const char *(*qmpPluginAPIRevEntry)(); #endif // QMPCOREPUBLIC_HPP diff --git a/midifmt-plugin/midifmtplugin.cpp b/midifmt-plugin/midifmtplugin.cpp index 62a9af1..39d6d4f 100644 --- a/midifmt-plugin/midifmtplugin.cpp +++ b/midifmt-plugin/midifmtplugin.cpp @@ -2,115 +2,140 @@ #include #include #include "midifmtplugin.hpp" -qmpPluginAPI* qmpMidiFmtPlugin::api=nullptr; +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; + 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; + 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>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; + 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) +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; + 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; + 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; + 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; + ret = nullptr; + f = nullptr; } CMidiStreamReader::~CMidiStreamReader() { } qmpMidiFmtPlugin::qmpMidiFmtPlugin(qmpPluginAPI *_api) -{api=_api;} +{ + api = _api; +} qmpMidiFmtPlugin::~qmpMidiFmtPlugin() -{api=nullptr;} +{ + api = nullptr; +} void qmpMidiFmtPlugin::init() { - api->registerFileReader(mdsreader=new CMidiStreamReader,"MIDS reader"); + api->registerFileReader(mdsreader = new CMidiStreamReader, "MIDS reader"); } void qmpMidiFmtPlugin::deinit() { - api->unregisterFileReader("MIDS reader"); - delete mdsreader; + api->unregisterFileReader("MIDS reader"); + delete mdsreader; +} +const char *qmpMidiFmtPlugin::pluginGetName() +{ + return "QMidiPlayer extra midi formats plugin"; +} +const char *qmpMidiFmtPlugin::pluginGetVersion() +{ + return PLUGIN_VERSION; } -const char* qmpMidiFmtPlugin::pluginGetName() -{return "QMidiPlayer extra midi formats plugin";} -const char* qmpMidiFmtPlugin::pluginGetVersion() -{return PLUGIN_VERSION;} diff --git a/midifmt-plugin/midifmtplugin.hpp b/midifmt-plugin/midifmtplugin.hpp index 038a2a7..b4eeddb 100644 --- a/midifmt-plugin/midifmtplugin.hpp +++ b/midifmt-plugin/midifmtplugin.hpp @@ -4,42 +4,46 @@ #include #include "../include/qmpcorepublic.hpp" -class CMidiStreamReader:public qmpFileReader +class CMidiStreamReader: public qmpFileReader { - 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(SEvent d); +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(SEvent d); }; -class qmpMidiFmtPlugin:public qmpPluginIntf +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(); +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;} +extern "C" { + EXPORTSYM qmpPluginIntf *qmpPluginGetInterface(qmpPluginAPI *api) + { + return new qmpMidiFmtPlugin(api); + } + EXPORTSYM const char *qmpPluginGetAPIRev() + { + return QMP_PLUGIN_API_REV; + } } #endif // MIDIFMTPLUGIN_HPP diff --git a/qmidiplayer-desktop/main.cpp b/qmidiplayer-desktop/main.cpp index 6bf21c0..c9408b9 100644 --- a/qmidiplayer-desktop/main.cpp +++ b/qmidiplayer-desktop/main.cpp @@ -26,56 +26,57 @@ #include #endif -int main(int argc,char **argv) +int main(int argc, char **argv) { #ifdef _WIN32 - if(!LoadLibraryA("libbacktrace.dll")) - fputs("Failed to load backtrace library. Stack trace will not be printed if unhandled exception occurs.\n",stderr); + if (!LoadLibraryA("libbacktrace.dll")) + fputs("Failed to load backtrace library. Stack trace will not be printed if unhandled exception occurs.\n", stderr); #endif - QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); - QCoreApplication::setApplicationName("qmidiplayer"); - QCoreApplication::setApplicationVersion(APP_VERSION); - if(!qgetenv("QT_SCALE_FACTOR").length()&&!qgetenv("QT_SCREEN_SCALE_FACTORS").length()) - QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); - qSetMessagePattern("%{time} @ %{file} : %{line}, in %{function} : %{message}"); - QApplication a(argc,argv); + QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); + QCoreApplication::setApplicationName("qmidiplayer"); + QCoreApplication::setApplicationVersion(APP_VERSION); + if (!qgetenv("QT_SCALE_FACTOR").length() && !qgetenv("QT_SCREEN_SCALE_FACTORS").length()) + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + qSetMessagePattern("%{time} @ %{file} : %{line}, in %{function} : %{message}"); + QApplication a(argc, argv); - QTranslator qtTranslator; - qtTranslator.load("qt_"+QLocale::system().name(), - QLibraryInfo::location(QLibraryInfo::TranslationsPath)); - a.installTranslator(&qtTranslator); - QTranslator qmpTranslator; + QTranslator qtTranslator; + qtTranslator.load("qt_" + QLocale::system().name(), + QLibraryInfo::location(QLibraryInfo::TranslationsPath)); + a.installTranslator(&qtTranslator); + QTranslator qmpTranslator; #ifndef NON_PORTABLE - qmpTranslator.load("qmp_"+QLocale::system().name(), - QCoreApplication::applicationDirPath()+"/translations/"); + qmpTranslator.load("qmp_" + QLocale::system().name(), + QCoreApplication::applicationDirPath() + "/translations/"); #else #define strify(s) #s - qmpTranslator.load("qmp_"+QLocale::system().name(), - QString(strify(INSTALL_PREFIX))+"/share/qmidiplayer/translations"); + qmpTranslator.load("qmp_" + QLocale::system().name(), + QString(strify(INSTALL_PREFIX)) + "/share/qmidiplayer/translations"); #undef strify #endif - a.installTranslator(&qmpTranslator); + a.installTranslator(&qmpTranslator); - QCommandLineParser clp; - clp.setApplicationDescription(QCoreApplication::translate("main","A cross-platform MIDI player.")); - clp.addHelpOption(); - clp.addVersionOption(); - clp.addPositionalArgument("file",QCoreApplication::translate("main","midi files to play (optional)."),"[files...]"); - clp.addOption(QCommandLineOption("plugin",QCoreApplication::translate("main","Load a plugin from ."),"plugin library")); - clp.addOption(QCommandLineOption({"l","load-all-files"},QCoreApplication::translate("main","Load all files from the same folder."))); + QCommandLineParser clp; + clp.setApplicationDescription(QCoreApplication::translate("main", "A cross-platform MIDI player.")); + clp.addHelpOption(); + clp.addVersionOption(); + clp.addPositionalArgument("file", QCoreApplication::translate("main", "midi files to play (optional)."), "[files...]"); + clp.addOption(QCommandLineOption("plugin", QCoreApplication::translate("main", "Load a plugin from ."), "plugin library")); + clp.addOption(QCommandLineOption({"l", "load-all-files"}, QCoreApplication::translate("main", "Load all files from the same folder."))); #ifdef _WIN32 - clp.addOption(QCommandLineOption("keep-console",QCoreApplication::translate("main","Keep console window open."))); + clp.addOption(QCommandLineOption("keep-console", QCoreApplication::translate("main", "Keep console window open."))); #endif - clp.process(a); + clp.process(a); #ifdef _WIN32 - if(!clp.isSet("keep-console")) - FreeConsole(); + if (!clp.isSet("keep-console")) + FreeConsole(); #endif - qmpMainWindow w(&clp); - if(w.parseArgs()==1)return 0; - w.init(); + qmpMainWindow w(&clp); + if (w.parseArgs() == 1) + return 0; + w.init(); - return a.exec(); + return a.exec(); } diff --git a/qmidiplayer-desktop/qdialskulpturestyle.cpp b/qmidiplayer-desktop/qdialskulpturestyle.cpp index 7650edb..29c8f79 100644 --- a/qmidiplayer-desktop/qdialskulpturestyle.cpp +++ b/qmidiplayer-desktop/qdialskulpturestyle.cpp @@ -36,35 +36,40 @@ static const bool UsePixmapCache = true; static void -paintIndicatorCached(QPainter *painter, const QStyleOption *option, std::function paintFunc, bool useCache, const QString &pixmapName) +paintIndicatorCached(QPainter *painter, const QStyleOption *option, std::function paintFunc, bool useCache, const QString &pixmapName) { - QRect rect = option->rect; - QPixmap internalPixmapCache; - QImage imageCache; - QPainter *p = painter; - int txType = painter->deviceTransform().type() | painter->worldTransform().type(); - bool doPixmapCache = useCache && (!option->rect.isEmpty()) - && ((txType <= QTransform::TxTranslate) || (painter->deviceTransform().type() == QTransform::TxScale)); - if (doPixmapCache && QPixmapCache::find(pixmapName, &internalPixmapCache)) { - painter->drawPixmap(option->rect.topLeft(), internalPixmapCache); - } else { - if (doPixmapCache) { - rect.setRect(0, 0, option->rect.width(), option->rect.height()); - qreal pixelRatio=painter->device()->devicePixelRatioF(); - imageCache = QImage(option->rect.size() * pixelRatio, QImage::Format_ARGB32_Premultiplied); - imageCache.setDevicePixelRatio(pixelRatio); - imageCache.fill(0); - p = new QPainter(&imageCache); - } - paintFunc(p,option); - if (doPixmapCache) { - p->end(); - delete p; - internalPixmapCache = QPixmap::fromImage(imageCache); - painter->drawPixmap(option->rect.topLeft(), internalPixmapCache); - QPixmapCache::insert(pixmapName, internalPixmapCache); - } - } + QRect rect = option->rect; + QPixmap internalPixmapCache; + QImage imageCache; + QPainter *p = painter; + int txType = painter->deviceTransform().type() | painter->worldTransform().type(); + bool doPixmapCache = useCache && (!option->rect.isEmpty()) + && ((txType <= QTransform::TxTranslate) || (painter->deviceTransform().type() == QTransform::TxScale)); + if (doPixmapCache && QPixmapCache::find(pixmapName, &internalPixmapCache)) + { + painter->drawPixmap(option->rect.topLeft(), internalPixmapCache); + } + else + { + if (doPixmapCache) + { + rect.setRect(0, 0, option->rect.width(), option->rect.height()); + qreal pixelRatio = painter->device()->devicePixelRatioF(); + imageCache = QImage(option->rect.size() * pixelRatio, QImage::Format_ARGB32_Premultiplied); + imageCache.setDevicePixelRatio(pixelRatio); + imageCache.fill(0); + p = new QPainter(&imageCache); + } + paintFunc(p, option); + if (doPixmapCache) + { + p->end(); + delete p; + internalPixmapCache = QPixmap::fromImage(imageCache); + painter->drawPixmap(option->rect.topLeft(), internalPixmapCache); + QPixmapCache::insert(pixmapName, internalPixmapCache); + } + } } void @@ -73,120 +78,132 @@ paintDialBase(QPainter *painter, const QStyleOption *option) // painter->fillRect(option->rect, Qt::red); // painter->save(); // painter->setRenderHint(QPainter::Antialiasing, true); - int d = qMin(option->rect.width(), option->rect.height()); -/* if (d > 20 && option->notchTarget > 0) { - d += -1; - } -*/ QRectF r((option->rect.width() - d) / 2.0, (option->rect.height() - d) / 2.0, d, d); - const qreal angle = option->direction == Qt::LeftToRight ? 135.0 : 45.0; + int d = qMin(option->rect.width(), option->rect.height()); + /* if (d > 20 && option->notchTarget > 0) { + d += -1; + } + */ + QRectF r((option->rect.width() - d) / 2.0, (option->rect.height() - d) / 2.0, d, d); + const qreal angle = option->direction == Qt::LeftToRight ? 135.0 : 45.0; // const qreal angle = 90; - painter->setPen(Qt::NoPen); - painter->setRenderHint(QPainter::Antialiasing); - QColor border_color = option->palette.color(QPalette::Window); + painter->setPen(Qt::NoPen); + painter->setRenderHint(QPainter::Antialiasing); + QColor border_color = option->palette.color(QPalette::Window); #if 0 - { - QRadialGradient depth_gradient(r.center(), d / 2); + { + QRadialGradient depth_gradient(r.center(), d / 2); // depth_gradient.setColorAt(0.0, QColor(0, 0, 0, 255)); - depth_gradient.setColorAt(0.5, QColor(0, 0, 0, 255)); - depth_gradient.setColorAt(1.0, QColor(0, 0, 0, 0)); - painter->setBrush(depth_gradient); - painter->drawEllipse(r); - } + depth_gradient.setColorAt(0.5, QColor(0, 0, 0, 255)); + depth_gradient.setColorAt(1.0, QColor(0, 0, 0, 0)); + painter->setBrush(depth_gradient); + painter->drawEllipse(r); + } #endif #if 1 - if (option->state & QStyle::State_HasFocus && option->state & QStyle::State_KeyboardFocusChange) { - painter->setBrush(option->palette.color(QPalette::Highlight).darker(180)); - r.adjust(1, 1, -1, -1); - painter->drawEllipse(r); - painter->setBrush(border_color); - r.adjust(1, 1, -1, -1); - painter->drawEllipse(r); - r.adjust(1, 1, -1, -1); - } else { - painter->setBrush(border_color); - r.adjust(1, 1, -1, -1); - painter->drawEllipse(r); - r.adjust(1, 1, -1, -1); - QConicalGradient border_gradient(r.center(), angle); - if (!(option->state & QStyle::State_Enabled)) { - border_color = border_color.lighter(120); - } - border_gradient.setColorAt(0.0, border_color.darker(180)); - border_gradient.setColorAt(0.3, border_color.darker(130)); - border_gradient.setColorAt(0.5, border_color.darker(170)); - border_gradient.setColorAt(0.7, border_color.darker(130)); - border_gradient.setColorAt(1.0, border_color.darker(180)); - painter->setBrush(border_gradient); + if (option->state & QStyle::State_HasFocus && option->state & QStyle::State_KeyboardFocusChange) + { + painter->setBrush(option->palette.color(QPalette::Highlight).darker(180)); + r.adjust(1, 1, -1, -1); + painter->drawEllipse(r); + painter->setBrush(border_color); + r.adjust(1, 1, -1, -1); + painter->drawEllipse(r); + r.adjust(1, 1, -1, -1); + } + else + { + painter->setBrush(border_color); + r.adjust(1, 1, -1, -1); + painter->drawEllipse(r); + r.adjust(1, 1, -1, -1); + QConicalGradient border_gradient(r.center(), angle); + if (!(option->state & QStyle::State_Enabled)) + { + border_color = border_color.lighter(120); + } + border_gradient.setColorAt(0.0, border_color.darker(180)); + border_gradient.setColorAt(0.3, border_color.darker(130)); + border_gradient.setColorAt(0.5, border_color.darker(170)); + border_gradient.setColorAt(0.7, border_color.darker(130)); + border_gradient.setColorAt(1.0, border_color.darker(180)); + painter->setBrush(border_gradient); // painter->setBrush(Qt::blue); - painter->drawEllipse(r); - r.adjust(1, 1, -1, -1); - } - d -= 6; - - QColor dial_color; - if (option->state & QStyle::State_Enabled) { - dial_color = option->palette.color(QPalette::Button).lighter(101); - if (option->state & QStyle::State_MouseOver) { - dial_color = dial_color.lighter(103); - } - } else { - dial_color = option->palette.color(QPalette::Window); - } - qreal t = option->state & QStyle::State_Enabled ? 2.0 : 1.5; - // ###: work around Qt 4.3.0 bug? (this works for 4.3.1) - QConicalGradient border_gradient(r.center(), angle); - border_gradient.setColorAt(0.0, dial_color.lighter(120)); - border_gradient.setColorAt(0.2, dial_color); - border_gradient.setColorAt(0.5, dial_color.darker(130)); - border_gradient.setColorAt(0.8, dial_color); - border_gradient.setColorAt(1.0, dial_color.lighter(120)); - painter->setPen(QPen(border_gradient, t)); + painter->drawEllipse(r); + r.adjust(1, 1, -1, -1); + } + d -= 6; + + QColor dial_color; + if (option->state & QStyle::State_Enabled) + { + dial_color = option->palette.color(QPalette::Button).lighter(101); + if (option->state & QStyle::State_MouseOver) + { + dial_color = dial_color.lighter(103); + } + } + else + { + dial_color = option->palette.color(QPalette::Window); + } + qreal t = option->state & QStyle::State_Enabled ? 2.0 : 1.5; + // ###: work around Qt 4.3.0 bug? (this works for 4.3.1) + QConicalGradient border_gradient(r.center(), angle); + border_gradient.setColorAt(0.0, dial_color.lighter(120)); + border_gradient.setColorAt(0.2, dial_color); + border_gradient.setColorAt(0.5, dial_color.darker(130)); + border_gradient.setColorAt(0.8, dial_color); + border_gradient.setColorAt(1.0, dial_color.lighter(120)); + painter->setPen(QPen(border_gradient, t)); #if 0 - QLinearGradient dial_gradient(r.topLeft(), r.bottomLeft()); - dial_gradient.setColorAt(0.0, dial_color.darker(105)); - dial_gradient.setColorAt(0.5, dial_color.lighter(102)); - dial_gradient.setColorAt(1.0, dial_color.lighter(105)); + QLinearGradient dial_gradient(r.topLeft(), r.bottomLeft()); + dial_gradient.setColorAt(0.0, dial_color.darker(105)); + dial_gradient.setColorAt(0.5, dial_color.lighter(102)); + dial_gradient.setColorAt(1.0, dial_color.lighter(105)); #elif 1 - QLinearGradient dial_gradient(option->direction == Qt::LeftToRight ? r.topLeft() : r.topRight(), option->direction == Qt::LeftToRight ? r.bottomRight() : r.bottomLeft()); + QLinearGradient dial_gradient(option->direction == Qt::LeftToRight ? r.topLeft() : r.topRight(), option->direction == Qt::LeftToRight ? r.bottomRight() : r.bottomLeft()); // QLinearGradient dial_gradient(r.topLeft(), r.bottomLeft()); - if (option->state & QStyle::State_Enabled) { + if (option->state & QStyle::State_Enabled) + { #if 1 - dial_gradient.setColorAt(0.0, dial_color.darker(106)); - dial_gradient.setColorAt(1.0, dial_color.lighter(104)); + dial_gradient.setColorAt(0.0, dial_color.darker(106)); + dial_gradient.setColorAt(1.0, dial_color.lighter(104)); #else - dial_gradient.setColorAt(0.0, dial_color.lighter(101)); - dial_gradient.setColorAt(0.5, dial_color.darker(103)); - dial_gradient.setColorAt(1.0, dial_color.lighter(104)); + dial_gradient.setColorAt(0.0, dial_color.lighter(101)); + dial_gradient.setColorAt(0.5, dial_color.darker(103)); + dial_gradient.setColorAt(1.0, dial_color.lighter(104)); #endif - } else { - dial_gradient.setColorAt(0.0, dial_color); - dial_gradient.setColorAt(1.0, dial_color); - } + } + else + { + dial_gradient.setColorAt(0.0, dial_color); + dial_gradient.setColorAt(1.0, dial_color); + } #elif 0 - QConicalGradient dial_gradient(r.center(), angle); - dial_gradient.setColorAt(0.0, dial_color.lighter(102)); - dial_gradient.setColorAt(0.5, dial_color.darker(103)); - dial_gradient.setColorAt(1.0, dial_color.lighter(102)); + QConicalGradient dial_gradient(r.center(), angle); + dial_gradient.setColorAt(0.0, dial_color.lighter(102)); + dial_gradient.setColorAt(0.5, dial_color.darker(103)); + dial_gradient.setColorAt(1.0, dial_color.lighter(102)); #else - QBrush dial_gradient(dial_color); + QBrush dial_gradient(dial_color); #endif - painter->setBrush(dial_gradient); - t = t / 2; - painter->drawEllipse(r.adjusted(t, t, -t, -t)); + painter->setBrush(dial_gradient); + t = t / 2; + painter->drawEllipse(r.adjusted(t, t, -t, -t)); // painter->setPen(Qt::NoPen); // painter->setBrush(dial_color); // painter->drawEllipse(r.adjusted(d / 4, d / 4, - d / 4, - d / 4)); #if 0 - QLinearGradient border2_gradient(r.topLeft(), r.bottomRight()); - border2_gradient.setColorAt(1.0, dial_color.darker(425)); - border2_gradient.setColorAt(0.9, dial_color); - border2_gradient.setColorAt(0.0, dial_color.darker(400)); - painter->setPen(QPen(border2_gradient, 1.3)); - painter->setBrush(Qt::NoBrush); - painter->drawEllipse(r.adjusted(0.3, 0.3, -0.3, -0.3)); + QLinearGradient border2_gradient(r.topLeft(), r.bottomRight()); + border2_gradient.setColorAt(1.0, dial_color.darker(425)); + border2_gradient.setColorAt(0.9, dial_color); + border2_gradient.setColorAt(0.0, dial_color.darker(400)); + painter->setPen(QPen(border2_gradient, 1.3)); + painter->setBrush(Qt::NoBrush); + painter->drawEllipse(r.adjusted(0.3, 0.3, -0.3, -0.3)); #endif // painter->restore(); #endif @@ -195,262 +212,297 @@ paintDialBase(QPainter *painter, const QStyleOption *option) void paintCachedDialBase(QPainter *painter, const QStyleOptionSlider *option) { - bool useCache = UsePixmapCache; - QString pixmapName; - QRect r = option->rect; - int d = qMin(r.width(), r.height()); - - if (/* option->state & (QStyle::State_HasFocus | QStyle::State_MouseOver) ||*/ d > 128) { - useCache = false; - } - if (useCache) { - uint state = uint(option->state) & (QStyle::State_Enabled | QStyle::State_On | QStyle::State_MouseOver | QStyle::State_KeyboardFocusChange | QStyle::State_HasFocus); - if (!(state & QStyle::State_Enabled)) { - state &= ~(QStyle::State_MouseOver | QStyle::State_HasFocus | QStyle::State_KeyboardFocusChange); - } - // state &= ~(QStyle::State_HasFocus); - pixmapName = QString("scp-qdb-%1-%2-%3-%4") - .arg(state, 0, 16) - .arg(option->direction, 0, 16) - .arg(option->palette.cacheKey(), 0, 16) - .arg(d, 0, 16); - } - paintIndicatorCached(painter, option, paintDialBase, useCache, pixmapName); + bool useCache = UsePixmapCache; + QString pixmapName; + QRect r = option->rect; + int d = qMin(r.width(), r.height()); + + if (/* option->state & (QStyle::State_HasFocus | QStyle::State_MouseOver) ||*/ d > 128) + { + useCache = false; + } + if (useCache) + { + uint state = uint(option->state) & (QStyle::State_Enabled | QStyle::State_On | QStyle::State_MouseOver | QStyle::State_KeyboardFocusChange | QStyle::State_HasFocus); + if (!(state & QStyle::State_Enabled)) + { + state &= ~(QStyle::State_MouseOver | QStyle::State_HasFocus | QStyle::State_KeyboardFocusChange); + } + // state &= ~(QStyle::State_HasFocus); + pixmapName = QString("scp-qdb-%1-%2-%3-%4") + .arg(state, 0, 16) + .arg(option->direction, 0, 16) + .arg(option->palette.cacheKey(), 0, 16) + .arg(d, 0, 16); + } + paintIndicatorCached(painter, option, paintDialBase, useCache, pixmapName); } void paintIndicatorDial(QPainter *painter, const QStyleOptionSlider *option) { - int d = qMin(option->rect.width(), option->rect.height()); - QRect rect(option->rect.center() - QPoint((d - 1) / 2, (d - 1) / 2), QSize(d, d)); - QStyleOptionSlider opt; - opt.QStyleOption::operator=(*option); - opt.rect = rect; - paintCachedDialBase(painter, &opt); + int d = qMin(option->rect.width(), option->rect.height()); + QRect rect(option->rect.center() - QPoint((d - 1) / 2, (d - 1) / 2), QSize(d, d)); + QStyleOptionSlider opt; + opt.QStyleOption::operator=(*option); + opt.rect = rect; + paintCachedDialBase(painter, &opt); } QColor shaded_color(const QColor &color, int shade) { #if 1 - const qreal contrast = 1.0; - int r, g, b; - color.getRgb(&r, &g, &b); - int gray = qGray(r, g, b); - gray = qMax(r, qMax(g, b)); - gray = (r + b + g + 3 * gray) / 6; - if (shade < 0) { - qreal k = 220.0 / 255.0 * shade; - k *= contrast; - int a = 255; - if (gray > 0) { - a = int(k * 255 / (0 - gray)); - if (a < 0) a = 0; - if (a > 255) a = 255; - } - return QColor(0, 0, 0, a); - } else { - qreal k = (255 - 220.0) / (255.0) * shade; - k *= contrast; - int a = 255; - if (gray < 255) { - a = int(k * 255 / (255 - gray)); - if (a < 0) a = 0; - if (a > 255) a = 255; - } - return QColor(255, 255, 255, a); - } + const qreal contrast = 1.0; + int r, g, b; + color.getRgb(&r, &g, &b); + int gray = qGray(r, g, b); + gray = qMax(r, qMax(g, b)); + gray = (r + b + g + 3 * gray) / 6; + if (shade < 0) + { + qreal k = 220.0 / 255.0 * shade; + k *= contrast; + int a = 255; + if (gray > 0) + { + a = int(k * 255 / (0 - gray)); + if (a < 0) a = 0; + if (a > 255) a = 255; + } + return QColor(0, 0, 0, a); + } + else + { + qreal k = (255 - 220.0) / (255.0) * shade; + k *= contrast; + int a = 255; + if (gray < 255) + { + a = int(k * 255 / (255 - gray)); + if (a < 0) a = 0; + if (a > 255) a = 255; + } + return QColor(255, 255, 255, a); + } #else - if (shade < 0) { - return QColor(0, 0, 0, -shade); - } else { - return QColor(255, 255, 255, shade); - } + if (shade < 0) + { + return QColor(0, 0, 0, -shade); + } + else + { + return QColor(255, 255, 255, shade); + } #endif } static void paintGrip(QPainter *painter, const QStyleOption *option) { - //painter->fillRect(option->rect, Qt::red); - int d = qMin(option->rect.width(), option->rect.height()); - // good values are 3 (very small), 4 (small), 5 (good), 7 (large), 9 (huge) - // int d = 5; - QRectF rect(QRectF(option->rect).center() - QPointF(d / 2.0, d / 2.0), QSizeF(d, d)); - const qreal angle = option->direction == Qt::LeftToRight ? 135.0 : 45.0; + //painter->fillRect(option->rect, Qt::red); + int d = qMin(option->rect.width(), option->rect.height()); + // good values are 3 (very small), 4 (small), 5 (good), 7 (large), 9 (huge) + // int d = 5; + QRectF rect(QRectF(option->rect).center() - QPointF(d / 2.0, d / 2.0), QSizeF(d, d)); + const qreal angle = option->direction == Qt::LeftToRight ? 135.0 : 45.0; // const qreal angle = 90; - QColor color; - qreal opacity = 0.9; - - painter->save(); - painter->setRenderHint(QPainter::Antialiasing); - painter->setPen(Qt::NoPen); - if (option->state & QStyle::State_Enabled) { - if (option->state & QStyle::State_Sunken) { - color = option->palette.color(QPalette::Highlight).darker(110); - } else { - color = option->palette.color(QPalette::Button); - } - } else { - color = option->palette.color(QPalette::Button); - opacity = 0.5; - } - - QConicalGradient gradient1(rect.center(), angle); - gradient1.setColorAt(0.0, shaded_color(color, -110)); - gradient1.setColorAt(0.25, shaded_color(color, -30)); - gradient1.setColorAt(0.5, shaded_color(color, 180)); - gradient1.setColorAt(0.75, shaded_color(color, -30)); - gradient1.setColorAt(1.0, shaded_color(color, -110)); - painter->setBrush(color); - painter->drawEllipse(rect); - painter->setBrush(gradient1); + QColor color; + qreal opacity = 0.9; + + painter->save(); + painter->setRenderHint(QPainter::Antialiasing); + painter->setPen(Qt::NoPen); + if (option->state & QStyle::State_Enabled) + { + if (option->state & QStyle::State_Sunken) + { + color = option->palette.color(QPalette::Highlight).darker(110); + } + else + { + color = option->palette.color(QPalette::Button); + } + } + else + { + color = option->palette.color(QPalette::Button); + opacity = 0.5; + } + + QConicalGradient gradient1(rect.center(), angle); + gradient1.setColorAt(0.0, shaded_color(color, -110)); + gradient1.setColorAt(0.25, shaded_color(color, -30)); + gradient1.setColorAt(0.5, shaded_color(color, 180)); + gradient1.setColorAt(0.75, shaded_color(color, -30)); + gradient1.setColorAt(1.0, shaded_color(color, -110)); + painter->setBrush(color); + painter->drawEllipse(rect); + painter->setBrush(gradient1); #if (QT_VERSION >= QT_VERSION_CHECK(4, 2, 0)) - // ### merge opacity into color - painter->setOpacity(opacity); + // ### merge opacity into color + painter->setOpacity(opacity); #endif - painter->drawEllipse(rect); + painter->drawEllipse(rect); #if (QT_VERSION >= QT_VERSION_CHECK(4, 2, 0)) - painter->setOpacity(1.0); - if (d > 2) { - QConicalGradient gradient2(rect.center(), angle); - gradient2.setColorAt(0.0, shaded_color(color, -40)); - gradient2.setColorAt(0.25, shaded_color(color, 0)); - gradient2.setColorAt(0.5, shaded_color(color, 210)); - gradient2.setColorAt(0.75, shaded_color(color, 0)); - gradient2.setColorAt(1.0, shaded_color(color, -40)); - rect.adjust(1, 1, -1, -1); - painter->setBrush(color); - painter->drawEllipse(rect); - painter->setBrush(gradient2); - painter->setOpacity(opacity); - painter->drawEllipse(rect); - painter->setOpacity(1.0); - if (d > 8) { - QConicalGradient gradient3(rect.center(), angle); - gradient3.setColorAt(0.0, shaded_color(color, -10)); - gradient3.setColorAt(0.25, shaded_color(color, 0)); - gradient3.setColorAt(0.5, shaded_color(color, 180)); - gradient3.setColorAt(0.75, shaded_color(color, 0)); - gradient3.setColorAt(1.0, shaded_color(color, -10)); - rect.adjust(2, 2, -2, -2); - painter->setBrush(color); - painter->drawEllipse(rect); - painter->setBrush(gradient3); - painter->setOpacity(opacity); - painter->drawEllipse(rect); - painter->setOpacity(1.0); - } - } + painter->setOpacity(1.0); + if (d > 2) + { + QConicalGradient gradient2(rect.center(), angle); + gradient2.setColorAt(0.0, shaded_color(color, -40)); + gradient2.setColorAt(0.25, shaded_color(color, 0)); + gradient2.setColorAt(0.5, shaded_color(color, 210)); + gradient2.setColorAt(0.75, shaded_color(color, 0)); + gradient2.setColorAt(1.0, shaded_color(color, -40)); + rect.adjust(1, 1, -1, -1); + painter->setBrush(color); + painter->drawEllipse(rect); + painter->setBrush(gradient2); + painter->setOpacity(opacity); + painter->drawEllipse(rect); + painter->setOpacity(1.0); + if (d > 8) + { + QConicalGradient gradient3(rect.center(), angle); + gradient3.setColorAt(0.0, shaded_color(color, -10)); + gradient3.setColorAt(0.25, shaded_color(color, 0)); + gradient3.setColorAt(0.5, shaded_color(color, 180)); + gradient3.setColorAt(0.75, shaded_color(color, 0)); + gradient3.setColorAt(1.0, shaded_color(color, -10)); + rect.adjust(2, 2, -2, -2); + painter->setBrush(color); + painter->drawEllipse(rect); + painter->setBrush(gradient3); + painter->setOpacity(opacity); + painter->drawEllipse(rect); + painter->setOpacity(1.0); + } + } #endif - painter->restore(); + painter->restore(); } void paintCachedGrip(QPainter *painter, const QStyleOption *option) { - bool useCache = UsePixmapCache; - QString pixmapName; - - if (/* option->state & (QStyle::State_HasFocus | QStyle::State_MouseOver) ||*/ option->rect.width() * option->rect.height() > 4096) { - useCache = false; - } - if (useCache) { - QStyle::State state = option->state & (QStyle::State_Enabled | QStyle::State_On | QStyle::State_MouseOver | QStyle::State_Sunken | QStyle::State_HasFocus); - if (!(state & QStyle::State_Enabled)) { - state &= ~(QStyle::State_MouseOver | QStyle::State_HasFocus); - } - state &= ~(QStyle::State_HasFocus); - QByteArray colorName = option->palette.color(QPalette::Button).name().toLatin1(); - pixmapName = QString("scp-isg-%1-%2-%3-%4-%5") - .arg(state, 0, 16) - .arg(option->direction, 0, 16) - .arg(QString(colorName)) - .arg(option->rect.width(), 0, 16) - .arg(option->rect.height(), 0, 16); - } - paintIndicatorCached(painter,option, - [=](QPainter *painter,const QStyleOption *option){ - QStyleOption opt(*option); - opt.rect.moveTo(0, 0); - paintGrip(painter,&opt); - }, - useCache,pixmapName); + bool useCache = UsePixmapCache; + QString pixmapName; + + if (/* option->state & (QStyle::State_HasFocus | QStyle::State_MouseOver) ||*/ option->rect.width() * option->rect.height() > 4096) + { + useCache = false; + } + if (useCache) + { + QStyle::State state = option->state & (QStyle::State_Enabled | QStyle::State_On | QStyle::State_MouseOver | QStyle::State_Sunken | QStyle::State_HasFocus); + if (!(state & QStyle::State_Enabled)) + { + state &= ~(QStyle::State_MouseOver | QStyle::State_HasFocus); + } + state &= ~(QStyle::State_HasFocus); + QByteArray colorName = option->palette.color(QPalette::Button).name().toLatin1(); + pixmapName = QString("scp-isg-%1-%2-%3-%4-%5") + .arg(state, 0, 16) + .arg(option->direction, 0, 16) + .arg(QString(colorName)) + .arg(option->rect.width(), 0, 16) + .arg(option->rect.height(), 0, 16); + } + paintIndicatorCached(painter, option, + [ = ](QPainter * painter, const QStyleOption * option) + { + QStyleOption opt(*option); + opt.rect.moveTo(0, 0); + paintGrip(painter, &opt); + }, + useCache, pixmapName); } void -QDialSkulptureStyle::drawComplexControl( ComplexControl cc, - const QStyleOptionComplex *optc, - QPainter *painter, - const QWidget *widget) const +QDialSkulptureStyle::drawComplexControl(ComplexControl cc, + const QStyleOptionComplex *optc, + QPainter *painter, + const QWidget *widget) const { - if (cc != QStyle::CC_Dial) { - QCommonStyle::drawComplexControl(cc, optc, painter, widget); - return; - } - - const QStyleOptionSlider *option = qstyleoption_cast(optc); - if (option == nullptr) - return; - - int d = qMin(option->rect.width() & ~1, option->rect.height() & ~1); - QStyleOptionSlider opt = *option; - const QAbstractSlider *slider = nullptr; - // always highlight knob if pressed (even if mouse is not over knob) - if ((option->state & QStyle::State_HasFocus) && (slider = qobject_cast(widget))) { - if (slider->isSliderDown()) { - opt.state |= QStyle::State_MouseOver; - } - } - - // tickmarks - opt.palette.setColor(QPalette::Inactive, QPalette::WindowText, QColor(80, 80, 80, 255)); - opt.palette.setColor(QPalette::Active, QPalette::WindowText, QColor(80, 80, 80, 255)); - opt.state &= ~QStyle::State_HasFocus; - opt.rect.setWidth(opt.rect.width() & ~1); - opt.rect.setHeight(opt.rect.height() & ~1); - opt.rect.moveCenter(option->rect.center()); - QCommonStyle::drawComplexControl(QStyle::CC_Dial, &opt, painter, widget); - - // focus rectangle - if (option->state & QStyle::State_HasFocus) { - QStyleOptionFocusRect focus; - opt.state |= QStyle::State_HasFocus; - focus.QStyleOption::operator=(opt); - focus.rect.adjust(-1, -1, 1, 1); - //drawPrimitive(QStyle::PE_FrameFocusRect, &focus, painter, widget); - } - opt.palette = option->palette; - - // dial base - if (d <= 256) { - QStyleOptionSlider topt(opt); - topt.rect.adjust(2,2,-2,-2); - topt.rect.moveCenter(option->rect.center()); - paintIndicatorDial(painter, &topt); - } else { - // large dials are slow to render, do not render them - } - - // dial knob - d -= 6; - int gripSize = (option->fontMetrics.height() / 4) * 2 - 1; - opt.rect.setSize(QSize(gripSize, gripSize)); - opt.rect.moveCenter(option->rect.center()); - // angle calculation from qcommonstyle.cpp (c) Trolltech 1992-2007, ASA. - qreal angle; - int sliderPosition = option->upsideDown ? option->sliderPosition : (option->maximum - option->sliderPosition); - int range = option->maximum - option->minimum; - if (!range) { - angle = M_PI / 2; - } else if (option->dialWrapping) { - angle = M_PI * 1.5 - (sliderPosition - option->minimum) * 2 * M_PI / range; - } else { - angle = (M_PI * 8 - (sliderPosition - option->minimum) * 10 * M_PI / range) / 6; - } - - qreal rr = d / 2.0 - gripSize - 2; - opt.rect.translate(int(0.5 + rr * cos(angle)), int(0.5 - rr * sin(angle))); - paintCachedGrip(painter, &opt); + if (cc != QStyle::CC_Dial) + { + QCommonStyle::drawComplexControl(cc, optc, painter, widget); + return; + } + + const QStyleOptionSlider *option = qstyleoption_cast(optc); + if (option == nullptr) + return; + + int d = qMin(option->rect.width() & ~1, option->rect.height() & ~1); + QStyleOptionSlider opt = *option; + const QAbstractSlider *slider = nullptr; + // always highlight knob if pressed (even if mouse is not over knob) + if ((option->state & QStyle::State_HasFocus) && (slider = qobject_cast(widget))) + { + if (slider->isSliderDown()) + { + opt.state |= QStyle::State_MouseOver; + } + } + + // tickmarks + opt.palette.setColor(QPalette::Inactive, QPalette::WindowText, QColor(80, 80, 80, 255)); + opt.palette.setColor(QPalette::Active, QPalette::WindowText, QColor(80, 80, 80, 255)); + opt.state &= ~QStyle::State_HasFocus; + opt.rect.setWidth(opt.rect.width() & ~1); + opt.rect.setHeight(opt.rect.height() & ~1); + opt.rect.moveCenter(option->rect.center()); + QCommonStyle::drawComplexControl(QStyle::CC_Dial, &opt, painter, widget); + + // focus rectangle + if (option->state & QStyle::State_HasFocus) + { + QStyleOptionFocusRect focus; + opt.state |= QStyle::State_HasFocus; + focus.QStyleOption::operator=(opt); + focus.rect.adjust(-1, -1, 1, 1); + //drawPrimitive(QStyle::PE_FrameFocusRect, &focus, painter, widget); + } + opt.palette = option->palette; + + // dial base + if (d <= 256) + { + QStyleOptionSlider topt(opt); + topt.rect.adjust(2, 2, -2, -2); + topt.rect.moveCenter(option->rect.center()); + paintIndicatorDial(painter, &topt); + } + else + { + // large dials are slow to render, do not render them + } + + // dial knob + d -= 6; + int gripSize = (option->fontMetrics.height() / 4) * 2 - 1; + opt.rect.setSize(QSize(gripSize, gripSize)); + opt.rect.moveCenter(option->rect.center()); + // angle calculation from qcommonstyle.cpp (c) Trolltech 1992-2007, ASA. + qreal angle; + int sliderPosition = option->upsideDown ? option->sliderPosition : (option->maximum - option->sliderPosition); + int range = option->maximum - option->minimum; + if (!range) + { + angle = M_PI / 2; + } + else if (option->dialWrapping) + { + angle = M_PI * 1.5 - (sliderPosition - option->minimum) * 2 * M_PI / range; + } + else + { + angle = (M_PI * 8 - (sliderPosition - option->minimum) * 10 * M_PI / range) / 6; + } + + qreal rr = d / 2.0 - gripSize - 2; + opt.rect.translate(int(0.5 + rr * cos(angle)), int(0.5 - rr * sin(angle))); + paintCachedGrip(painter, &opt); } diff --git a/qmidiplayer-desktop/qdialskulpturestyle.hpp b/qmidiplayer-desktop/qdialskulpturestyle.hpp index 2f3ba04..42a8e0d 100644 --- a/qmidiplayer-desktop/qdialskulpturestyle.hpp +++ b/qmidiplayer-desktop/qdialskulpturestyle.hpp @@ -25,14 +25,14 @@ #include -class QDialSkulptureStyle:public QCommonStyle +class QDialSkulptureStyle : public QCommonStyle { public: - QDialSkulptureStyle(){} - virtual ~QDialSkulptureStyle(){} + QDialSkulptureStyle() {} + virtual ~QDialSkulptureStyle() {} - virtual void drawComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, QPainter *p, - const QWidget *widget=0) const; + virtual void drawComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, QPainter *p, + const QWidget *widget = nullptr) const; }; diff --git a/qmidiplayer-desktop/qmpchanneleditor.cpp b/qmidiplayer-desktop/qmpchanneleditor.cpp index 5343c1c..8f92932 100644 --- a/qmidiplayer-desktop/qmpchanneleditor.cpp +++ b/qmidiplayer-desktop/qmpchanneleditor.cpp @@ -4,140 +4,163 @@ #include "qmpmainwindow.hpp" qmpChannelEditor::qmpChannelEditor(QWidget *parent): - QDialog(parent), - ui(new Ui::qmpChannelEditor) + QDialog(parent), + ui(new Ui::qmpChannelEditor) { - ui->setupUi(this);ch=0; - styl=new QDialSkulptureStyle(); - dials=findChildren(); - for(auto&d:dials) - d->setStyle(styl); + ui->setupUi(this); + ch = 0; + styl = new QDialSkulptureStyle(); + dials = findChildren(); + for (auto &d : dials) + d->setStyle(styl); } qmpChannelEditor::~qmpChannelEditor() { - delete styl; - delete ui; + delete styl; + delete ui; } void qmpChannelEditor::setupWindow(int chid) { - char str[256];if(~chid)ch=chid; - setWindowTitle(tr("Channel Parameter Editor - Channel #%1").arg(ch+1)); - CMidiPlayer* player=qmpMainWindow::getInstance()->getPlayer(); - uint16_t b;uint8_t p;std::string pstn; - if(!player->getChannelOutputDevice(ch)->getChannelPreset(ch,&b,&p,pstn)) - { - b=player->getCC(ch,0)<<7|player->getCC(ch,32); - p=player->getCC(ch,128); - pstn=player->getChannelOutputDevice(ch)->getPresetName(b,p); - } - ui->lbPresetName->setText(pstn.c_str()); - sprintf(str,"BK: %03d",b);ui->lbBank->setText(str); - sprintf(str,"PC: %03d",p);ui->lbPreset->setText(str); - ui->lbChannelNumber->setText(QString::number(ch+1)); - auto setupControl=[this,player](int ccid,QLabel* lb,QDial* d,QString ccname,std::function valconv) - { - uint16_t b=player->getCC(ch,ccid); - lb->setText(QString("%1 %2").arg(ccname).arg(valconv(b))); - d->setValue(b); - }; - auto defconv=std::bind(static_cast(&QString::number),std::placeholders::_1,10); - auto panconv=[](uint v)->QString{ - if(v==64)return tr("C"); - else if(v<64)return tr("L%1").arg(64-v); - else return tr("R%1").arg(v-64); - }; - setupControl(7,ui->lbVol,ui->dVol,tr("Vol."),defconv); - setupControl(91,ui->lbReverb,ui->dReverb,tr("Rev."),defconv); - setupControl(93,ui->lbChorus,ui->dChorus,tr("Chr."),defconv); - setupControl(71,ui->lbReso,ui->dReso,tr("Res."),defconv); - setupControl(74,ui->lbCut,ui->dCut,tr("Cut."),defconv); - setupControl(73,ui->lbAttack,ui->dAttack,tr("Atk."),defconv); - setupControl(75,ui->lbDecay,ui->dDecay,tr("Dec."),defconv); - setupControl(72,ui->lbRelease,ui->dRelease,tr("Rel."),defconv); - setupControl(76,ui->lbRate,ui->dRate,tr("Rate"),defconv); - setupControl(77,ui->lbDepth,ui->dDepth,tr("Dep."),defconv); - setupControl(78,ui->lbDelay,ui->dDelay,tr("Del."),defconv); - setupControl(10,ui->lbPan,ui->dPan,tr("Pan."),panconv); + char str[256]; + if (~chid) + ch = chid; + setWindowTitle(tr("Channel Parameter Editor - Channel #%1").arg(ch + 1)); + CMidiPlayer *player = qmpMainWindow::getInstance()->getPlayer(); + uint16_t b; + uint8_t p; + std::string pstn; + if (!player->getChannelOutputDevice(ch)->getChannelPreset(ch, &b, &p, pstn)) + { + b = player->getCC(ch, 0) << 7 | player->getCC(ch, 32); + p = player->getCC(ch, 128); + pstn = player->getChannelOutputDevice(ch)->getPresetName(b, p); + } + ui->lbPresetName->setText(pstn.c_str()); + sprintf(str, "BK: %03d", b); + ui->lbBank->setText(str); + sprintf(str, "PC: %03d", p); + ui->lbPreset->setText(str); + ui->lbChannelNumber->setText(QString::number(ch + 1)); + auto setupControl = [this, player](int ccid, QLabel *lb, QDial *d, QString ccname, std::function valconv) + { + uint16_t b = player->getCC(ch, ccid); + lb->setText(QString("%1 %2").arg(ccname).arg(valconv(b))); + d->setValue(b); + }; + auto defconv = std::bind(static_cast(&QString::number), std::placeholders::_1, 10); + auto panconv = [](uint v)->QString + { + if (v == 64) + return tr("C"); + else if (v < 64) + return tr("L%1").arg(64 - v); + else return tr("R%1").arg(v - 64); + }; + setupControl(7, ui->lbVol, ui->dVol, tr("Vol."), defconv); + setupControl(91, ui->lbReverb, ui->dReverb, tr("Rev."), defconv); + setupControl(93, ui->lbChorus, ui->dChorus, tr("Chr."), defconv); + setupControl(71, ui->lbReso, ui->dReso, tr("Res."), defconv); + setupControl(74, ui->lbCut, ui->dCut, tr("Cut."), defconv); + setupControl(73, ui->lbAttack, ui->dAttack, tr("Atk."), defconv); + setupControl(75, ui->lbDecay, ui->dDecay, tr("Dec."), defconv); + setupControl(72, ui->lbRelease, ui->dRelease, tr("Rel."), defconv); + setupControl(76, ui->lbRate, ui->dRate, tr("Rate"), defconv); + setupControl(77, ui->lbDepth, ui->dDepth, tr("Dep."), defconv); + setupControl(78, ui->lbDelay, ui->dDelay, tr("Del."), defconv); + setupControl(10, ui->lbPan, ui->dPan, tr("Pan."), panconv); } void qmpChannelEditor::sendCC() { - CMidiPlayer* player=qmpMainWindow::getInstance()->getPlayer(); - player->setCC(ch,7,ui->dVol->value()); - player->setCC(ch,10,ui->dPan->value()); - player->setCC(ch,91,ui->dReverb->value()); - player->setCC(ch,93,ui->dChorus->value()); - player->setCC(ch,71,ui->dReso->value()); - player->setCC(ch,74,ui->dCut->value()); - player->setCC(ch,73,ui->dAttack->value()); - player->setCC(ch,75,ui->dDecay->value()); - player->setCC(ch,72,ui->dRelease->value()); - player->setCC(ch,76,ui->dRate->value()); - player->setCC(ch,77,ui->dDepth->value()); - player->setCC(ch,78,ui->dDelay->value()); - qmpMainWindow::getInstance()->invokeCallback("channel.ccchange",nullptr); + CMidiPlayer *player = qmpMainWindow::getInstance()->getPlayer(); + player->setCC(ch, 7, ui->dVol->value()); + player->setCC(ch, 10, ui->dPan->value()); + player->setCC(ch, 91, ui->dReverb->value()); + player->setCC(ch, 93, ui->dChorus->value()); + player->setCC(ch, 71, ui->dReso->value()); + player->setCC(ch, 74, ui->dCut->value()); + player->setCC(ch, 73, ui->dAttack->value()); + player->setCC(ch, 75, ui->dDecay->value()); + player->setCC(ch, 72, ui->dRelease->value()); + player->setCC(ch, 76, ui->dRate->value()); + player->setCC(ch, 77, ui->dDepth->value()); + player->setCC(ch, 78, ui->dDelay->value()); + qmpMainWindow::getInstance()->invokeCallback("channel.ccchange", nullptr); } void qmpChannelEditor::showEvent(QShowEvent *e) { - knobpressed=0; - setupWindow(); - connectSlots(); - updconn=connect(qmpMainWindow::getInstance()->getTimer(),&QTimer::timeout,std::bind(&qmpChannelEditor::setupWindow,this,-1)); - e->accept(); + knobpressed = 0; + setupWindow(); + connectSlots(); + updconn = connect(qmpMainWindow::getInstance()->getTimer(), &QTimer::timeout, std::bind(&qmpChannelEditor::setupWindow, this, -1)); + e->accept(); } void qmpChannelEditor::closeEvent(QCloseEvent *e) { - disconnectSlots(); - disconnect(updconn); - e->accept(); + disconnectSlots(); + disconnect(updconn); + e->accept(); } void qmpChannelEditor::on_pbChLeft_clicked() { - disconnectSlots(); - if(ch>0)--ch;else ch=15;setupWindow(); - connectSlots(); + disconnectSlots(); + if (ch > 0) + --ch; + else ch = 15; + setupWindow(); + connectSlots(); } void qmpChannelEditor::on_pbChRight_clicked() { - disconnectSlots(); - if(ch<15)++ch;else ch=0;setupWindow(); - connectSlots(); + disconnectSlots(); + if (ch < 15) + ++ch; + else ch = 0; + setupWindow(); + connectSlots(); } void qmpChannelEditor::commonPressed() { - disconnect(updconn); - knobpressed=1; + disconnect(updconn); + knobpressed = 1; } void qmpChannelEditor::commonReleased() { - updconn=connect(qmpMainWindow::getInstance()->getTimer(),&QTimer::timeout,std::bind(&qmpChannelEditor::setupWindow,this,-1)); - sendCC();knobpressed=0; + updconn = connect(qmpMainWindow::getInstance()->getTimer(), &QTimer::timeout, std::bind(&qmpChannelEditor::setupWindow, this, -1)); + sendCC(); + knobpressed = 0; } void qmpChannelEditor::commonChanged() -{if(knobpressed){sendCC();setupWindow();}} +{ + if (knobpressed) + { + sendCC(); + setupWindow(); + } +} void qmpChannelEditor::connectSlots() { - for(auto&d:dials) - { - connect(d,&QDial::sliderPressed,this,&qmpChannelEditor::commonPressed); - connect(d,&QDial::sliderReleased,this,&qmpChannelEditor::commonReleased); - connect(d,&QDial::valueChanged,this,&qmpChannelEditor::commonChanged); - } + for (auto &d : dials) + { + connect(d, &QDial::sliderPressed, this, &qmpChannelEditor::commonPressed); + connect(d, &QDial::sliderReleased, this, &qmpChannelEditor::commonReleased); + connect(d, &QDial::valueChanged, this, &qmpChannelEditor::commonChanged); + } } void qmpChannelEditor::disconnectSlots() { - for(auto&d:dials) - { - disconnect(d,&QDial::sliderPressed,this,&qmpChannelEditor::commonPressed); - disconnect(d,&QDial::sliderReleased,this,&qmpChannelEditor::commonReleased); - disconnect(d,&QDial::valueChanged,this,&qmpChannelEditor::commonChanged); - } + for (auto &d : dials) + { + disconnect(d, &QDial::sliderPressed, this, &qmpChannelEditor::commonPressed); + disconnect(d, &QDial::sliderReleased, this, &qmpChannelEditor::commonReleased); + disconnect(d, &QDial::valueChanged, this, &qmpChannelEditor::commonChanged); + } } diff --git a/qmidiplayer-desktop/qmpchanneleditor.hpp b/qmidiplayer-desktop/qmpchanneleditor.hpp index c7ef028..9749124 100644 --- a/qmidiplayer-desktop/qmpchanneleditor.hpp +++ b/qmidiplayer-desktop/qmpchanneleditor.hpp @@ -6,40 +6,41 @@ #include #include "qdialskulpturestyle.hpp" -namespace Ui { - class qmpChannelEditor; +namespace Ui +{ +class qmpChannelEditor; } class QDial; -class qmpChannelEditor:public QDialog +class qmpChannelEditor: public QDialog { - Q_OBJECT + Q_OBJECT - public: - explicit qmpChannelEditor(QWidget *parent=nullptr); - ~qmpChannelEditor(); - protected: - void showEvent(QShowEvent *e); - void closeEvent(QCloseEvent *e); - public slots: - void setupWindow(int chid=-1); +public: + explicit qmpChannelEditor(QWidget *parent = nullptr); + ~qmpChannelEditor(); +protected: + void showEvent(QShowEvent *e); + void closeEvent(QCloseEvent *e); +public slots: + void setupWindow(int chid = -1); - private slots: - void commonPressed(); - void commonReleased(); - void commonChanged(); - void on_pbChLeft_clicked(); - void on_pbChRight_clicked(); +private slots: + void commonPressed(); + void commonReleased(); + void commonChanged(); + void on_pbChLeft_clicked(); + void on_pbChRight_clicked(); - private: - Ui::qmpChannelEditor *ui; - int ch,knobpressed; - void sendCC(); - void connectSlots(); - void disconnectSlots(); - QList dials; - QMetaObject::Connection updconn; - QCommonStyle* styl; +private: + Ui::qmpChannelEditor *ui; + int ch, knobpressed; + void sendCC(); + void connectSlots(); + void disconnectSlots(); + QList dials; + QMetaObject::Connection updconn; + QCommonStyle *styl; }; #endif // QMPCHANNELEDITOR_H diff --git a/qmidiplayer-desktop/qmpchannelswindow.cpp b/qmidiplayer-desktop/qmpchannelswindow.cpp index 0854e4c..e22d75e 100644 --- a/qmidiplayer-desktop/qmpchannelswindow.cpp +++ b/qmidiplayer-desktop/qmpchannelswindow.cpp @@ -9,360 +9,394 @@ #include "ui_qmpchannelswindow.h" #include "qmpmainwindow.hpp" -qmpChannelsModel::qmpChannelsModel(QObject*parent):QAbstractTableModel(parent) +qmpChannelsModel::qmpChannelsModel(QObject *parent): QAbstractTableModel(parent) { - evh=qmpMainWindow::getInstance()->getPlayer()->registerEventHandler( - [this](const void* _e,void*){ - if(!updatequeued) - { - updatequeued=true; - const SEvent *e=(const SEvent*)(_e); - if((e->p1&0xF0)==0xC0) - emit dataChanged(index(e->p1&0xF0,4),index(e->p1&0xF0,4),{Qt::ItemDataRole::DisplayRole}); - QMetaObject::invokeMethod(this, &qmpChannelsModel::updateChannelActivity, Qt::ConnectionType::QueuedConnection); - } - } - ,nullptr,false); - QTimer*t=new QTimer(this); - t->setInterval(500); - t->setSingleShot(false); - connect(t,&QTimer::timeout,[this](){emit this->dataChanged(this->index(0,4),this->index(15,4),{Qt::ItemDataRole::DisplayRole});}); - memset(mute,0,sizeof(mute)); - memset(solo,0,sizeof(solo)); + evh = qmpMainWindow::getInstance()->getPlayer()->registerEventHandler( + [this](const void *_e, void *) + { + if (!updatequeued) + { + updatequeued = true; + const SEvent *e = (const SEvent *)(_e); + if ((e->p1 & 0xF0) == 0xC0) + emit dataChanged(index(e->p1 & 0xF0, 4), index(e->p1 & 0xF0, 4), {Qt::ItemDataRole::DisplayRole}); + QMetaObject::invokeMethod(this, &qmpChannelsModel::updateChannelActivity, Qt::ConnectionType::QueuedConnection); + } + } + , nullptr, false); + QTimer *t = new QTimer(this); + t->setInterval(500); + t->setSingleShot(false); + connect(t, &QTimer::timeout, [this]() + { + emit this->dataChanged(this->index(0, 4), this->index(15, 4), {Qt::ItemDataRole::DisplayRole}); + }); + memset(mute, 0, sizeof(mute)); + memset(solo, 0, sizeof(solo)); } -int qmpChannelsModel::columnCount(const QModelIndex&parent)const -{return parent.isValid()?0:6;} -int qmpChannelsModel::rowCount(const QModelIndex&parent)const -{return parent.isValid()?0:16;} -QModelIndex qmpChannelsModel::parent(const QModelIndex&child)const +int qmpChannelsModel::columnCount(const QModelIndex &parent)const { - Q_UNUSED(child) - return QModelIndex(); + return parent.isValid() ? 0 : 6; } -QVariant qmpChannelsModel::data(const QModelIndex&index,int role)const +int qmpChannelsModel::rowCount(const QModelIndex &parent)const { - switch(index.column()) - { - case 0: - if(role==Qt::ItemDataRole::DecorationRole) - { - using namespace std::chrono_literals; - bool lit=(std::chrono::system_clock::now()-qmpMainWindow::getInstance()->getPlayer()->getLastEventTS()[index.row()])<50ms; - return lit?QIcon(":/img/ledon.svg"):QIcon(":/img/ledoff.svg"); - } - break; - case 1: - if(role==Qt::ItemDataRole::CheckStateRole) - return mute[index.row()]?Qt::CheckState::Checked:Qt::CheckState::Unchecked; - break; - case 2: - if(role==Qt::ItemDataRole::CheckStateRole) - return solo[index.row()]?Qt::CheckState::Checked:Qt::CheckState::Unchecked; - break; - case 3: - if(role==Qt::ItemDataRole::DisplayRole) - { - std::vector devs=qmpMainWindow::getInstance()->getPlayer()->getMidiOutDevices(); - return QString::fromStdString(devs[qmpMainWindow::getInstance()->getPlayer()->getChannelOutput(index.row())]); - } - break; - case 4: - { - if(role==Qt::ItemDataRole::DisplayRole) - { - int ch=index.row(); - uint16_t b;uint8_t p; - std::string nm; - char data[256]; - CMidiPlayer *plyr=qmpMainWindow::getInstance()->getPlayer(); - bool r=plyr->getChannelOutputDevice(ch)->getChannelPreset(ch,&b,&p,nm); - sprintf(data,"%03d:%03d %s",b,p,nm.c_str()); - if(!r) - { - nm=plyr->getChannelOutputDevice(ch)->getPresetName(plyr->getCC(ch,0)<<7|plyr->getCC(ch,32),plyr->getCC(ch,128)); - sprintf(data,"%03d:%03d:%03d %s",plyr->getCC(ch,0),plyr->getCC(ch,32),plyr->getCC(ch,128),nm.c_str()); - } - return QString(data); - } - } - break; - case 5: - if(role==Qt::ItemDataRole::DisplayRole) - return "..."; - if(role==Qt::ItemDataRole::TextAlignmentRole) - return Qt::AlignmentFlag::AlignCenter; - break; - } - return QVariant(); + return parent.isValid() ? 0 : 16; } -bool qmpChannelsModel::setData(const QModelIndex&index,const QVariant&value,int role) +QModelIndex qmpChannelsModel::parent(const QModelIndex &child)const { - if(index.column()==3) - { - if(role!=Qt::ItemDataRole::DisplayRole)return false; - std::vector dsv=CMidiPlayer::getInstance()->getMidiOutDevices(); - int idx=std::find(dsv.begin(),dsv.end(),value.toString().toStdString())-dsv.begin(); - if(idx==CMidiPlayer::getInstance()->getChannelOutput(index.row()))return false; - CMidiPlayer::getInstance()->setChannelOutput(index.row(),idx); - emit dataChanged(index,index,{Qt::DisplayRole}); - return true; - } - return false; + Q_UNUSED(child) + return QModelIndex(); } -QVariant qmpChannelsModel::headerData(int section,Qt::Orientation orientation,int role)const +QVariant qmpChannelsModel::data(const QModelIndex &index, int role)const { - if(role!=Qt::ItemDataRole::DisplayRole)return QVariant(); - if(orientation==Qt::Orientation::Vertical) - return section+1; - switch(section) - { - case 0:return QString("A"); - case 1:return QString("M"); - case 2:return QString("S"); - case 3:return QString("Device"); - case 4:return QString("Preset"); - case 5:return QString("..."); - } - return QString(); + switch (index.column()) + { + case 0: + if (role == Qt::ItemDataRole::DecorationRole) + { + using namespace std::chrono_literals; + bool lit = (std::chrono::system_clock::now() - qmpMainWindow::getInstance()->getPlayer()->getLastEventTS()[index.row()]) < 50ms; + return lit ? QIcon(":/img/ledon.svg") : QIcon(":/img/ledoff.svg"); + } + break; + case 1: + if (role == Qt::ItemDataRole::CheckStateRole) + return mute[index.row()] ? Qt::CheckState::Checked : Qt::CheckState::Unchecked; + break; + case 2: + if (role == Qt::ItemDataRole::CheckStateRole) + return solo[index.row()] ? Qt::CheckState::Checked : Qt::CheckState::Unchecked; + break; + case 3: + if (role == Qt::ItemDataRole::DisplayRole) + { + std::vector devs = qmpMainWindow::getInstance()->getPlayer()->getMidiOutDevices(); + return QString::fromStdString(devs[qmpMainWindow::getInstance()->getPlayer()->getChannelOutput(index.row())]); + } + break; + case 4: + { + if (role == Qt::ItemDataRole::DisplayRole) + { + int ch = index.row(); + uint16_t b; + uint8_t p; + std::string nm; + char data[256]; + CMidiPlayer *plyr = qmpMainWindow::getInstance()->getPlayer(); + bool r = plyr->getChannelOutputDevice(ch)->getChannelPreset(ch, &b, &p, nm); + sprintf(data, "%03d:%03d %s", b, p, nm.c_str()); + if (!r) + { + nm = plyr->getChannelOutputDevice(ch)->getPresetName(plyr->getCC(ch, 0) << 7 | plyr->getCC(ch, 32), plyr->getCC(ch, 128)); + sprintf(data, "%03d:%03d:%03d %s", plyr->getCC(ch, 0), plyr->getCC(ch, 32), plyr->getCC(ch, 128), nm.c_str()); + } + return QString(data); + } + } + break; + case 5: + if (role == Qt::ItemDataRole::DisplayRole) + return "..."; + if (role == Qt::ItemDataRole::TextAlignmentRole) + return Qt::AlignmentFlag::AlignCenter; + break; + } + return QVariant(); } -Qt::ItemFlags qmpChannelsModel::flags(const QModelIndex&idx)const +bool qmpChannelsModel::setData(const QModelIndex &index, const QVariant &value, int role) { - Qt::ItemFlags ret=Qt::ItemFlag::ItemIsEnabled|Qt::ItemFlag::ItemIsSelectable; - if(idx.column()==1||idx.column()==2) - ret|=Qt::ItemFlag::ItemIsUserCheckable; - if(idx.column()==3) - ret|=Qt::ItemFlag::ItemIsEditable; - return ret; + if (index.column() == 3) + { + if (role != Qt::ItemDataRole::DisplayRole) + return false; + std::vector dsv = CMidiPlayer::getInstance()->getMidiOutDevices(); + int idx = std::find(dsv.begin(), dsv.end(), value.toString().toStdString()) - dsv.begin(); + if (idx == CMidiPlayer::getInstance()->getChannelOutput(index.row())) + return false; + CMidiPlayer::getInstance()->setChannelOutput(index.row(), idx); + emit dataChanged(index, index, {Qt::DisplayRole}); + return true; + } + return false; +} +QVariant qmpChannelsModel::headerData(int section, Qt::Orientation orientation, int role)const +{ + if (role != Qt::ItemDataRole::DisplayRole) + return QVariant(); + if (orientation == Qt::Orientation::Vertical) + return section + 1; + switch (section) + { + case 0: + return QString("A"); + case 1: + return QString("M"); + case 2: + return QString("S"); + case 3: + return QString("Device"); + case 4: + return QString("Preset"); + case 5: + return QString("..."); + } + return QString(); +} +Qt::ItemFlags qmpChannelsModel::flags(const QModelIndex &idx)const +{ + Qt::ItemFlags ret = Qt::ItemFlag::ItemIsEnabled | Qt::ItemFlag::ItemIsSelectable; + if (idx.column() == 1 || idx.column() == 2) + ret |= Qt::ItemFlag::ItemIsUserCheckable; + if (idx.column() == 3) + ret |= Qt::ItemFlag::ItemIsEditable; + return ret; } void qmpChannelsModel::updateChannelActivity() { - emit dataChanged(index(0,0),index(15,0),{Qt::ItemDataRole::DecorationRole}); - updatequeued=false; + emit dataChanged(index(0, 0), index(15, 0), {Qt::ItemDataRole::DecorationRole}); + updatequeued = false; } -void qmpChannelsModel::channelMSClicked(const QModelIndex&idx) +void qmpChannelsModel::channelMSClicked(const QModelIndex &idx) { - bool*x[3]={nullptr,mute,solo}; - if(x[idx.column()][idx.row()]^=1) - x[3-idx.column()][idx.row()]=0; - qmpMainWindow::getInstance()->getPlayer()->setMute(idx.row(),mute[idx.row()]); - qmpMainWindow::getInstance()->getPlayer()->setSolo(idx.row(),solo[idx.row()]); - emit dataChanged(index(idx.row(),1),index(idx.row(),2),{Qt::ItemDataRole::CheckStateRole}); + bool *x[3] = {nullptr, mute, solo}; + if (x[idx.column()][idx.row()] ^= 1) + x[3 - idx.column()][idx.row()] = 0; + qmpMainWindow::getInstance()->getPlayer()->setMute(idx.row(), mute[idx.row()]); + qmpMainWindow::getInstance()->getPlayer()->setSolo(idx.row(), solo[idx.row()]); + emit dataChanged(index(idx.row(), 1), index(idx.row(), 2), {Qt::ItemDataRole::CheckStateRole}); } void qmpChannelsModel::channelMSClearAll(int type) { - if(type==1) - { - memset(mute,0,sizeof(mute)); - for(int i=0;i<16;++i) - qmpMainWindow::getInstance()->getPlayer()->setMute(i,0); - emit dataChanged(index(0,1),index(15,1),{Qt::ItemDataRole::CheckStateRole}); - } - if(type==2) - { - memset(solo,0,sizeof(solo)); - for(int i=0;i<16;++i) - qmpMainWindow::getInstance()->getPlayer()->setSolo(i,0); - emit dataChanged(index(0,2),index(15,2),{Qt::ItemDataRole::CheckStateRole}); - } + if (type == 1) + { + memset(mute, 0, sizeof(mute)); + for (int i = 0; i < 16; ++i) + qmpMainWindow::getInstance()->getPlayer()->setMute(i, 0); + emit dataChanged(index(0, 1), index(15, 1), {Qt::ItemDataRole::CheckStateRole}); + } + if (type == 2) + { + memset(solo, 0, sizeof(solo)); + for (int i = 0; i < 16; ++i) + qmpMainWindow::getInstance()->getPlayer()->setSolo(i, 0); + emit dataChanged(index(0, 2), index(15, 2), {Qt::ItemDataRole::CheckStateRole}); + } } -qmpDeviceItemDelegate::qmpDeviceItemDelegate(bool ignoreInternal,QWidget*parent): - QStyledItemDelegate(parent),par(parent),nofs(ignoreInternal){} -void qmpDeviceItemDelegate::paint(QPainter*painter,const QStyleOptionViewItem&option,const QModelIndex&index)const +qmpDeviceItemDelegate::qmpDeviceItemDelegate(bool ignoreInternal, QWidget *parent): + QStyledItemDelegate(parent), par(parent), nofs(ignoreInternal) {} +void qmpDeviceItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index)const { - QStyleOptionViewItem opt; - initStyleOption(&opt,index); - QStyleOptionComboBox socb; - socb.currentText=opt.text; - socb.editable=false; - socb.rect=option.rect; - socb.state=opt.state; - par->style()->drawComplexControl(QStyle::ComplexControl::CC_ComboBox,&socb,painter,option.widget); - par->style()->drawControl(QStyle::CE_ComboBoxLabel,&socb,painter,option.widget); + QStyleOptionViewItem opt; + initStyleOption(&opt, index); + QStyleOptionComboBox socb; + socb.currentText = opt.text; + socb.editable = false; + socb.rect = option.rect; + socb.state = opt.state; + par->style()->drawComplexControl(QStyle::ComplexControl::CC_ComboBox, &socb, painter, option.widget); + par->style()->drawControl(QStyle::CE_ComboBoxLabel, &socb, painter, option.widget); } -QSize qmpDeviceItemDelegate::sizeHint(const QStyleOptionViewItem&option,const QModelIndex&index)const +QSize qmpDeviceItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index)const { - QStyleOptionViewItem opt; - initStyleOption(&opt,index); - QStyleOptionComboBox socb; - socb.currentText=opt.text; - socb.editable=false; - socb.rect=option.rect; - QSize sz=par->fontMetrics().size(Qt::TextFlag::TextSingleLine,socb.currentText); - return par->style()->sizeFromContents(QStyle::ContentsType::CT_ComboBox,&socb,sz,option.widget); + QStyleOptionViewItem opt; + initStyleOption(&opt, index); + QStyleOptionComboBox socb; + socb.currentText = opt.text; + socb.editable = false; + socb.rect = option.rect; + QSize sz = par->fontMetrics().size(Qt::TextFlag::TextSingleLine, socb.currentText); + return par->style()->sizeFromContents(QStyle::ContentsType::CT_ComboBox, &socb, sz, option.widget); } -QWidget* qmpDeviceItemDelegate::createEditor(QWidget*parent,const QStyleOptionViewItem&option,const QModelIndex&index)const +QWidget *qmpDeviceItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index)const { - Q_UNUSED(option) - Q_UNUSED(index) - QComboBox *cb=new QComboBox(parent); - cb->setEditable(false); - connect(cb,static_cast(&QComboBox::currentIndexChanged),this,[index,cb](int){ - const_cast(index.model())->setData(index,cb->currentText(),Qt::ItemDataRole::DisplayRole); - cb->hidePopup(); - }); - return cb; + Q_UNUSED(option) + Q_UNUSED(index) + QComboBox *cb = new QComboBox(parent); + cb->setEditable(false); + connect(cb, static_cast(&QComboBox::currentIndexChanged), this, [index, cb](int) + { + const_cast(index.model())->setData(index, cb->currentText(), Qt::ItemDataRole::DisplayRole); + cb->hidePopup(); + }); + return cb; } -void qmpDeviceItemDelegate::setEditorData(QWidget*widget,const QModelIndex&index)const +void qmpDeviceItemDelegate::setEditorData(QWidget *widget, const QModelIndex &index)const { - /* - * We want to quit editing as soon as the popup of the combobox is closed. - * Unfortunately QTableView does not do that. And I don't feel like sub-classing - * it. So here are some dirty tricks to make it work that way. - */ - QComboBox *cb=qobject_cast(widget); - QSignalBlocker sblk(cb); - cb->clear(); - std::vector devs=qmpMainWindow::getInstance()->getPlayer()->getMidiOutDevices(); - for(auto s:devs) - if(!nofs||(nofs&&s!="Internal FluidSynth")) - cb->addItem(QString::fromStdString(s)); - cb->setCurrentText(index.data().toString()); - cb->showPopup(); + /* + * We want to quit editing as soon as the popup of the combobox is closed. + * Unfortunately QTableView does not do that. And I don't feel like sub-classing + * it. So here are some dirty tricks to make it work that way. + */ + QComboBox *cb = qobject_cast(widget); + QSignalBlocker sblk(cb); + cb->clear(); + std::vector devs = qmpMainWindow::getInstance()->getPlayer()->getMidiOutDevices(); + for (auto s : devs) + if (!nofs || (nofs && s != "Internal FluidSynth")) + cb->addItem(QString::fromStdString(s)); + cb->setCurrentText(index.data().toString()); + cb->showPopup(); } -void qmpDeviceItemDelegate::setModelData(QWidget*editor,QAbstractItemModel*model,const QModelIndex&index)const +void qmpDeviceItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index)const { - QComboBox *cb=qobject_cast(editor); - model->setData(index,cb->currentText(),Qt::ItemDataRole::DisplayRole); + QComboBox *cb = qobject_cast(editor); + model->setData(index, cb->currentText(), Qt::ItemDataRole::DisplayRole); } -void qmpDeviceItemDelegate::updateEditorGeometry(QWidget*editor,const QStyleOptionViewItem&option,const QModelIndex&index)const +void qmpDeviceItemDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index)const { - Q_UNUSED(index) - editor->setGeometry(option.rect); + Q_UNUSED(index) + editor->setGeometry(option.rect); } -qmpChannelsWindow::qmpChannelsWindow(QWidget *parent) : - QWidget(parent,Qt::Dialog), - ui(new Ui::qmpChannelsWindow) +qmpChannelsWindow::qmpChannelsWindow(QWidget *parent): + QWidget(parent, Qt::Dialog), + ui(new Ui::qmpChannelsWindow) { - ui->setupUi(this); - mainwindow=qmpMainWindow::getInstance(); - ui->tvChannels->setHorizontalHeader(new QHeaderView(Qt::Orientation::Horizontal)); - ui->tvChannels->setModel(chmodel=new qmpChannelsModel(ui->tvChannels)); - ui->tvChannels->setItemDelegateForColumn(3,new qmpDeviceItemDelegate(false,ui->tvChannels)); - ui->tvChannels->setAlternatingRowColors(true); - ui->tvChannels->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection); - ui->tvChannels->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeMode::ResizeToContents); - ui->tvChannels->horizontalHeader()->setSectionResizeMode(4, QHeaderView::ResizeMode::Stretch); - connect(ui->tvChannels,&QTableView::clicked,[this](const QModelIndex&idx){ - if(idx.column()==1||idx.column()==2) - this->chmodel->channelMSClicked(idx); - if(idx.column()==3) - this->ui->tvChannels->edit(idx); - if(idx.column()==5) - this->showChannelEditorWindow(idx.row()); - }); - connect(ui->tvChannels,&QTableView::activated,[this](const QModelIndex&idx){ - if(idx.column()==4) - { - pselectw->show(); - pselectw->setupWindow(idx.row()); - } - }); - pselectw=new qmpPresetSelector(this); - ceditw=new qmpChannelEditor(this); - cha=new QIcon(":/img/ledon.svg");chi=new QIcon(":/img/ledoff.svg"); - eh=qmpMainWindow::getInstance()->getPlayer()->registerEventHandler( - [this](const void *ee,void*){ - const SEvent *e=(const SEvent*)ee; - if((e->type&0xF0)==0x90&&e->p2>0&&(e->flags&0x01)) - emit this->noteOn(); - } - ,nullptr,false); - qmpMainWindow::getInstance()->registerFunctionality( - chnlf=new qmpChannelFunc(this), - std::string("Channel"), - tr("Channel").toStdString(), - getThemedIconc(":/img/channel.svg"), - 0, - true - ); - if(mainwindow->getSettings()->getOptionRaw("DialogStatus/ChnlW",QRect(-999,-999,999,999)).toRect()!=QRect(-999,-999,999,999)) - setGeometry(mainwindow->getSettings()->getOptionRaw("DialogStatus/ChnlW",QRect(-999,-999,999,999)).toRect()); - if(mainwindow->getSettings()->getOptionRaw("DialogStatus/ChnlWShown",0).toInt()) - {show();qmpMainWindow::getInstance()->setFuncState("Channel",true);} + ui->setupUi(this); + mainwindow = qmpMainWindow::getInstance(); + ui->tvChannels->setHorizontalHeader(new QHeaderView(Qt::Orientation::Horizontal)); + ui->tvChannels->setModel(chmodel = new qmpChannelsModel(ui->tvChannels)); + ui->tvChannels->setItemDelegateForColumn(3, new qmpDeviceItemDelegate(false, ui->tvChannels)); + ui->tvChannels->setAlternatingRowColors(true); + ui->tvChannels->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection); + ui->tvChannels->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeMode::ResizeToContents); + ui->tvChannels->horizontalHeader()->setSectionResizeMode(4, QHeaderView::ResizeMode::Stretch); + connect(ui->tvChannels, &QTableView::clicked, [this](const QModelIndex &idx) + { + if (idx.column() == 1 || idx.column() == 2) + this->chmodel->channelMSClicked(idx); + if (idx.column() == 3) + this->ui->tvChannels->edit(idx); + if (idx.column() == 5) + this->showChannelEditorWindow(idx.row()); + }); + connect(ui->tvChannels, &QTableView::activated, [this](const QModelIndex &idx) + { + if (idx.column() == 4) + { + pselectw->show(); + pselectw->setupWindow(idx.row()); + } + }); + pselectw = new qmpPresetSelector(this); + ceditw = new qmpChannelEditor(this); + cha = new QIcon(":/img/ledon.svg"); + chi = new QIcon(":/img/ledoff.svg"); + eh = qmpMainWindow::getInstance()->getPlayer()->registerEventHandler( + [this](const void *ee, void *) + { + const SEvent *e = (const SEvent *)ee; + if ((e->type & 0xF0) == 0x90 && e->p2 > 0 && (e->flags & 0x01)) + emit this->noteOn(); + } + , nullptr, false); + qmpMainWindow::getInstance()->registerFunctionality( + chnlf = new qmpChannelFunc(this), + std::string("Channel"), + tr("Channel").toStdString(), + getThemedIconc(":/img/channel.svg"), + 0, + true + ); + if (mainwindow->getSettings()->getOptionRaw("DialogStatus/ChnlW", QRect(-999, -999, 999, 999)).toRect() != QRect(-999, -999, 999, 999)) + setGeometry(mainwindow->getSettings()->getOptionRaw("DialogStatus/ChnlW", QRect(-999, -999, 999, 999)).toRect()); + if (mainwindow->getSettings()->getOptionRaw("DialogStatus/ChnlWShown", 0).toInt()) + { + show(); + qmpMainWindow::getInstance()->setFuncState("Channel", true); + } } void qmpChannelsWindow::showEvent(QShowEvent *event) { - if(mainwindow->getSettings()->getOptionBool("Behavior/DialogStatus")) - { - mainwindow->getSettings()->setOptionRaw("DialogStatus/ChnlWShown",1); - } - if(mainwindow->getSettings()->getOptionRaw("DialogStatus/ChnlW",QRect(-999,-999,999,999)).toRect()!=QRect(-999,-999,999,999)) - setGeometry(mainwindow->getSettings()->getOptionRaw("DialogStatus/ChnlW",QRect(-999,-999,999,999)).toRect()); - event->accept(); + if (mainwindow->getSettings()->getOptionBool("Behavior/DialogStatus")) + { + mainwindow->getSettings()->setOptionRaw("DialogStatus/ChnlWShown", 1); + } + if (mainwindow->getSettings()->getOptionRaw("DialogStatus/ChnlW", QRect(-999, -999, 999, 999)).toRect() != QRect(-999, -999, 999, 999)) + setGeometry(mainwindow->getSettings()->getOptionRaw("DialogStatus/ChnlW", QRect(-999, -999, 999, 999)).toRect()); + event->accept(); } void qmpChannelsWindow::closeEvent(QCloseEvent *event) { - if(mainwindow->getSettings()->getOptionBool("Behavior/DialogStatus")) - { - mainwindow->getSettings()->setOptionRaw("DialogStatus/ChnlW",geometry()); - } - setVisible(false); - if(!qmpMainWindow::getInstance()->isFinalizing()&&mainwindow->getSettings()->getOptionBool("Behavior/DialogStatus")) - { - mainwindow->getSettings()->setOptionRaw("DialogStatus/ChnlWShown",0); - } - mainwindow->setFuncState("Channel",false); - event->accept(); + if (mainwindow->getSettings()->getOptionBool("Behavior/DialogStatus")) + { + mainwindow->getSettings()->setOptionRaw("DialogStatus/ChnlW", geometry()); + } + setVisible(false); + if (!qmpMainWindow::getInstance()->isFinalizing() && mainwindow->getSettings()->getOptionBool("Behavior/DialogStatus")) + { + mainwindow->getSettings()->setOptionRaw("DialogStatus/ChnlWShown", 0); + } + mainwindow->setFuncState("Channel", false); + event->accept(); } void qmpChannelsWindow::selectDefaultDevice() { - std::string selecteddev; - std::vector devs=mainwindow->getPlayer()->getMidiOutDevices(); - size_t devc=devs.size(); - std::set devset; - for(auto dev:devs)devset.insert(dev); - QVariant *devpriov=static_cast(qmpMainWindow::getInstance()->getSettings()->getOptionCustom("Midi/DevicePriority")); - QList devprio=devpriov->toList(); - delete devpriov; - for(auto &setdev:devprio) - if(devset.find(setdev.toString().toStdString())!=devset.end()) - { - selecteddev=setdev.toString().toStdString(); - break; - } - for(int ch=0;ch<16;++ch) - { - for(size_t j=0;jgetPlayer()->setChannelOutput(ch,j); - } - } + std::string selecteddev; + std::vector devs = mainwindow->getPlayer()->getMidiOutDevices(); + size_t devc = devs.size(); + std::set devset; + for (auto dev : devs) + devset.insert(dev); + QVariant *devpriov = static_cast(qmpMainWindow::getInstance()->getSettings()->getOptionCustom("Midi/DevicePriority")); + QList devprio = devpriov->toList(); + delete devpriov; + for (auto &setdev : devprio) + if (devset.find(setdev.toString().toStdString()) != devset.end()) + { + selecteddev = setdev.toString().toStdString(); + break; + } + for (int ch = 0; ch < 16; ++ch) + { + for (size_t j = 0; j < devc; ++j) + { + if (selecteddev == devs[j]) + mainwindow->getPlayer()->setChannelOutput(ch, j); + } + } } qmpChannelsWindow::~qmpChannelsWindow() { - mainwindow->unregisterFunctionality("Channel"); - mainwindow->getPlayer()->unregisterEventHandler(eh); - delete chnlf; - delete chi;delete cha; - delete ui; + mainwindow->unregisterFunctionality("Channel"); + mainwindow->getPlayer()->unregisterEventHandler(eh); + delete chnlf; + delete chi; + delete cha; + delete ui; } void qmpChannelsWindow::on_pbUnmute_clicked() { - chmodel->channelMSClearAll(1); + chmodel->channelMSClearAll(1); } void qmpChannelsWindow::on_pbUnsolo_clicked() { - chmodel->channelMSClearAll(2); + chmodel->channelMSClearAll(2); } void qmpChannelsWindow::showChannelEditorWindow(int chid) { - ceditw->show(); - ceditw->setupWindow(chid); + ceditw->show(); + ceditw->setupWindow(chid); } qmpChannelFunc::qmpChannelFunc(qmpChannelsWindow *par) -{p=par;} +{ + p = par; +} void qmpChannelFunc::show() -{p->show();} +{ + p->show(); +} void qmpChannelFunc::close() -{p->close();} +{ + p->close(); +} diff --git a/qmidiplayer-desktop/qmpchannelswindow.hpp b/qmidiplayer-desktop/qmpchannelswindow.hpp index f78d032..c8443e7 100644 --- a/qmidiplayer-desktop/qmpchannelswindow.hpp +++ b/qmidiplayer-desktop/qmpchannelswindow.hpp @@ -15,88 +15,89 @@ #include "../core/qmpmidiplay.hpp" #include "../core/qmpmidioutrtmidi.hpp" -namespace Ui { - class qmpChannelsWindow; +namespace Ui +{ +class qmpChannelsWindow; } class qmpChannelsWindow; class qmpMainWindow; -class qmpChannelFunc:public qmpFuncBaseIntf +class qmpChannelFunc : public qmpFuncBaseIntf { - private: - qmpChannelsWindow *p; - public: - qmpChannelFunc(qmpChannelsWindow *par); - void show(); - void close(); +private: + qmpChannelsWindow *p; +public: + qmpChannelFunc(qmpChannelsWindow *par); + void show(); + void close(); }; -class qmpChannelsModel:public QAbstractTableModel +class qmpChannelsModel : public QAbstractTableModel { - Q_OBJECT - public: - explicit qmpChannelsModel(QObject*parent=nullptr); - int columnCount(const QModelIndex&parent=QModelIndex())const override; - int rowCount(const QModelIndex&parent=QModelIndex())const override; - QModelIndex parent(const QModelIndex&child)const override; - QVariant data(const QModelIndex&index,int role=Qt::ItemDataRole::DisplayRole)const override; - bool setData(const QModelIndex &index,const QVariant &value,int role=Qt::EditRole)override; - QVariant headerData(int section,Qt::Orientation orientation,int role=Qt::ItemDataRole::DisplayRole)const override; - Qt::ItemFlags flags(const QModelIndex&idx)const override; - public slots: - void updateChannelActivity(); - void channelMSClicked(const QModelIndex&idx); - void channelMSClearAll(int type); - private: - int evh; - bool updatequeued; - bool mute[16],solo[16]; + Q_OBJECT +public: + explicit qmpChannelsModel(QObject *parent = nullptr); + int columnCount(const QModelIndex &parent = QModelIndex())const override; + int rowCount(const QModelIndex &parent = QModelIndex())const override; + QModelIndex parent(const QModelIndex &child)const override; + QVariant data(const QModelIndex &index, int role = Qt::ItemDataRole::DisplayRole)const override; + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole)override; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::ItemDataRole::DisplayRole)const override; + Qt::ItemFlags flags(const QModelIndex &idx)const override; +public slots: + void updateChannelActivity(); + void channelMSClicked(const QModelIndex &idx); + void channelMSClearAll(int type); +private: + int evh; + bool updatequeued; + bool mute[16], solo[16]; }; -class qmpDeviceItemDelegate:public QStyledItemDelegate +class qmpDeviceItemDelegate: public QStyledItemDelegate { - Q_OBJECT - public: - explicit qmpDeviceItemDelegate(bool ignoreInternal=false,QWidget*parent=nullptr); - void paint(QPainter*painter,const QStyleOptionViewItem&option,const QModelIndex&index)const override; - QSize sizeHint(const QStyleOptionViewItem&option,const QModelIndex&index)const override; - QWidget* createEditor(QWidget*parent,const QStyleOptionViewItem&option,const QModelIndex&index)const override; - void setEditorData(QWidget*editor,const QModelIndex&index)const override; - void setModelData(QWidget*editor,QAbstractItemModel*model,const QModelIndex&index)const override; - void updateEditorGeometry(QWidget*editor,const QStyleOptionViewItem&option,const QModelIndex&index)const override; - private: - QWidget *par; - bool nofs; + Q_OBJECT +public: + explicit qmpDeviceItemDelegate(bool ignoreInternal = false, QWidget *parent = nullptr); + void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index)const override; + QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index)const override; + QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index)const override; + void setEditorData(QWidget *editor, const QModelIndex &index)const override; + void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index)const override; + void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index)const override; +private: + QWidget *par; + bool nofs; }; -class qmpChannelsWindow:public QWidget +class qmpChannelsWindow: public QWidget { - Q_OBJECT + Q_OBJECT - public: - explicit qmpChannelsWindow(QWidget *parent=nullptr); - ~qmpChannelsWindow(); - void showEvent(QShowEvent *event); - void closeEvent(QCloseEvent *event); - void selectDefaultDevice(); - public slots: - void showChannelEditorWindow(int chid); - void on_pbUnmute_clicked(); - void on_pbUnsolo_clicked(); +public: + explicit qmpChannelsWindow(QWidget *parent = nullptr); + ~qmpChannelsWindow(); + void showEvent(QShowEvent *event); + void closeEvent(QCloseEvent *event); + void selectDefaultDevice(); +public slots: + void showChannelEditorWindow(int chid); + void on_pbUnmute_clicked(); + void on_pbUnsolo_clicked(); - signals: - void noteOn(); +signals: + void noteOn(); - private: - qmpMainWindow* mainwindow; - Ui::qmpChannelsWindow *ui; - qmpPresetSelector *pselectw; - qmpChannelEditor *ceditw; - qmpChannelsModel *chmodel; - QIcon *cha,*chi; - qmpChannelFunc *chnlf; - int eh; +private: + qmpMainWindow *mainwindow; + Ui::qmpChannelsWindow *ui; + qmpPresetSelector *pselectw; + qmpChannelEditor *ceditw; + qmpChannelsModel *chmodel; + QIcon *cha, *chi; + qmpChannelFunc *chnlf; + int eh; }; #endif // QMPCHANNELSWINDOW_H diff --git a/qmidiplayer-desktop/qmpcustomizewindow.cpp b/qmidiplayer-desktop/qmpcustomizewindow.cpp index 0ea3228..f4346b4 100644 --- a/qmidiplayer-desktop/qmpcustomizewindow.cpp +++ b/qmidiplayer-desktop/qmpcustomizewindow.cpp @@ -9,83 +9,86 @@ #include "ui_qmpcustomizewindow.h" qmpCustomizeWindow::qmpCustomizeWindow(QWidget *parent): - QDialog(parent), - ui(new Ui::qmpCustomizeWindow) + QDialog(parent), + ui(new Ui::qmpCustomizeWindow) { - ui->setupUi(this); + ui->setupUi(this); } qmpCustomizeWindow::~qmpCustomizeWindow() { - delete ui; + delete ui; } void qmpCustomizeWindow::load(void *data) { - ui->lwAvail->clear(); - ui->lwEnabled->clear(); - QList list=static_cast(data)->toList(); - std::vector v; - for(auto i:list) - v.push_back(i.toString().toStdString()); - std::map& m=qmpMainWindow::getInstance()->getFunc(); - std::set s; - for(auto i=v.begin();i!=v.end();++i) - { - if(m.find(*i)==m.end())continue; - s.insert(*i); - QListWidgetItem* it=new QListWidgetItem( - m[*i].icon(), - QString(m[*i].desc().c_str()) - ); - it->setToolTip(i->c_str()); - ui->lwEnabled->addItem(it); - } - for(auto i=m.begin();i!=m.end();++i) - { - if(s.find(i->first)==s.end()) - { - QListWidgetItem* it=new QListWidgetItem( - i->second.icon(), - QString(i->second.desc().c_str()) - ); - it->setToolTip(i->first.c_str()); - ui->lwAvail->addItem(it); - } - } + ui->lwAvail->clear(); + ui->lwEnabled->clear(); + QList list = static_cast(data)->toList(); + std::vector v; + for (auto i : list) + v.push_back(i.toString().toStdString()); + std::map &m = qmpMainWindow::getInstance()->getFunc(); + std::set s; + for (auto i = v.begin(); i != v.end(); ++i) + { + if (m.find(*i) == m.end()) + continue; + s.insert(*i); + QListWidgetItem *it = new QListWidgetItem( + m[*i].icon(), + QString(m[*i].desc().c_str()) + ); + it->setToolTip(i->c_str()); + ui->lwEnabled->addItem(it); + } + for (auto i = m.begin(); i != m.end(); ++i) + { + if (s.find(i->first) == s.end()) + { + QListWidgetItem *it = new QListWidgetItem( + i->second.icon(), + QString(i->second.desc().c_str()) + ); + it->setToolTip(i->first.c_str()); + ui->lwAvail->addItem(it); + } + } } void *qmpCustomizeWindow::save() { - QList ret; - for(int i=0;ilwEnabled->count();++i) - { - ret.push_back(QVariant(ui->lwEnabled->item(i)->toolTip())); - } - return new QVariant(ret); + QList ret; + for (int i = 0; i < ui->lwEnabled->count(); ++i) + { + ret.push_back(QVariant(ui->lwEnabled->item(i)->toolTip())); + } + return new QVariant(ret); } void qmpCustomizeWindow::on_tbAdd_clicked() { - if(!ui->lwAvail->currentItem())return; - ui->lwEnabled->addItem(ui->lwAvail->takeItem(ui->lwAvail->currentRow())); - ui->lwAvail->removeItemWidget(ui->lwAvail->currentItem()); + if (!ui->lwAvail->currentItem()) + return; + ui->lwEnabled->addItem(ui->lwAvail->takeItem(ui->lwAvail->currentRow())); + ui->lwAvail->removeItemWidget(ui->lwAvail->currentItem()); } void qmpCustomizeWindow::on_tbRemove_clicked() { - if(!ui->lwEnabled->currentItem())return; - ui->lwAvail->addItem(ui->lwEnabled->takeItem(ui->lwEnabled->currentRow())); + if (!ui->lwEnabled->currentItem()) + return; + ui->lwAvail->addItem(ui->lwEnabled->takeItem(ui->lwEnabled->currentRow())); } void qmpCustomizeWindow::on_buttonBox_accepted() { - accept(); - close(); + accept(); + close(); } void qmpCustomizeWindow::on_buttonBox_rejected() { - reject(); - close(); + reject(); + close(); } diff --git a/qmidiplayer-desktop/qmpcustomizewindow.hpp b/qmidiplayer-desktop/qmpcustomizewindow.hpp index 321c22e..002d2fc 100644 --- a/qmidiplayer-desktop/qmpcustomizewindow.hpp +++ b/qmidiplayer-desktop/qmpcustomizewindow.hpp @@ -3,28 +3,29 @@ #include -namespace Ui { +namespace Ui +{ class qmpCustomizeWindow; } -class qmpCustomizeWindow:public QDialog +class qmpCustomizeWindow: public QDialog { - Q_OBJECT + Q_OBJECT - public: - explicit qmpCustomizeWindow(QWidget *parent=nullptr); - ~qmpCustomizeWindow(); - void load(void* data); - void* save(); +public: + explicit qmpCustomizeWindow(QWidget *parent = nullptr); + ~qmpCustomizeWindow(); + void load(void *data); + void *save(); - private slots: - void on_tbAdd_clicked(); - void on_tbRemove_clicked(); - void on_buttonBox_accepted(); - void on_buttonBox_rejected(); +private slots: + void on_tbAdd_clicked(); + void on_tbRemove_clicked(); + void on_buttonBox_accepted(); + void on_buttonBox_rejected(); - private: - Ui::qmpCustomizeWindow *ui; +private: + Ui::qmpCustomizeWindow *ui; }; #endif // QMPCUSTOMIZEWINDOW_HPP diff --git a/qmidiplayer-desktop/qmpdeviceprioritydialog.cpp b/qmidiplayer-desktop/qmpdeviceprioritydialog.cpp index bf358d8..9c77e0a 100644 --- a/qmidiplayer-desktop/qmpdeviceprioritydialog.cpp +++ b/qmidiplayer-desktop/qmpdeviceprioritydialog.cpp @@ -6,107 +6,108 @@ #include "ui_qmpdeviceprioritydialog.h" qmpDevicePriorityDialog::qmpDevicePriorityDialog(QWidget *parent) : - QDialog(parent), - ui(new Ui::qmpDevicePriorityDialog) + QDialog(parent), + ui(new Ui::qmpDevicePriorityDialog) { - ui->setupUi(this); - model=new QStandardItemModel(this); - ui->tvDevices->setModel(model); - ui->tvDevices->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection); - ui->tvDevices->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeMode::ResizeToContents); - ui->tvDevices->setSelectionBehavior(QAbstractItemView::SelectionBehavior::SelectRows); - model->setHorizontalHeaderLabels({"E","Device","Connected?"}); + ui->setupUi(this); + model = new QStandardItemModel(this); + ui->tvDevices->setModel(model); + ui->tvDevices->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection); + ui->tvDevices->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeMode::ResizeToContents); + ui->tvDevices->setSelectionBehavior(QAbstractItemView::SelectionBehavior::SelectRows); + model->setHorizontalHeaderLabels({"E", "Device", "Connected?"}); } qmpDevicePriorityDialog::~qmpDevicePriorityDialog() { - delete ui; + delete ui; } void qmpDevicePriorityDialog::setupRegisteredDevices() { - std::set sset,sconn; - auto conndevs=CMidiPlayer::getInstance()->getMidiOutDevices(); - for(auto dev:conndevs) - sconn.insert(dev); - model->removeRows(0,model->rowCount()); - for(auto dev:setdevs) - { - QStandardItem *e=new QStandardItem; - e->setCheckable(true); - e->setEditable(false); - e->setCheckState(Qt::CheckState::Checked); - QStandardItem *a=new QStandardItem; - a->setText(sconn.find(dev.toString().toStdString())!=sconn.end()?"Connected":"Disconnected"); - a->setEditable(false); - QStandardItem *devn=new QStandardItem(dev.toString()); - devn->setEditable(false); - model->appendRow({e,devn,a}); - sset.insert(dev.toString().toStdString()); - } - for(auto dev:conndevs) - { - if(sset.find(dev)!=sset.end())continue; - QStandardItem *e=new QStandardItem; - e->setCheckable(true); - e->setEditable(false); - e->setCheckState(Qt::CheckState::Unchecked); - QStandardItem *a=new QStandardItem; - a->setText("Connected"); - a->setEditable(false); - QStandardItem *devn=new QStandardItem(QString::fromStdString(dev)); - devn->setEditable(false); - model->appendRow({e,devn,a}); - } + std::set sset, sconn; + auto conndevs = CMidiPlayer::getInstance()->getMidiOutDevices(); + for (auto dev : conndevs) + sconn.insert(dev); + model->removeRows(0, model->rowCount()); + for (auto dev : setdevs) + { + QStandardItem *e = new QStandardItem; + e->setCheckable(true); + e->setEditable(false); + e->setCheckState(Qt::CheckState::Checked); + QStandardItem *a = new QStandardItem; + a->setText(sconn.find(dev.toString().toStdString()) != sconn.end() ? "Connected" : "Disconnected"); + a->setEditable(false); + QStandardItem *devn = new QStandardItem(dev.toString()); + devn->setEditable(false); + model->appendRow({e, devn, a}); + sset.insert(dev.toString().toStdString()); + } + for (auto dev : conndevs) + { + if (sset.find(dev) != sset.end()) + continue; + QStandardItem *e = new QStandardItem; + e->setCheckable(true); + e->setEditable(false); + e->setCheckState(Qt::CheckState::Unchecked); + QStandardItem *a = new QStandardItem; + a->setText("Connected"); + a->setEditable(false); + QStandardItem *devn = new QStandardItem(QString::fromStdString(dev)); + devn->setEditable(false); + model->appendRow({e, devn, a}); + } } void qmpDevicePriorityDialog::load(void *data) { - setdevs=static_cast(data)->toList(); - setupRegisteredDevices(); + setdevs = static_cast(data)->toList(); + setupRegisteredDevices(); } void *qmpDevicePriorityDialog::save() { - QList ret; - for(int i=0;irowCount();++i) - if(model->item(i,0)->checkState()==Qt::CheckState::Checked) - ret.push_back(model->item(i,1)->text()); - return new QVariant(ret); + QList ret; + for (int i = 0; i < model->rowCount(); ++i) + if (model->item(i, 0)->checkState() == Qt::CheckState::Checked) + ret.push_back(model->item(i, 1)->text()); + return new QVariant(ret); } void qmpDevicePriorityDialog::on_pbUp_clicked() { - const QModelIndex &idx=ui->tvDevices->selectionModel()->currentIndex(); - if(idx.isValid()&&idx.row()>0) - { - int row=idx.row(); - auto r=model->takeRow(row); - model->insertRow(row-1,r); - ui->tvDevices->clearSelection(); - ui->tvDevices->selectionModel()->setCurrentIndex(model->index(row-1,idx.column()),QItemSelectionModel::Rows|QItemSelectionModel::Select); - } + const QModelIndex &idx = ui->tvDevices->selectionModel()->currentIndex(); + if (idx.isValid() && idx.row() > 0) + { + int row = idx.row(); + auto r = model->takeRow(row); + model->insertRow(row - 1, r); + ui->tvDevices->clearSelection(); + ui->tvDevices->selectionModel()->setCurrentIndex(model->index(row - 1, idx.column()), QItemSelectionModel::Rows | QItemSelectionModel::Select); + } } void qmpDevicePriorityDialog::on_pbDown_clicked() { - const QModelIndex &idx=ui->tvDevices->selectionModel()->currentIndex(); - if(idx.isValid()&&idx.row()rowCount()-1) - { - int row=idx.row(); - auto r=model->takeRow(row); - model->insertRow(row+1,r); - ui->tvDevices->clearSelection(); - ui->tvDevices->selectionModel()->setCurrentIndex(model->index(row+1,idx.column()),QItemSelectionModel::Rows|QItemSelectionModel::Select); - } + const QModelIndex &idx = ui->tvDevices->selectionModel()->currentIndex(); + if (idx.isValid() && idx.row() < model->rowCount() - 1) + { + int row = idx.row(); + auto r = model->takeRow(row); + model->insertRow(row + 1, r); + ui->tvDevices->clearSelection(); + ui->tvDevices->selectionModel()->setCurrentIndex(model->index(row + 1, idx.column()), QItemSelectionModel::Rows | QItemSelectionModel::Select); + } } void qmpDevicePriorityDialog::on_buttonBox_accepted() { - accept(); + accept(); } void qmpDevicePriorityDialog::on_buttonBox_rejected() { - reject(); + reject(); } diff --git a/qmidiplayer-desktop/qmpdeviceprioritydialog.hpp b/qmidiplayer-desktop/qmpdeviceprioritydialog.hpp index 78ce3fa..85170b9 100644 --- a/qmidiplayer-desktop/qmpdeviceprioritydialog.hpp +++ b/qmidiplayer-desktop/qmpdeviceprioritydialog.hpp @@ -5,32 +5,33 @@ #include #include -namespace Ui { +namespace Ui +{ class qmpDevicePriorityDialog; } -class qmpDevicePriorityDialog:public QDialog +class qmpDevicePriorityDialog : public QDialog { - Q_OBJECT + Q_OBJECT public: - explicit qmpDevicePriorityDialog(QWidget *parent=nullptr); - ~qmpDevicePriorityDialog(); - void load(void* data); - void* save(); + explicit qmpDevicePriorityDialog(QWidget *parent = nullptr); + ~qmpDevicePriorityDialog(); + void load(void *data); + void *save(); private slots: - void on_pbUp_clicked(); - void on_pbDown_clicked(); - void on_buttonBox_accepted(); + void on_pbUp_clicked(); + void on_pbDown_clicked(); + void on_buttonBox_accepted(); - void on_buttonBox_rejected(); + void on_buttonBox_rejected(); - private: - Ui::qmpDevicePriorityDialog *ui; - QStandardItemModel *model; - QList setdevs; - void setupRegisteredDevices(); +private: + Ui::qmpDevicePriorityDialog *ui; + QStandardItemModel *model; + QList setdevs; + void setupRegisteredDevices(); }; #endif // QMPDEVICEPRIORITYDIALOG_HPP diff --git a/qmidiplayer-desktop/qmpdevpropdialog.cpp b/qmidiplayer-desktop/qmpdevpropdialog.cpp index 3b9ccc4..c5f1966 100644 --- a/qmidiplayer-desktop/qmpdevpropdialog.cpp +++ b/qmidiplayer-desktop/qmpdevpropdialog.cpp @@ -10,108 +10,113 @@ #include "ui_qmpdevpropdialog.h" qmpDevPropDialog::qmpDevPropDialog(QWidget *parent) : - QDialog(parent), - ui(new Ui::qmpDevPropDialog) + QDialog(parent), + ui(new Ui::qmpDevPropDialog) { - ui->setupUi(this); - ui->twProps->setItemDelegateForColumn(0,new qmpDeviceItemDelegate(true,ui->twProps)); - ui->twProps->setEditTriggers(QAbstractItemView::EditTrigger::NoEditTriggers); - connect(ui->twProps,&QTableWidget::cellClicked,[this](int r,int c){ - if(c==0) - this->ui->twProps->edit(ui->twProps->model()->index(r,c)); - if(c==3) - { - QString p=QFileDialog::getOpenFileUrl(this,tr("Select Device Initialization File"),QUrl()).toLocalFile(); - if(p.length())this->ui->twProps->item(r,2)->setText(p); - } - }); - connect(ui->twProps,&QTableWidget::cellChanged,this,[this](int r,int c){ - if(c!=0)return; - QString connst(tr("Disconnected")); - for(auto&ds:qmpMainWindow::getInstance()->getPlayer()->getMidiOutDevices()) - if(ui->twProps->item(r,c)->text()==QString::fromStdString(ds)) - { - connst=tr("Connected"); - break; - } - ui->twProps->item(r,1)->setText(connst); - }); + ui->setupUi(this); + ui->twProps->setItemDelegateForColumn(0, new qmpDeviceItemDelegate(true, ui->twProps)); + ui->twProps->setEditTriggers(QAbstractItemView::EditTrigger::NoEditTriggers); + connect(ui->twProps, &QTableWidget::cellClicked, [this](int r, int c) + { + if (c == 0) + this->ui->twProps->edit(ui->twProps->model()->index(r, c)); + if (c == 3) + { + QString p = QFileDialog::getOpenFileUrl(this, tr("Select Device Initialization File"), QUrl()).toLocalFile(); + if (p.length()) + this->ui->twProps->item(r, 2)->setText(p); + } + }); + connect(ui->twProps, &QTableWidget::cellChanged, this, [this](int r, int c) + { + if (c != 0) + return; + QString connst(tr("Disconnected")); + for (auto &ds : qmpMainWindow::getInstance()->getPlayer()->getMidiOutDevices()) + if (ui->twProps->item(r, c)->text() == QString::fromStdString(ds)) + { + connst = tr("Connected"); + break; + } + ui->twProps->item(r, 1)->setText(connst); + }); } qmpDevPropDialog::~qmpDevPropDialog() { - delete ui; + delete ui; } void qmpDevPropDialog::load(void *data) { - QList lst=static_cast(data)->toList(); - ui->twProps->clearContents(); - ui->twProps->setRowCount(0); - for(auto&i:lst) - { - QPair p=i.value>(); - setupRow(p.first,p.second); - } + QList lst = static_cast(data)->toList(); + ui->twProps->clearContents(); + ui->twProps->setRowCount(0); + for (auto &i : lst) + { + QPair p = i.value>(); + setupRow(p.first, p.second); + } } void *qmpDevPropDialog::save() { - QList ret; - for(int i=0;itwProps->rowCount();++i) - { - QPair p - { - ui->twProps->item(i,0)->text(), - ui->twProps->item(i,2)->text() - }; - ret.push_back(QVariant::fromValue(p)); - } - return new QVariant(ret); + QList ret; + for (int i = 0; i < ui->twProps->rowCount(); ++i) + { + QPair p + { + ui->twProps->item(i, 0)->text(), + ui->twProps->item(i, 2)->text() + }; + ret.push_back(QVariant::fromValue(p)); + } + return new QVariant(ret); } void qmpDevPropDialog::on_pbAdd_clicked() { - setupRow(); + setupRow(); } void qmpDevPropDialog::on_pbRemove_clicked() { - ui->twProps->removeRow(ui->twProps->currentRow()); + ui->twProps->removeRow(ui->twProps->currentRow()); } -void qmpDevPropDialog::setupRow(const QString&dn,const QString&din) +void qmpDevPropDialog::setupRow(const QString &dn, const QString &din) { - int r; - ui->twProps->insertRow(r=ui->twProps->rowCount()); - ui->twProps->setRowHeight(r,32); - QTableWidgetItem *cbx=new QTableWidgetItem; - ui->twProps->setItem(r,1,cbx); - QTableWidgetItem *cb; - ui->twProps->setItem(r,0,cb=new QTableWidgetItem); - ui->twProps->setItem(r,2,new QTableWidgetItem); - ui->twProps->setItem(r,3,new QTableWidgetItem("...")); - if(din.length())ui->twProps->item(r,2)->setText(din); - cbx->setFlags(Qt::ItemFlag::ItemIsEnabled|Qt::ItemFlag::ItemIsSelectable); - cbx->setText(tr("Disconnected")); - ui->twProps->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeMode::ResizeToContents); - if(dn.length()) - { - cb->setText(dn); - cb->setFlags(cb->flags()|Qt::ItemFlag::ItemIsEditable); - std::vector dsv=CMidiPlayer::getInstance()->getMidiOutDevices(); - if(std::find(dsv.begin(),dsv.end(),dn.toStdString())==dsv.end()) - cb->setFlags(cb->flags()&(~Qt::ItemFlag::ItemIsEnabled)); - else cb->setFlags(cb->flags()|Qt::ItemFlag::ItemIsEnabled); - } + int r; + ui->twProps->insertRow(r = ui->twProps->rowCount()); + ui->twProps->setRowHeight(r, 32); + QTableWidgetItem *cbx = new QTableWidgetItem; + ui->twProps->setItem(r, 1, cbx); + QTableWidgetItem *cb; + ui->twProps->setItem(r, 0, cb = new QTableWidgetItem); + ui->twProps->setItem(r, 2, new QTableWidgetItem); + ui->twProps->setItem(r, 3, new QTableWidgetItem("...")); + if (din.length()) + ui->twProps->item(r, 2)->setText(din); + cbx->setFlags(Qt::ItemFlag::ItemIsEnabled | Qt::ItemFlag::ItemIsSelectable); + cbx->setText(tr("Disconnected")); + ui->twProps->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeMode::ResizeToContents); + if (dn.length()) + { + cb->setText(dn); + cb->setFlags(cb->flags() | Qt::ItemFlag::ItemIsEditable); + std::vector dsv = CMidiPlayer::getInstance()->getMidiOutDevices(); + if (std::find(dsv.begin(), dsv.end(), dn.toStdString()) == dsv.end()) + cb->setFlags(cb->flags() & (~Qt::ItemFlag::ItemIsEnabled)); + else cb->setFlags(cb->flags() | Qt::ItemFlag::ItemIsEnabled); + } } void qmpDevPropDialog::on_buttonBox_accepted() { - accept(); + accept(); } void qmpDevPropDialog::on_buttonBox_rejected() { - reject(); + reject(); } diff --git a/qmidiplayer-desktop/qmpdevpropdialog.hpp b/qmidiplayer-desktop/qmpdevpropdialog.hpp index e98aba9..eb69d81 100644 --- a/qmidiplayer-desktop/qmpdevpropdialog.hpp +++ b/qmidiplayer-desktop/qmpdevpropdialog.hpp @@ -3,32 +3,33 @@ #include -namespace Ui { +namespace Ui +{ class qmpDevPropDialog; } class qmpDevPropDialog : public QDialog { - Q_OBJECT + Q_OBJECT - public: - explicit qmpDevPropDialog(QWidget *parent = nullptr); - ~qmpDevPropDialog(); - void load(void* data); - void* save(); +public: + explicit qmpDevPropDialog(QWidget *parent = nullptr); + ~qmpDevPropDialog(); + void load(void *data); + void *save(); - private slots: - void on_pbAdd_clicked(); +private slots: + void on_pbAdd_clicked(); - void on_pbRemove_clicked(); + void on_pbRemove_clicked(); - void on_buttonBox_accepted(); + void on_buttonBox_accepted(); - void on_buttonBox_rejected(); + void on_buttonBox_rejected(); - private: - Ui::qmpDevPropDialog *ui; - void setupRow(const QString &dn="",const QString &din=""); +private: + Ui::qmpDevPropDialog *ui; + void setupRow(const QString &dn = QString(), const QString &din = QString()); }; #endif // QMPDEVPROPDIALOG_HPP diff --git a/qmidiplayer-desktop/qmpefxwindow.cpp b/qmidiplayer-desktop/qmpefxwindow.cpp index 7691756..ec1cef3 100644 --- a/qmidiplayer-desktop/qmpefxwindow.cpp +++ b/qmidiplayer-desktop/qmpefxwindow.cpp @@ -4,215 +4,296 @@ #include "qmpmainwindow.hpp" qmpEfxWindow::qmpEfxWindow(QWidget *parent) : - QWidget(parent,Qt::Dialog), - ui(new Ui::qmpEfxWindow) -{ - ui->setupUi(this);initialized=false; - styl=new QDialSkulptureStyle(); - QList dials=findChildren(); - for(int i=0;isetStyle(styl); - qmpSettings *settings=qmpMainWindow::getInstance()->getSettings(); - ui->cbEnabledC->setChecked(settings->getOptionRaw("Effects/ChorusEnabled",1).toInt()); - ui->cbEnabledR->setChecked(settings->getOptionRaw("Effects/ReverbEnabled",1).toInt()); - rr=settings->getOptionRaw("Effects/ReverbRoom",0.2).toDouble(); - rd=settings->getOptionRaw("Effects/ReverbDamp",0.0).toDouble(); - rw=settings->getOptionRaw("Effects/ReverbWidth",0.5).toDouble(); - rl=settings->getOptionRaw("Effects/ReverbLevel",0.9).toDouble(); - - cfb=settings->getOptionRaw("Effects/ChorusFeedbk",3).toInt(); - cl=settings->getOptionRaw("Effects/ChorusLevel",2.0).toDouble(); - cr=settings->getOptionRaw("Effects/ChorusRate",0.3).toDouble(); - cd=settings->getOptionRaw("Effects/ChorusDepth",8.0).toDouble(); - ct=settings->getOptionRaw("Effects/ChorusType",FLUID_CHORUS_MOD_SINE).toInt(); - qmpMainWindow::getInstance()->registerFunctionality( - efxf=new qmpEfxFunc(this), - std::string("Effects"), - tr("Effects").toStdString(), - getThemedIconc(":/img/effects.svg"), - 0, - true - ); - if(settings->getOptionRaw("DialogStatus/EfxW",QRect(-999,-999,999,999)).toRect()!=QRect(-999,-999,999,999)) - setGeometry(settings->getOptionRaw("DialogStatus/EfxW",QRect(-999,-999,999,999)).toRect()); - if(settings->getOptionRaw("DialogStatus/EfxWShown",0).toInt()) - {show();qmpMainWindow::getInstance()->setFuncState("Effects",true);} + QWidget(parent, Qt::Dialog), + ui(new Ui::qmpEfxWindow) +{ + ui->setupUi(this); + initialized = false; + styl = new QDialSkulptureStyle(); + QList dials = findChildren(); + for (int i = 0; i < dials.count(); ++i) + dials.at(i)->setStyle(styl); + qmpSettings *settings = qmpMainWindow::getInstance()->getSettings(); + ui->cbEnabledC->setChecked(settings->getOptionRaw("Effects/ChorusEnabled", 1).toInt()); + ui->cbEnabledR->setChecked(settings->getOptionRaw("Effects/ReverbEnabled", 1).toInt()); + rr = settings->getOptionRaw("Effects/ReverbRoom", 0.2).toDouble(); + rd = settings->getOptionRaw("Effects/ReverbDamp", 0.0).toDouble(); + rw = settings->getOptionRaw("Effects/ReverbWidth", 0.5).toDouble(); + rl = settings->getOptionRaw("Effects/ReverbLevel", 0.9).toDouble(); + + cfb = settings->getOptionRaw("Effects/ChorusFeedbk", 3).toInt(); + cl = settings->getOptionRaw("Effects/ChorusLevel", 2.0).toDouble(); + cr = settings->getOptionRaw("Effects/ChorusRate", 0.3).toDouble(); + cd = settings->getOptionRaw("Effects/ChorusDepth", 8.0).toDouble(); + ct = settings->getOptionRaw("Effects/ChorusType", FLUID_CHORUS_MOD_SINE).toInt(); + qmpMainWindow::getInstance()->registerFunctionality( + efxf = new qmpEfxFunc(this), + std::string("Effects"), + tr("Effects").toStdString(), + getThemedIconc(":/img/effects.svg"), + 0, + true + ); + if (settings->getOptionRaw("DialogStatus/EfxW", QRect(-999, -999, 999, 999)).toRect() != QRect(-999, -999, 999, 999)) + setGeometry(settings->getOptionRaw("DialogStatus/EfxW", QRect(-999, -999, 999, 999)).toRect()); + if (settings->getOptionRaw("DialogStatus/EfxWShown", 0).toInt()) + { + show(); + qmpMainWindow::getInstance()->setFuncState("Effects", true); + } } qmpEfxWindow::~qmpEfxWindow() { - qmpMainWindow::getInstance()->unregisterFunctionality("Effects"); - delete efxf; - delete styl; - delete ui; + qmpMainWindow::getInstance()->unregisterFunctionality("Effects"); + delete efxf; + delete styl; + delete ui; } void qmpEfxWindow::closeEvent(QCloseEvent *event) { - qmpSettings *settings=qmpMainWindow::getInstance()->getSettings(); - if(settings->getOptionBool("Behavior/DialogStatus")) - { - settings->setOptionRaw("DialogStatus/EfxW",geometry()); - } - setVisible(false); - if(!qmpMainWindow::getInstance()->isFinalizing()&&settings->getOptionBool("Behavior/DialogStatus")) - { - settings->setOptionRaw("DialogStatus/EfxWShown",0); - } - qmpMainWindow::getInstance()->setFuncState("Effects",false); - event->accept(); + qmpSettings *settings = qmpMainWindow::getInstance()->getSettings(); + if (settings->getOptionBool("Behavior/DialogStatus")) + { + settings->setOptionRaw("DialogStatus/EfxW", geometry()); + } + setVisible(false); + if (!qmpMainWindow::getInstance()->isFinalizing() && settings->getOptionBool("Behavior/DialogStatus")) + { + settings->setOptionRaw("DialogStatus/EfxWShown", 0); + } + qmpMainWindow::getInstance()->setFuncState("Effects", false); + event->accept(); } void qmpEfxWindow::showEvent(QShowEvent *event) { - //CMidiPlayer* player=qmpMainWindow::getInstance()->getPlayer(); - //These parameters will never be modified outside this window... - /*if(initialized) - { - player->getReverbPara(&rr,&rd,&rw,&rl); - player->getChorusPara(&cfb,&cl,&cr,&cd,&ct); - }*/ - ui->sbRoom->setValue((int)round(rr*100));ui->dRoom->setValue((int)round(rr*100)); - ui->sbDamp->setValue((int)round(rd*100));ui->dDamp->setValue((int)round(rd*100)); - ui->sbWidth->setValue((int)round(rw*100));ui->dWidth->setValue((int)round(rw*100)); - ui->sbLevelR->setValue((int)round(rl*100));ui->dLevelR->setValue((int)round(rl*100)); - - ui->sbFeedBack->setValue(cfb);ui->dFeedBack->setValue(cfb); - ui->sbRate->setValue(cr);ui->dRate->setValue((int)round(cr*100)); - ui->sbDepth->setValue(cd);ui->dDepth->setValue((int)round(cd*10)); - ui->sbLevelC->setValue((int)round(cl*100));ui->dLevelC->setValue((int)round(cl*100)); - if(ct==FLUID_CHORUS_MOD_SINE)ui->rbSine->setChecked(true),ui->rbTriangle->setChecked(false); - if(ct==FLUID_CHORUS_MOD_TRIANGLE)ui->rbSine->setChecked(false),ui->rbTriangle->setChecked(true); - initialized=true; - qmpSettings *settings=qmpMainWindow::getInstance()->getSettings(); - if(settings->getOptionRaw("DialogStatus/EfxW",QRect(-999,-999,999,999)).toRect()!=QRect(-999,-999,999,999)) - setGeometry(settings->getOptionRaw("DialogStatus/EfxW",QRect(-999,-999,999,999)).toRect()); - if(settings->getOptionBool("Behavior/DialogStatus")) - { - settings->setOptionRaw("DialogStatus/EfxWShown",1); - } - event->accept(); + //These parameters will never be modified outside this window... + /*if(initialized) + { + player->getReverbPara(&rr,&rd,&rw,&rl); + player->getChorusPara(&cfb,&cl,&cr,&cd,&ct); + }*/ + ui->sbRoom->setValue((int)round(rr * 100)); + ui->dRoom->setValue((int)round(rr * 100)); + ui->sbDamp->setValue((int)round(rd * 100)); + ui->dDamp->setValue((int)round(rd * 100)); + ui->sbWidth->setValue((int)round(rw * 100)); + ui->dWidth->setValue((int)round(rw * 100)); + ui->sbLevelR->setValue((int)round(rl * 100)); + ui->dLevelR->setValue((int)round(rl * 100)); + + ui->sbFeedBack->setValue(cfb); + ui->dFeedBack->setValue(cfb); + ui->sbRate->setValue(cr); + ui->dRate->setValue((int)round(cr * 100)); + ui->sbDepth->setValue(cd); + ui->dDepth->setValue((int)round(cd * 10)); + ui->sbLevelC->setValue((int)round(cl * 100)); + ui->dLevelC->setValue((int)round(cl * 100)); + if (ct == FLUID_CHORUS_MOD_SINE) + { + ui->rbSine->setChecked(true); + ui->rbTriangle->setChecked(false); + } + if (ct == FLUID_CHORUS_MOD_TRIANGLE) + { + ui->rbSine->setChecked(false); + ui->rbTriangle->setChecked(true); + } + initialized = true; + qmpSettings *settings = qmpMainWindow::getInstance()->getSettings(); + if (settings->getOptionRaw("DialogStatus/EfxW", QRect(-999, -999, 999, 999)).toRect() != QRect(-999, -999, 999, 999)) + setGeometry(settings->getOptionRaw("DialogStatus/EfxW", QRect(-999, -999, 999, 999)).toRect()); + if (settings->getOptionBool("Behavior/DialogStatus")) + { + settings->setOptionRaw("DialogStatus/EfxWShown", 1); + } + event->accept(); } void qmpEfxWindow::sendEfxChange(void *_fs) { - if(!qmpMainWindow::getInstance()||!initialized)return; - rr=ui->sbRoom->value()/100.;rd=ui->sbDamp->value()/100.; - rw=ui->sbWidth->value()/100.;rl=ui->sbLevelR->value()/100.; - ct=ui->rbSine->isChecked()?FLUID_CHORUS_MOD_SINE:FLUID_CHORUS_MOD_TRIANGLE; - cfb=ui->sbFeedBack->value();cl=ui->sbLevelC->value()/100.; - cr=ui->sbRate->value();cd=ui->sbDepth->value(); - IFluidSettings* fs=(IFluidSettings*)_fs; - if(!_fs)fs=qmpMainWindow::getInstance()->getFluid(); - fs->setReverbPara(ui->cbEnabledR->isChecked()?1:0,rr,rd,rw,rl); - fs->setChorusPara(ui->cbEnabledC->isChecked()?1:0,cfb,cl,cr,cd,ct); - - qmpSettings *settings=qmpMainWindow::getInstance()->getSettings(); - settings->setOptionRaw("Effects/ChorusEnabled",ui->cbEnabledC->isChecked()?1:0); - settings->setOptionRaw("Effects/ReverbEnabled",ui->cbEnabledR->isChecked()?1:0); - settings->setOptionRaw("Effects/ReverbRoom",rr); - settings->setOptionRaw("Effects/ReverbDamp",rd); - settings->setOptionRaw("Effects/ReverbWidth",rw); - settings->setOptionRaw("Effects/ReverbLevel",rl); - - settings->setOptionRaw("Effects/ChorusFeedbk",cfb); - settings->setOptionRaw("Effects/ChorusLevel",cl); - settings->setOptionRaw("Effects/ChorusRate",cr); - settings->setOptionRaw("Effects/ChorusDepth",cd); - settings->setOptionRaw("Effects/ChorusType",ct); + if (!qmpMainWindow::getInstance() || !initialized) + return; + rr = ui->sbRoom->value() / 100.; + rd = ui->sbDamp->value() / 100.; + rw = ui->sbWidth->value() / 100.; + rl = ui->sbLevelR->value() / 100.; + ct = ui->rbSine->isChecked() ? FLUID_CHORUS_MOD_SINE : FLUID_CHORUS_MOD_TRIANGLE; + cfb = ui->sbFeedBack->value(); + cl = ui->sbLevelC->value() / 100.; + cr = ui->sbRate->value(); + cd = ui->sbDepth->value(); + IFluidSettings *fs = (IFluidSettings *)_fs; + if (!_fs) + fs = qmpMainWindow::getInstance()->getFluid(); + fs->setReverbPara(ui->cbEnabledR->isChecked() ? 1 : 0, rr, rd, rw, rl); + fs->setChorusPara(ui->cbEnabledC->isChecked() ? 1 : 0, cfb, cl, cr, cd, ct); + + qmpSettings *settings = qmpMainWindow::getInstance()->getSettings(); + settings->setOptionRaw("Effects/ChorusEnabled", ui->cbEnabledC->isChecked() ? 1 : 0); + settings->setOptionRaw("Effects/ReverbEnabled", ui->cbEnabledR->isChecked() ? 1 : 0); + settings->setOptionRaw("Effects/ReverbRoom", rr); + settings->setOptionRaw("Effects/ReverbDamp", rd); + settings->setOptionRaw("Effects/ReverbWidth", rw); + settings->setOptionRaw("Effects/ReverbLevel", rl); + + settings->setOptionRaw("Effects/ChorusFeedbk", cfb); + settings->setOptionRaw("Effects/ChorusLevel", cl); + settings->setOptionRaw("Effects/ChorusRate", cr); + settings->setOptionRaw("Effects/ChorusDepth", cd); + settings->setOptionRaw("Effects/ChorusType", ct); } void qmpEfxWindow::dailValueChange() { - if(!initialized)return; - ui->sbRoom->setValue(ui->dRoom->value()); - ui->sbDamp->setValue(ui->dDamp->value()); - ui->sbWidth->setValue(ui->dWidth->value()); - ui->sbLevelR->setValue(ui->dLevelR->value()); - ui->sbFeedBack->setValue(ui->dFeedBack->value()); - ui->sbRate->setValue(ui->dRate->value()/100.); - ui->sbDepth->setValue(ui->dDepth->value()/10.); - ui->sbLevelC->setValue(ui->dLevelC->value()); - sendEfxChange(); + if (!initialized) + return; + ui->sbRoom->setValue(ui->dRoom->value()); + ui->sbDamp->setValue(ui->dDamp->value()); + ui->sbWidth->setValue(ui->dWidth->value()); + ui->sbLevelR->setValue(ui->dLevelR->value()); + ui->sbFeedBack->setValue(ui->dFeedBack->value()); + ui->sbRate->setValue(ui->dRate->value() / 100.); + ui->sbDepth->setValue(ui->dDepth->value() / 10.); + ui->sbLevelC->setValue(ui->dLevelC->value()); + sendEfxChange(); } void qmpEfxWindow::spinValueChange() { - if(!initialized)return; - ui->dRoom->setValue(ui->sbRoom->value()); - ui->dDamp->setValue(ui->sbDamp->value()); - ui->dWidth->setValue(ui->sbWidth->value()); - ui->dLevelR->setValue(ui->sbLevelR->value()); - ui->dFeedBack->setValue(ui->sbFeedBack->value()); - ui->dRate->setValue((int)(ui->sbRate->value()*100)); - ui->dDepth->setValue((int)(ui->sbDepth->value()*10)); - ui->dLevelC->setValue(ui->sbLevelC->value()); - sendEfxChange(); + if (!initialized) + return; + ui->dRoom->setValue(ui->sbRoom->value()); + ui->dDamp->setValue(ui->sbDamp->value()); + ui->dWidth->setValue(ui->sbWidth->value()); + ui->dLevelR->setValue(ui->sbLevelR->value()); + ui->dFeedBack->setValue(ui->sbFeedBack->value()); + ui->dRate->setValue((int)(ui->sbRate->value() * 100)); + ui->dDepth->setValue((int)(ui->sbDepth->value() * 10)); + ui->dLevelC->setValue(ui->sbLevelC->value()); + sendEfxChange(); } void qmpEfxWindow::on_dRoom_valueChanged() -{dailValueChange();} +{ + dailValueChange(); +} void qmpEfxWindow::on_dDamp_valueChanged() -{dailValueChange();} +{ + dailValueChange(); +} void qmpEfxWindow::on_dWidth_valueChanged() -{dailValueChange();} +{ + dailValueChange(); +} void qmpEfxWindow::on_dLevelR_valueChanged() -{dailValueChange();} +{ + dailValueChange(); +} void qmpEfxWindow::on_dFeedBack_valueChanged() -{dailValueChange();} +{ + dailValueChange(); +} void qmpEfxWindow::on_dRate_valueChanged() -{dailValueChange();} +{ + dailValueChange(); +} void qmpEfxWindow::on_dDepth_valueChanged() -{dailValueChange();} +{ + dailValueChange(); +} void qmpEfxWindow::on_dLevelC_valueChanged() -{dailValueChange();} +{ + dailValueChange(); +} void qmpEfxWindow::on_sbRoom_valueChanged(QString s) -{s=QString();spinValueChange();} +{ + s = QString(); + spinValueChange(); +} void qmpEfxWindow::on_sbDamp_valueChanged(QString s) -{s=QString();spinValueChange();} +{ + s = QString(); + spinValueChange(); +} void qmpEfxWindow::on_sbWidth_valueChanged(QString s) -{s=QString();spinValueChange();} +{ + s = QString(); + spinValueChange(); +} void qmpEfxWindow::on_sbLevelR_valueChanged(QString s) -{s=QString();spinValueChange();} +{ + s = QString(); + spinValueChange(); +} void qmpEfxWindow::on_sbFeedBack_valueChanged(QString s) -{s=QString();spinValueChange();} +{ + s = QString(); + spinValueChange(); +} void qmpEfxWindow::on_sbRate_valueChanged(QString s) -{s=QString();spinValueChange();} +{ + s = QString(); + spinValueChange(); +} void qmpEfxWindow::on_sbDepth_valueChanged(QString s) -{s=QString();spinValueChange();} +{ + s = QString(); + spinValueChange(); +} void qmpEfxWindow::on_sbLevelC_valueChanged(QString s) -{s=QString();spinValueChange();} +{ + s = QString(); + spinValueChange(); +} void qmpEfxWindow::on_cbEnabledC_stateChanged() -{sendEfxChange();} +{ + sendEfxChange(); +} void qmpEfxWindow::on_cbEnabledR_stateChanged() -{sendEfxChange();} +{ + sendEfxChange(); +} void qmpEfxWindow::on_rbSine_toggled() -{sendEfxChange();} +{ + sendEfxChange(); +} void qmpEfxWindow::on_rbTriangle_toggled() -{sendEfxChange();} +{ + sendEfxChange(); +} qmpEfxFunc::qmpEfxFunc(qmpEfxWindow *par) -{p=par;} +{ + p = par; +} void qmpEfxFunc::show() -{p->show();} +{ + p->show(); +} void qmpEfxFunc::close() -{p->close();} +{ + p->close(); +} diff --git a/qmidiplayer-desktop/qmpefxwindow.hpp b/qmidiplayer-desktop/qmpefxwindow.hpp index bacda1d..9e5e8bf 100644 --- a/qmidiplayer-desktop/qmpefxwindow.hpp +++ b/qmidiplayer-desktop/qmpefxwindow.hpp @@ -9,64 +9,65 @@ #include "qdialskulpturestyle.hpp" #include "../include/qmpcorepublic.hpp" -namespace Ui { - class qmpEfxWindow; +namespace Ui +{ +class qmpEfxWindow; } class qmpEfxWindow; -class qmpEfxFunc:public qmpFuncBaseIntf +class qmpEfxFunc : public qmpFuncBaseIntf { - private: - qmpEfxWindow *p; - public: - qmpEfxFunc(qmpEfxWindow *par); - void show(); - void close(); +private: + qmpEfxWindow *p; +public: + qmpEfxFunc(qmpEfxWindow *par); + void show(); + void close(); }; -class qmpEfxWindow:public QWidget +class qmpEfxWindow : public QWidget { - Q_OBJECT + Q_OBJECT - public: - explicit qmpEfxWindow(QWidget *parent=0); - ~qmpEfxWindow(); - void closeEvent(QCloseEvent *event); - void showEvent(QShowEvent *event); - void sendEfxChange(void *_fs=nullptr); +public: + explicit qmpEfxWindow(QWidget *parent = nullptr); + ~qmpEfxWindow(); + void closeEvent(QCloseEvent *event); + void showEvent(QShowEvent *event); + void sendEfxChange(void *_fs = nullptr); - private slots: - void on_dRoom_valueChanged(); - void on_dDamp_valueChanged(); - void on_dWidth_valueChanged(); - void on_dLevelR_valueChanged(); - void on_dFeedBack_valueChanged(); - void on_dRate_valueChanged(); - void on_dDepth_valueChanged(); - void on_dLevelC_valueChanged(); - void on_sbRoom_valueChanged(QString s); - void on_sbDamp_valueChanged(QString s); - void on_sbWidth_valueChanged(QString s); - void on_sbLevelR_valueChanged(QString s); - void on_sbFeedBack_valueChanged(QString s); - void on_sbRate_valueChanged(QString s); - void on_sbDepth_valueChanged(QString s); - void on_sbLevelC_valueChanged(QString s); - void on_cbEnabledC_stateChanged(); - void on_cbEnabledR_stateChanged(); - void on_rbSine_toggled(); - void on_rbTriangle_toggled(); +private slots: + void on_dRoom_valueChanged(); + void on_dDamp_valueChanged(); + void on_dWidth_valueChanged(); + void on_dLevelR_valueChanged(); + void on_dFeedBack_valueChanged(); + void on_dRate_valueChanged(); + void on_dDepth_valueChanged(); + void on_dLevelC_valueChanged(); + void on_sbRoom_valueChanged(QString s); + void on_sbDamp_valueChanged(QString s); + void on_sbWidth_valueChanged(QString s); + void on_sbLevelR_valueChanged(QString s); + void on_sbFeedBack_valueChanged(QString s); + void on_sbRate_valueChanged(QString s); + void on_sbDepth_valueChanged(QString s); + void on_sbLevelC_valueChanged(QString s); + void on_cbEnabledC_stateChanged(); + void on_cbEnabledR_stateChanged(); + void on_rbSine_toggled(); + void on_rbTriangle_toggled(); - private: - void dailValueChange(); - void spinValueChange(); - Ui::qmpEfxWindow *ui; - double rr,rd,rw,rl; - int cfb,ct,initialized; - double cl,cr,cd; - QCommonStyle* styl; - qmpEfxFunc *efxf; +private: + void dailValueChange(); + void spinValueChange(); + Ui::qmpEfxWindow *ui; + double rr, rd, rw, rl; + int cfb, ct, initialized; + double cl, cr, cd; + QCommonStyle *styl; + qmpEfxFunc *efxf; }; #endif // QMPEFXWINDOW_HPP diff --git a/qmidiplayer-desktop/qmphelpwindow.cpp b/qmidiplayer-desktop/qmphelpwindow.cpp index 4579e2c..082c2f6 100644 --- a/qmidiplayer-desktop/qmphelpwindow.cpp +++ b/qmidiplayer-desktop/qmphelpwindow.cpp @@ -2,43 +2,44 @@ #include "qmphelpwindow.hpp" #include "ui_qmphelpwindow.h" -static const char *months="JanFebMarAprMayJunJulAugSepOctNovDec"; +static const char *months = "JanFebMarAprMayJunJulAugSepOctNovDec"; std::string parseDate(const char *date) { - char ms[8]; - int y,d,m;sscanf(date,"%s %d %d",ms,&d,&y); - m=(strstr(months,ms)-months)/3+1; - char r[16]; - sprintf(r,"%04d-%02d-%02d",y,m,d); - return std::string(r); + char ms[8]; + int y, d, m; + sscanf(date, "%s %d %d", ms, &d, &y); + m = (strstr(months, ms) - months) / 3 + 1; + char r[16]; + sprintf(r, "%04d-%02d-%02d", y, m, d); + return std::string(r); } qmpHelpWindow::qmpHelpWindow(QWidget *parent) : - QDialog(parent), - ui(new Ui::qmpHelpWindow) + QDialog(parent), + ui(new Ui::qmpHelpWindow) { - ui->setupUi(this); - ui->textBrowser->setSearchPaths(QStringList(QString(":/doc"))+QStringList(QString(":/img"))); - ui->textBrowser->setSource(QUrl("qrc:///doc/index_internal.html")); + ui->setupUi(this); + ui->textBrowser->setSearchPaths(QStringList(QString(":/doc")) + QStringList(QString(":/img"))); + ui->textBrowser->setSource(QUrl("qrc:///doc/index_internal.html")); } qmpHelpWindow::~qmpHelpWindow() { - delete ui; + delete ui; } void qmpHelpWindow::on_textBrowser_sourceChanged(const QUrl &src) { - if(src.fileName()==QString("version_internal.html")) - { - QString s=ui->textBrowser->toHtml(); - s.replace("CT_QT_VERSION_STR",QT_VERSION_STR); - s.replace("RT_QT_VERSION_STR",qVersion()); - s.replace("CT_FLUIDSYNTH_VERSION",FLUIDSYNTH_VERSION); - s.replace("RT_FLUIDSYNTH_VERSION",fluid_version_str()); - s.replace("APP_VERSION",APP_VERSION); - s.replace("BUILD_DATE",parseDate(__DATE__).c_str()); - s.replace("BUILD_MACHINE",QT_STRINGIFY(BUILD_MACHINE)); - ui->textBrowser->setHtml(s); - } + if (src.fileName() == QString("version_internal.html")) + { + QString s = ui->textBrowser->toHtml(); + s.replace("CT_QT_VERSION_STR", QT_VERSION_STR); + s.replace("RT_QT_VERSION_STR", qVersion()); + s.replace("CT_FLUIDSYNTH_VERSION", FLUIDSYNTH_VERSION); + s.replace("RT_FLUIDSYNTH_VERSION", fluid_version_str()); + s.replace("APP_VERSION", APP_VERSION); + s.replace("BUILD_DATE", parseDate(__DATE__).c_str()); + s.replace("BUILD_MACHINE", QT_STRINGIFY(BUILD_MACHINE)); + ui->textBrowser->setHtml(s); + } } diff --git a/qmidiplayer-desktop/qmphelpwindow.hpp b/qmidiplayer-desktop/qmphelpwindow.hpp index a94da33..35824ed 100644 --- a/qmidiplayer-desktop/qmphelpwindow.hpp +++ b/qmidiplayer-desktop/qmphelpwindow.hpp @@ -6,23 +6,24 @@ #define BUILD_MACHINE UNKNOWN #endif -namespace Ui { - class qmpHelpWindow; +namespace Ui +{ +class qmpHelpWindow; } class qmpHelpWindow : public QDialog { - Q_OBJECT + Q_OBJECT - public: - explicit qmpHelpWindow(QWidget *parent = 0); - ~qmpHelpWindow(); +public: + explicit qmpHelpWindow(QWidget *parent = nullptr); + ~qmpHelpWindow(); - private slots: - void on_textBrowser_sourceChanged(const QUrl &src); +private slots: + void on_textBrowser_sourceChanged(const QUrl &src); - private: - Ui::qmpHelpWindow *ui; +private: + Ui::qmpHelpWindow *ui; }; #endif // QMPHELPWINDOW_H diff --git a/qmidiplayer-desktop/qmpinfowindow.cpp b/qmidiplayer-desktop/qmpinfowindow.cpp index c0b8892..654c8f4 100644 --- a/qmidiplayer-desktop/qmpinfowindow.cpp +++ b/qmidiplayer-desktop/qmpinfowindow.cpp @@ -4,84 +4,95 @@ #include "qmpmainwindow.hpp" #include "qmpsettingswindow.hpp" -const char* minors="abebbbf c g d a e b f#c#g#d#a#"; -const char* majors="CbGbDbAbEbBbF C G D A E B F#C#"; -const char* standards="? GM GM2GS XG "; +const char *minors = "abebbbf c g d a e b f#c#g#d#a#"; +const char *majors = "CbGbDbAbEbBbF C G D A E B F#C#"; +const char *standards = "? GM GM2GS XG "; qmpInfoWindow::qmpInfoWindow(QWidget *parent) : - QDialog(parent), - ui(new Ui::qmpInfoWindow) + QDialog(parent), + ui(new Ui::qmpInfoWindow) { - ui->setupUi(this); - qmpMainWindow::getInstance()->registerFunctionality( - infof=new qmpInfoFunc(this), - std::string("FileInfo"), - tr("File Information").toStdString(), - getThemedIconc(":/img/info.svg"), - 0, - true - ); + ui->setupUi(this); + qmpMainWindow::getInstance()->registerFunctionality( + infof = new qmpInfoFunc(this), + std::string("FileInfo"), + tr("File Information").toStdString(), + getThemedIconc(":/img/info.svg"), + 0, + true + ); } qmpInfoWindow::~qmpInfoWindow() { - qmpMainWindow::getInstance()->unregisterFunctionality("FileInfo"); - delete infof; - delete ui; + qmpMainWindow::getInstance()->unregisterFunctionality("FileInfo"); + delete infof; + delete ui; } void qmpInfoWindow::closeEvent(QCloseEvent *e) { - setVisible(false); - qmpMainWindow::getInstance()->setFuncState("FileInfo",false); - e->accept(); + setVisible(false); + qmpMainWindow::getInstance()->setFuncState("FileInfo", false); + e->accept(); } void qmpInfoWindow::hideEvent(QHideEvent *e) { - qmpMainWindow::getInstance()->setFuncState("FileInfo",false); - e->accept(); + qmpMainWindow::getInstance()->setFuncState("FileInfo", false); + e->accept(); } void qmpInfoWindow::updateInfo() { - char str[256]; - CMidiPlayer* player=qmpMainWindow::getInstance()->getPlayer(); - std::string textencoding=qmpMainWindow::getInstance()->getSettings()->getOptionEnumIntOptName("Midi/TextEncoding"); - ui->lbFileName->setText(QString("File name: ")+qmpMainWindow::getInstance()->getFileName()); - if(player->getTitle()) - { - if(textencoding!="Unicode") - ui->lbTitle->setText(QString("Title: ")+ - QTextCodec::codecForName(textencoding.c_str())->toUnicode(player->getTitle())); - else - ui->lbTitle->setText(QString("Title: ")+player->getTitle()); - } - else ui->lbTitle->setText(QString("Title: ")); - if(player->getCopyright()) - { - if(textencoding!="Unicode") - ui->lbCopyright->setText(QString("Copyright: ")+ - QTextCodec::codecForName(textencoding.c_str())->toUnicode(player->getCopyright())); - else - ui->lbCopyright->setText(QString("Copyright: ")+player->getCopyright()); - } - else ui->lbCopyright->setText(QString("Copyright: ")); - ui->lbTempo->setText(QString("Tempo: ")+QString::number(player->getTempo(),'g',5)); - int t,r;t=player->getCurrentKeySignature();r=(int8_t)((t>>8)&0xFF)+7; - strncpy(str,t&0xFF?minors+2*r:majors+2*r,2);str[2]='\0'; - ui->lbKeySig->setText(QString("Key Sig.: ")+str); - player->getCurrentTimeSignature(&t,&r);sprintf(str,"Time Sig.: %d/%d",t,r); - ui->lbTimeSig->setText(str); - sprintf(str,"Note count: %u",player->getFileNoteCount()); - ui->lbNoteCount->setText(str); - strncpy(str,standards+player->getFileStandard()*3,3);str[3]='\0'; - ui->lbFileStandard->setText(QString("File standard: ")+str); + char str[256]; + CMidiPlayer *player = qmpMainWindow::getInstance()->getPlayer(); + std::string textencoding = qmpMainWindow::getInstance()->getSettings()->getOptionEnumIntOptName("Midi/TextEncoding"); + ui->lbFileName->setText(QString("File name: ") + qmpMainWindow::getInstance()->getFileName()); + if (player->getTitle()) + { + if (textencoding != "Unicode") + ui->lbTitle->setText(QString("Title: ") + + QTextCodec::codecForName(textencoding.c_str())->toUnicode(player->getTitle())); + else + ui->lbTitle->setText(QString("Title: ") + player->getTitle()); + } + else ui->lbTitle->setText(QString("Title: ")); + if (player->getCopyright()) + { + if (textencoding != "Unicode") + ui->lbCopyright->setText(QString("Copyright: ") + + QTextCodec::codecForName(textencoding.c_str())->toUnicode(player->getCopyright())); + else + ui->lbCopyright->setText(QString("Copyright: ") + player->getCopyright()); + } + else ui->lbCopyright->setText(QString("Copyright: ")); + ui->lbTempo->setText(QString("Tempo: ") + QString::number(player->getTempo(), 'g', 5)); + int t, r; + t = player->getCurrentKeySignature(); + r = (int8_t)((t >> 8) & 0xFF) + 7; + strncpy(str, t & 0xFF ? minors + 2 * r : majors + 2 * r, 2); + str[2] = '\0'; + ui->lbKeySig->setText(QString("Key Sig.: ") + str); + player->getCurrentTimeSignature(&t, &r); + sprintf(str, "Time Sig.: %d/%d", t, r); + ui->lbTimeSig->setText(str); + sprintf(str, "Note count: %u", player->getFileNoteCount()); + ui->lbNoteCount->setText(str); + strncpy(str, standards + player->getFileStandard() * 3, 3); + str[3] = '\0'; + ui->lbFileStandard->setText(QString("File standard: ") + str); } qmpInfoFunc::qmpInfoFunc(qmpInfoWindow *par) -{p=par;} +{ + p = par; +} void qmpInfoFunc::show() -{p->show();} +{ + p->show(); +} void qmpInfoFunc::close() -{p->close();} +{ + p->close(); +} diff --git a/qmidiplayer-desktop/qmpinfowindow.hpp b/qmidiplayer-desktop/qmpinfowindow.hpp index 6a179af..7e09b8a 100644 --- a/qmidiplayer-desktop/qmpinfowindow.hpp +++ b/qmidiplayer-desktop/qmpinfowindow.hpp @@ -10,50 +10,51 @@ #include #include "../include/qmpcorepublic.hpp" -namespace Ui { - class qmpInfoWindow; +namespace Ui +{ +class qmpInfoWindow; } class QClickableLabel : public QLabel { - Q_OBJECT - public: - explicit QClickableLabel(QWidget *parent=0):QLabel(parent){} - protected: - void mousePressEvent(QMouseEvent *e) - { - QLabel::mousePressEvent(e); - if(e->buttons()&Qt::LeftButton) - QApplication::clipboard()->setText(text()); - } + Q_OBJECT +public: + explicit QClickableLabel(QWidget *parent = nullptr) : QLabel(parent) {} +protected: + void mousePressEvent(QMouseEvent *e) + { + QLabel::mousePressEvent(e); + if (e->buttons() & Qt::LeftButton) + QApplication::clipboard()->setText(text()); + } }; class qmpInfoWindow; -class qmpInfoFunc:public qmpFuncBaseIntf +class qmpInfoFunc : public qmpFuncBaseIntf { - private: - qmpInfoWindow *p; - public: - qmpInfoFunc(qmpInfoWindow *par); - void show(); - void close(); +private: + qmpInfoWindow *p; +public: + qmpInfoFunc(qmpInfoWindow *par); + void show(); + void close(); }; class qmpInfoWindow : public QDialog { - Q_OBJECT - - public: - explicit qmpInfoWindow(QWidget *parent = 0); - ~qmpInfoWindow(); - void closeEvent(QCloseEvent *e); - void hideEvent(QHideEvent *e); - public slots: - void updateInfo(); - - private: - Ui::qmpInfoWindow *ui; - qmpInfoFunc *infof; + Q_OBJECT + +public: + explicit qmpInfoWindow(QWidget *parent = nullptr); + ~qmpInfoWindow(); + void closeEvent(QCloseEvent *e); + void hideEvent(QHideEvent *e); +public slots: + void updateInfo(); + +private: + Ui::qmpInfoWindow *ui; + qmpInfoFunc *infof; }; #endif // QMPINFOWINDOW_HPP diff --git a/qmidiplayer-desktop/qmpmainwindow.cpp b/qmidiplayer-desktop/qmpmainwindow.cpp index ea90493..98378aa 100644 --- a/qmidiplayer-desktop/qmpmainwindow.cpp +++ b/qmidiplayer-desktop/qmpmainwindow.cpp @@ -16,797 +16,938 @@ #define setButtonWidth(x,h) {x->setMaximumWidth(h*(logicalDpiY()/96.));x->setMinimumWidth(h*(logicalDpiY()/96.));} #ifdef _WIN32 #include -char* wcsto8bit(const wchar_t* s) +char *wcsto8bit(const wchar_t *s) { - int size=WideCharToMultiByte(CP_OEMCP,WC_NO_BEST_FIT_CHARS,s,-1,0,0,0,0); - char* c=(char*)calloc(size,sizeof(char)); - WideCharToMultiByte(CP_OEMCP,WC_NO_BEST_FIT_CHARS,s,-1,c,size,0,0); - return c; + int size = WideCharToMultiByte(CP_OEMCP, WC_NO_BEST_FIT_CHARS, s, -1, 0, 0, 0, 0); + char *c = (char *)calloc(size, sizeof(char)); + WideCharToMultiByte(CP_OEMCP, WC_NO_BEST_FIT_CHARS, s, -1, c, size, 0, 0); + return c; } #endif #define UPDATE_INTERVAL 66 -qmpMainWindow* qmpMainWindow::ref=nullptr; - -qmpMainWindow::qmpMainWindow(QCommandLineParser *_clp,QWidget *parent): - QMainWindow(parent), - ui(new Ui::qmpMainWindow), - clp(_clp) -{ - ui->setupUi(this); - ui->lbCurPoly->setText("00000");ui->lbMaxPoly->setText("00000"); - ui->lbFileName->setText("");ref=this;ui->verticalLayout->setAlignment(ui->pushButton,Qt::AlignRight); - setButtonHeight(ui->pbNext,36);setButtonHeight(ui->pbPlayPause,36);setButtonHeight(ui->pbAdd,36); - setButtonHeight(ui->pbPrev,36);setButtonHeight(ui->pbSettings,36);setButtonHeight(ui->pbStop,36); - playing=false;stopped=true;dragging=false;fin=false; - settings.reset(new qmpSettings()); - settingsw=new qmpSettingsWindow(settings.get(),this); - player=nullptr;timer=nullptr;fluidrenderer=nullptr; +qmpMainWindow *qmpMainWindow::ref = nullptr; + +qmpMainWindow::qmpMainWindow(QCommandLineParser *_clp, QWidget *parent): + QMainWindow(parent), + ui(new Ui::qmpMainWindow), + clp(_clp) +{ + ui->setupUi(this); + ui->lbCurPoly->setText("00000"); + ui->lbMaxPoly->setText("00000"); + ui->lbFileName->setText(""); + ref = this; + ui->verticalLayout->setAlignment(ui->pushButton, Qt::AlignRight); + setButtonHeight(ui->pbNext, 36); + setButtonHeight(ui->pbPlayPause, 36); + setButtonHeight(ui->pbAdd, 36); + setButtonHeight(ui->pbPrev, 36); + setButtonHeight(ui->pbSettings, 36); + setButtonHeight(ui->pbStop, 36); + playing = false; + stopped = true; + dragging = false; + fin = false; + settings.reset(new qmpSettings()); + settingsw = new qmpSettingsWindow(settings.get(), this); + player = nullptr; + timer = nullptr; + fluidrenderer = nullptr; } qmpMainWindow::~qmpMainWindow() { - QLista=ui->lbFileName->actions(); - for(unsigned i=0;ilbFileName->removeAction(a[i]); - delete a[i]; - } - pmgr->deinitPlugins(); - auto rtdev=qmpRtMidiManager::getDevices(); - for(auto &i:rtdev)player->unregisterMidiOutDevice(i.second); - delete pmgr; - if(timer)delete timer; - delete helpw;helpw=nullptr; - delete efxw;efxw=nullptr; - delete chnlw;chnlw=nullptr; - delete plistw;plistw=nullptr; - delete infow;infow=nullptr; - delete settingsw;settingsw=nullptr; - delete panicf;panicf=nullptr; - delete renderf;renderf=nullptr; - delete reloadsynf;reloadsynf=nullptr; - if(player)delete player; - internalfluid->deviceDeinit(); - delete internalfluid; - delete ui; + QLista = ui->lbFileName->actions(); + for (unsigned i = 0; i < a.size(); ++i) + { + ui->lbFileName->removeAction(a[i]); + delete a[i]; + } + pmgr->deinitPlugins(); + auto rtdev = qmpRtMidiManager::getDevices(); + for (auto &i : rtdev) + player->unregisterMidiOutDevice(i.second); + delete pmgr; + if (timer) + delete timer; + delete helpw; + helpw = nullptr; + delete efxw; + efxw = nullptr; + delete chnlw; + chnlw = nullptr; + delete plistw; + plistw = nullptr; + delete infow; + infow = nullptr; + delete settingsw; + settingsw = nullptr; + delete panicf; + panicf = nullptr; + delete renderf; + renderf = nullptr; + delete reloadsynf; + reloadsynf = nullptr; + if (player) + delete player; + internalfluid->deviceDeinit(); + delete internalfluid; + delete ui; } void qmpMainWindow::init() { - show(); - ui->centralWidget->setEnabled(false); - - pmgr=new qmpPluginManager(); - registerMidiOptions(); - - std::future f=std::async(std::launch::async, - [this] - { - player=new CMidiPlayer(); - internalfluid=new qmpMidiOutFluid(); - player->registerMidiOutDevice(internalfluid,"Internal FluidSynth"); - reloadsynf=new qmpReloadSynthFunc(this); - - internalfluid->registerOptions(pmgr->pluginAPI); - playerSetup(internalfluid); - internalfluid->deviceInit(); - loadSoundFont(internalfluid); - for(int i=0;i<16;++i) - player->setChannelOutput(i,0); - - auto rtdev=qmpRtMidiManager::getDevices(); - for(auto &i:rtdev) - player->registerMidiOutDevice(i.first,i.second); - } - ); - while(f.wait_for(std::chrono::milliseconds(100))==std::future_status::timeout) - QApplication::processEvents(); - ui->centralWidget->setEnabled(true); - - settingsw->registerSoundFontOption(); - registerBehaviorOptions(); - settingsw->registerCustomizeWidgetOptions(); - - plistw=new qmpPlistWindow(this); - chnlw=new qmpChannelsWindow(this); - efxw=new qmpEfxWindow(this); - infow=new qmpInfoWindow(this); - helpw=new qmpHelpWindow(this); - timer=new QTimer(this); - renderf=new qmpRenderFunc(this); - panicf=new qmpPanicFunc(this); - if(argfiles.size()) - { - plistw->emptyList(); - for(auto&i:argfiles)plistw->insertItem(i); - } - - if(settings->getOptionBool("Behavior/DialogStatus")) - { - QRect g=settings->getOptionRaw("DialogStatus/MainW",QRect(-999,-999,999,999)).toRect(); - if(g!=QRect(-999,-999,999,999))setGeometry(g); - } - - registerFunctionality(renderf,"Render",tr("Render to wave").toStdString(),getThemedIconc(":/img/render.svg"),0,false); - registerFunctionality(panicf,"Panic",tr("Panic").toStdString(),getThemedIconc(":/img/panic.svg"),0,false); - registerFunctionality(reloadsynf,"ReloadSynth",tr("Restart fluidsynth").toStdString(),getThemedIconc(":/img/repeat-base.svg"),0,false); - const QStringList &qpp=clp->values("plugin"); - std::vector pp; - for(auto s:qpp) - pp.push_back(s.toStdString()); - pmgr->scanPlugins(pp); - settingsw->registerPluginOption(pmgr); - settingsw->updatePluginList(pmgr); - pmgr->initPlugins(); - - settingsw->registerExtraMidiOptions(); - - QVariant* dinif_v=static_cast(settings->getOptionCustom("Midi/DeviceInitializationFiles")); - QList devinif_list=dinif_v->toList(); - delete dinif_v; - QMap devinif_map; - for(auto &i:devinif_list) - { - QPair p=i.value>(); - devinif_map[p.first]=p.second; - } - auto rtdev=qmpRtMidiManager::getDevices(); - for(auto &i:rtdev) - { - if(devinif_map.contains(QString(i.second.c_str()))) - i.first->setInitializerFile(devinif_map[QString(i.second.c_str())].toStdString().c_str()); - } - chnlw->selectDefaultDevice(); - - ui->vsMasterVol->setValue(settings->getOptionRaw("FluidSynth/Gain",50).toInt()); - connect(timer,&QTimer::timeout,this,&qmpMainWindow::updateWidgets); - connect(timer,&QTimer::timeout,infow,&qmpInfoWindow::updateInfo); - ui->pbNext->setIcon(QIcon(getThemedIcon(":/img/next.svg"))); - ui->pbPrev->setIcon(QIcon(getThemedIcon(":/img/prev.svg"))); - ui->pbPlayPause->setIcon(QIcon(getThemedIcon(":/img/play.svg"))); - ui->pbStop->setIcon(QIcon(getThemedIcon(":/img/stop.svg"))); - ui->pbSettings->setIcon(QIcon(getThemedIcon(":/img/settings.svg"))); - ui->pbAdd->setIcon(QIcon(getThemedIcon(":/img/open.svg"))); - if(argfiles.size())on_pbPlayPause_clicked(); - setupWidget();settingsw->postInit(); + show(); + ui->centralWidget->setEnabled(false); + + pmgr = new qmpPluginManager(); + registerMidiOptions(); + + std::future f = std::async(std::launch::async, [this] + { + player = new CMidiPlayer(); + internalfluid = new qmpMidiOutFluid(); + player->registerMidiOutDevice(internalfluid, "Internal FluidSynth"); + reloadsynf = new qmpReloadSynthFunc(this); + + internalfluid->registerOptions(pmgr->pluginAPI); + playerSetup(internalfluid); + internalfluid->deviceInit(); + loadSoundFont(internalfluid); + for (int i = 0; i < 16; ++i) + player->setChannelOutput(i, 0); + + auto rtdev = qmpRtMidiManager::getDevices(); + for (auto &i : rtdev) + player->registerMidiOutDevice(i.first, i.second); + }); + while (f.wait_for(std::chrono::milliseconds(100)) == std::future_status::timeout) + QApplication::processEvents(); + ui->centralWidget->setEnabled(true); + + settingsw->registerSoundFontOption(); + registerBehaviorOptions(); + settingsw->registerCustomizeWidgetOptions(); + + plistw = new qmpPlistWindow(this); + chnlw = new qmpChannelsWindow(this); + efxw = new qmpEfxWindow(this); + infow = new qmpInfoWindow(this); + helpw = new qmpHelpWindow(this); + timer = new QTimer(this); + renderf = new qmpRenderFunc(this); + panicf = new qmpPanicFunc(this); + if (argfiles.size()) + { + plistw->emptyList(); + for (auto &i : argfiles) + plistw->insertItem(i); + } + + if (settings->getOptionBool("Behavior/DialogStatus")) + { + QRect g = settings->getOptionRaw("DialogStatus/MainW", QRect(-999, -999, 999, 999)).toRect(); + if (g != QRect(-999, -999, 999, 999)) + setGeometry(g); + } + + registerFunctionality(renderf, "Render", tr("Render to wave").toStdString(), getThemedIconc(":/img/render.svg"), 0, false); + registerFunctionality(panicf, "Panic", tr("Panic").toStdString(), getThemedIconc(":/img/panic.svg"), 0, false); + registerFunctionality(reloadsynf, "ReloadSynth", tr("Restart fluidsynth").toStdString(), getThemedIconc(":/img/repeat-base.svg"), 0, false); + const QStringList &qpp = clp->values("plugin"); + std::vector pp; + for (auto &s : qpp) + pp.push_back(s.toStdString()); + pmgr->scanPlugins(pp); + settingsw->registerPluginOption(pmgr); + settingsw->updatePluginList(pmgr); + pmgr->initPlugins(); + + settingsw->registerExtraMidiOptions(); + + QVariant *dinif_v = static_cast(settings->getOptionCustom("Midi/DeviceInitializationFiles")); + QList devinif_list = dinif_v->toList(); + delete dinif_v; + QMap devinif_map; + for (auto &i : devinif_list) + { + QPair p = i.value>(); + devinif_map[p.first] = p.second; + } + auto rtdev = qmpRtMidiManager::getDevices(); + for (auto &i : rtdev) + { + if (devinif_map.contains(QString(i.second.c_str()))) + i.first->setInitializerFile(devinif_map[QString(i.second.c_str())].toStdString().c_str()); + } + chnlw->selectDefaultDevice(); + + ui->vsMasterVol->setValue(settings->getOptionRaw("FluidSynth/Gain", 50).toInt()); + connect(timer, &QTimer::timeout, this, &qmpMainWindow::updateWidgets); + connect(timer, &QTimer::timeout, infow, &qmpInfoWindow::updateInfo); + ui->pbNext->setIcon(QIcon(getThemedIcon(":/img/next.svg"))); + ui->pbPrev->setIcon(QIcon(getThemedIcon(":/img/prev.svg"))); + ui->pbPlayPause->setIcon(QIcon(getThemedIcon(":/img/play.svg"))); + ui->pbStop->setIcon(QIcon(getThemedIcon(":/img/stop.svg"))); + ui->pbSettings->setIcon(QIcon(getThemedIcon(":/img/settings.svg"))); + ui->pbAdd->setIcon(QIcon(getThemedIcon(":/img/open.svg"))); + if (argfiles.size()) + on_pbPlayPause_clicked(); + setupWidget(); + settingsw->postInit(); } int qmpMainWindow::parseArgs() { - bool loadfolder=clp->isSet("load-all-files"); - const QStringList &args=clp->positionalArguments(); - for(int i=0;igetOptionBool("Behavior/LoadFolder")) - { - QDirIterator di(QFileInfo(args.at(i)).absolutePath()); - while(di.hasNext()) - { - QString c=di.next(); - argfiles.push_back(c); - } - } - else - argfiles.push_back(args.at(i)); - } - } - return 0; + bool loadfolder = clp->isSet("load-all-files"); + const QStringList &args = clp->positionalArguments(); + for (int i = 0; i < args.size(); ++i) + { + if (QFileInfo(args.at(i)).exists()) + { + if (loadfolder || settings->getOptionBool("Behavior/LoadFolder")) + { + QDirIterator di(QFileInfo(args.at(i)).absolutePath()); + while (di.hasNext()) + { + QString c = di.next(); + argfiles.push_back(c); + } + } + else + argfiles.push_back(args.at(i)); + } + } + return 0; } void qmpMainWindow::closeEvent(QCloseEvent *event) { - if(settings->getOptionBool("Behavior/DialogStatus")) - { - settings->setOptionRaw("DialogStatus/MainW",geometry()); - } - on_pbStop_clicked();fin=true; - for(auto i=mfunc.begin();i!=mfunc.end();++i) - { - i->second.i()->close(); - i->second.setAssignedControl((QReflectiveAction*)nullptr), - i->second.setAssignedControl((QReflectivePushButton*)nullptr); - } - efxw->close();chnlw->close(); - plistw->close();infow->close(); - settingsw->close(); - event->accept(); + if (settings->getOptionBool("Behavior/DialogStatus")) + { + settings->setOptionRaw("DialogStatus/MainW", geometry()); + } + on_pbStop_clicked(); + fin = true; + for (auto i = mfunc.begin(); i != mfunc.end(); ++i) + { + i->second.i()->close(); + i->second.setAssignedControl((QReflectiveAction *)nullptr), + i->second.setAssignedControl((QReflectivePushButton *)nullptr); + } + efxw->close(); + chnlw->close(); + plistw->close(); + infow->close(); + settingsw->close(); + event->accept(); } void qmpMainWindow::dropEvent(QDropEvent *event) { - QList l=event->mimeData()->urls(); - QStringList sl; - for(int i=0;iinsertItems(sl); - switchTrack(plistw->getLastItem()); + QList l = event->mimeData()->urls(); + QStringList sl; + for (int i = 0; i < l.size(); ++i) + sl.push_back(l.at(i).toLocalFile()); + plistw->insertItems(sl); + switchTrack(plistw->getLastItem()); } void qmpMainWindow::dragEnterEvent(QDragEnterEvent *event) { - //if(event->mimeData()->hasFormat("application/x-midi")) - event->acceptProposedAction(); + //if(event->mimeData()->hasFormat("application/x-midi")) + event->acceptProposedAction(); } void qmpMainWindow::updateWidgets() { - setFuncEnabled("Render",stopped);setFuncEnabled("ReloadSynth",stopped); - if(player->isFinished()&&playerTh) - { - if(!plistw->getRepeat()) - { - timer->stop();stopped=true;playing=false; - invokeCallback("main.stop",nullptr); - setFuncEnabled("Render",stopped);setFuncEnabled("ReloadSynth",stopped); - player->playerDeinit(); - auto f=std::async([this]{playerTh->join();}); - while(f.wait_for(std::chrono::milliseconds(100))==std::future_status::timeout) - { - QApplication::processEvents(); - ui->lbCurPoly->setText(QString("%1").arg(internalfluid->getPolyphone(),5,10,QChar('0'))); - ui->lbMaxPoly->setText(QString("%1").arg(internalfluid->getMaxPolyphone(),5,10,QChar('0'))); - } - delete playerTh;playerTh=nullptr; - player->playerPanic(true); - chnlw->on_pbUnmute_clicked();chnlw->on_pbUnsolo_clicked(); - ui->pbPlayPause->setIcon(QIcon(getThemedIcon(":/img/play.svg"))); - ui->hsTimer->setValue(0); - ui->lbCurPoly->setText("00000");ui->lbMaxPoly->setText("00000"); - ui->lbCurTime->setText("00:00"); - } - else - switchTrack(plistw->getNextItem(),false); - } - if(renderTh) - { - if(fluidrenderer->isFinished()) - { - renderTh->join();timer->stop(); - ui->centralWidget->setEnabled(true); - delete renderTh;renderTh=nullptr; - fluidrenderer->renderDeinit(); - delete fluidrenderer;fluidrenderer=nullptr; - } - } - while(!player->isFinished()&&player->getTCeptr()>player->getStamp(ui->hsTimer->value()) - &&ui->hsTimer->value()<100&&!dragging) - ui->hsTimer->setValue(ui->hsTimer->value()+1); - if(playing) - { - std::chrono::duration elapsed= - std::chrono::duration_cast>(std::chrono::steady_clock::now()-st); - char ts[100]; - sprintf(ts,"%02d:%02d",(int)(elapsed.count()+offset)/60,(int)(elapsed.count()+offset)%60); - ui->lbCurTime->setText(ts); - ui->lbCurPoly->setText(QString("%1").arg(internalfluid->getPolyphone(),5,10,QChar('0'))); - ui->lbMaxPoly->setText(QString("%1").arg(internalfluid->getMaxPolyphone(),5,10,QChar('0'))); - } -} - -QString qmpMainWindow::getFileName(){return ui->lbFileName->text();} -void qmpMainWindow::switchTrack(QString s,bool interrupt) -{ - stopped=false;playing=true; - setFuncEnabled("Render",stopped);setFuncEnabled("ReloadSynth",stopped); - ui->pbPlayPause->setIcon(QIcon(getThemedIcon(":/img/pause.svg"))); - if(interrupt) - { - player->playerDeinit(); - player->playerPanic(); - } - invokeCallback("main.stop",nullptr); - if(playerTh) - { - auto f=std::async([this]{playerTh->join();}); - while(f.wait_for(std::chrono::milliseconds(100))==std::future_status::timeout) - { - QApplication::processEvents(); - ui->lbCurPoly->setText(QString("%1").arg(internalfluid->getPolyphone(),5,10,QChar('0'))); - ui->lbMaxPoly->setText(QString("%1").arg(internalfluid->getMaxPolyphone(),5,10,QChar('0'))); - } - delete playerTh;playerTh=nullptr; - } - timer->stop(); - player->playerPanic(true); - ui->hsTimer->setValue(0); - chnlw->on_pbUnmute_clicked();chnlw->on_pbUnsolo_clicked(); - QString fns=s;setWindowTitle(QUrl::fromLocalFile(fns).fileName().left(QUrl::fromLocalFile(fns).fileName().lastIndexOf('.'))+" - QMidiPlayer"); - ui->lbFileName->setText(QUrl::fromLocalFile(fns).fileName().left(QUrl::fromLocalFile(fns).fileName().lastIndexOf('.'))); - onfnChanged(); - if(!loadFile(fns))return; - char ts[100]; - sprintf(ts,"%02d:%02d",(int)player->getFtime()/60,(int)player->getFtime()%60); - ui->lbFinTime->setText(ts); - player->playerInit(); - invokeCallback("main.start",nullptr); - internalfluid->setGain(ui->vsMasterVol->value()/250.);efxw->sendEfxChange(); - playerTh=new std::thread([this]{ - player->playerThread(); - if(settings->getOptionBool("Midi/WaitVoice")&&player->isFinished()) - while(internalfluid->getPolyphone()>0) - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - }); + setFuncEnabled("Render", stopped); + setFuncEnabled("ReloadSynth", stopped); + if (player->isFinished() && playerTh) + { + if (!plistw->getRepeat()) + { + timer->stop(); + stopped = true; + playing = false; + invokeCallback("main.stop", nullptr); + setFuncEnabled("Render", stopped); + setFuncEnabled("ReloadSynth", stopped); + player->playerDeinit(); + auto f = std::async([this] {playerTh->join();}); + while (f.wait_for(std::chrono::milliseconds(100)) == std::future_status::timeout) + { + QApplication::processEvents(); + ui->lbCurPoly->setText(QString("%1").arg(internalfluid->getPolyphone(), 5, 10, QChar('0'))); + ui->lbMaxPoly->setText(QString("%1").arg(internalfluid->getMaxPolyphone(), 5, 10, QChar('0'))); + } + delete playerTh; + playerTh = nullptr; + player->playerPanic(true); + chnlw->on_pbUnmute_clicked(); + chnlw->on_pbUnsolo_clicked(); + ui->pbPlayPause->setIcon(QIcon(getThemedIcon(":/img/play.svg"))); + ui->hsTimer->setValue(0); + ui->lbCurPoly->setText("00000"); + ui->lbMaxPoly->setText("00000"); + ui->lbCurTime->setText("00:00"); + } + else + switchTrack(plistw->getNextItem(), false); + } + if (renderTh) + { + if (fluidrenderer->isFinished()) + { + renderTh->join(); + timer->stop(); + ui->centralWidget->setEnabled(true); + delete renderTh; + renderTh = nullptr; + fluidrenderer->renderDeinit(); + delete fluidrenderer; + fluidrenderer = nullptr; + } + } + while (!player->isFinished() && player->getTCeptr() > player->getStamp(ui->hsTimer->value()) + && ui->hsTimer->value() < 100 && !dragging) + ui->hsTimer->setValue(ui->hsTimer->value() + 1); + if (playing) + { + std::chrono::duration elapsed = + std::chrono::duration_cast>(std::chrono::steady_clock::now() - st); + char ts[100]; + sprintf(ts, "%02d:%02d", (int)(elapsed.count() + offset) / 60, (int)(elapsed.count() + offset) % 60); + ui->lbCurTime->setText(ts); + ui->lbCurPoly->setText(QString("%1").arg(internalfluid->getPolyphone(), 5, 10, QChar('0'))); + ui->lbMaxPoly->setText(QString("%1").arg(internalfluid->getMaxPolyphone(), 5, 10, QChar('0'))); + } +} + +QString qmpMainWindow::getFileName() +{ + return ui->lbFileName->text(); +} +void qmpMainWindow::switchTrack(QString s, bool interrupt) +{ + stopped = false; + playing = true; + setFuncEnabled("Render", stopped); + setFuncEnabled("ReloadSynth", stopped); + ui->pbPlayPause->setIcon(QIcon(getThemedIcon(":/img/pause.svg"))); + if (interrupt) + { + player->playerDeinit(); + player->playerPanic(); + } + invokeCallback("main.stop", nullptr); + if (playerTh) + { + auto f = std::async([this] {playerTh->join();}); + while (f.wait_for(std::chrono::milliseconds(100)) == std::future_status::timeout) + { + QApplication::processEvents(); + ui->lbCurPoly->setText(QString("%1").arg(internalfluid->getPolyphone(), 5, 10, QChar('0'))); + ui->lbMaxPoly->setText(QString("%1").arg(internalfluid->getMaxPolyphone(), 5, 10, QChar('0'))); + } + delete playerTh; + playerTh = nullptr; + } + timer->stop(); + player->playerPanic(true); + ui->hsTimer->setValue(0); + chnlw->on_pbUnmute_clicked(); + chnlw->on_pbUnsolo_clicked(); + QString fns = s; + setWindowTitle(QUrl::fromLocalFile(fns).fileName().left(QUrl::fromLocalFile(fns).fileName().lastIndexOf('.')) + " - QMidiPlayer"); + ui->lbFileName->setText(QUrl::fromLocalFile(fns).fileName().left(QUrl::fromLocalFile(fns).fileName().lastIndexOf('.'))); + onfnChanged(); + if (!loadFile(fns)) + return; + char ts[100]; + sprintf(ts, "%02d:%02d", (int)player->getFtime() / 60, (int)player->getFtime() % 60); + ui->lbFinTime->setText(ts); + player->playerInit(); + invokeCallback("main.start", nullptr); + internalfluid->setGain(ui->vsMasterVol->value() / 250.); + efxw->sendEfxChange(); + playerTh = new std::thread([this] + { + player->playerThread(); + if (settings->getOptionBool("Midi/WaitVoice") && player->isFinished()) + while (internalfluid->getPolyphone() > 0) + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + }); #ifdef _WIN32 - SetThreadPriority((void*)playerTh->native_handle(),THREAD_PRIORITY_TIME_CRITICAL); + SetThreadPriority((void *)playerTh->native_handle(), THREAD_PRIORITY_TIME_CRITICAL); #endif - st=std::chrono::steady_clock::now();offset=0; - timer->start(UPDATE_INTERVAL); + st = std::chrono::steady_clock::now(); + offset = 0; + timer->start(UPDATE_INTERVAL); } std::string qmpMainWindow::getTitle() { - if(settings->getOptionEnumIntOptName("Midi/TextEncoding")=="Unicode") - return std::string(player->getTitle()); - return QTextCodec::codecForName( - settings->getOptionEnumIntOptName("Midi/TextEncoding").c_str())-> - toUnicode(player->getTitle()).toStdString(); + if (settings->getOptionEnumIntOptName("Midi/TextEncoding") == "Unicode") + return std::string(player->getTitle()); + return QTextCodec::codecForName( + settings->getOptionEnumIntOptName("Midi/TextEncoding").c_str())-> + toUnicode(player->getTitle()).toStdString(); } std::wstring qmpMainWindow::getWTitle() { - if(settings->getOptionEnumIntOptName("Midi/TextEncoding")=="Unicode") - return QString(player->getTitle()).toStdWString(); - return QTextCodec::codecForName( - settings->getOptionEnumIntOptName("Midi/TextEncoding").c_str())-> - toUnicode(player->getTitle()).toStdWString(); -} - -void qmpMainWindow::playerSetup(IFluidSettings* fs) -{ - fs->setOptStr("audio.driver",settings->getOptionEnumIntOptName("FluidSynth/AudioDriver").c_str()); - fs->setOptInt("audio.period-size",settings->getOptionInt("FluidSynth/BufSize")); - fs->setOptInt("audio.periods",settings->getOptionInt("FluidSynth/BufCnt")); - fs->setOptStr("audio.sample-format",settings->getOptionEnumIntOptName("FluidSynth/SampleFormat").c_str()); - fs->setOptNum("synth.sample-rate",settings->getOptionInt("FluidSynth/SampleRate")); - fs->setOptInt("synth.polyphony",settings->getOptionInt("FluidSynth/Polyphony")); - fs->setOptInt("synth.cpu-cores",settings->getOptionInt("FluidSynth/Threads")); - std::string bsmode; - if(settings->getOptionBool("FluidSynth/AutoBS")&&player->getFileStandard()) - switch(player->getFileStandard()) - { - case 1:bsmode="gm";break; - case 2:bsmode="mma";break; - case 3:bsmode="gs";break; - case 4:bsmode="xg";break; - } - else - { - bsmode=settings->getOptionEnumIntOptName("FluidSynth/BankSelect"); - std::transform(bsmode.begin(),bsmode.end(),bsmode.begin(),[](char i){return tolower(i);}); - } - fs->setOptStr("synth.midi-bank-select",bsmode.c_str()); - player->sendSysX(settings->getOptionBool("Midi/SendSysEx")); + if (settings->getOptionEnumIntOptName("Midi/TextEncoding") == "Unicode") + return QString(player->getTitle()).toStdWString(); + return QTextCodec::codecForName( + settings->getOptionEnumIntOptName("Midi/TextEncoding").c_str())-> + toUnicode(player->getTitle()).toStdWString(); +} + +void qmpMainWindow::playerSetup(IFluidSettings *fs) +{ + fs->setOptStr("audio.driver", settings->getOptionEnumIntOptName("FluidSynth/AudioDriver").c_str()); + fs->setOptInt("audio.period-size", settings->getOptionInt("FluidSynth/BufSize")); + fs->setOptInt("audio.periods", settings->getOptionInt("FluidSynth/BufCnt")); + fs->setOptStr("audio.sample-format", settings->getOptionEnumIntOptName("FluidSynth/SampleFormat").c_str()); + fs->setOptNum("synth.sample-rate", settings->getOptionInt("FluidSynth/SampleRate")); + fs->setOptInt("synth.polyphony", settings->getOptionInt("FluidSynth/Polyphony")); + fs->setOptInt("synth.cpu-cores", settings->getOptionInt("FluidSynth/Threads")); + std::string bsmode; + if (settings->getOptionBool("FluidSynth/AutoBS") && player->getFileStandard()) + switch (player->getFileStandard()) + { + case 1: + bsmode = "gm"; + break; + case 2: + bsmode = "mma"; + break; + case 3: + bsmode = "gs"; + break; + case 4: + bsmode = "xg"; + break; + } + else + { + bsmode = settings->getOptionEnumIntOptName("FluidSynth/BankSelect"); + std::transform(bsmode.begin(), bsmode.end(), bsmode.begin(), [](char i) + { + return tolower(i); + }); + } + fs->setOptStr("synth.midi-bank-select", bsmode.c_str()); + player->sendSysX(settings->getOptionBool("Midi/SendSysEx")); } void qmpMainWindow::loadSoundFont(IFluidSettings *fs) { - QVariant *data=static_cast(settings->getOptionCustom("FluidSynth/SoundFonts")); - QList sflist=data->toList(); - for(auto i=sflist.rbegin();i!=sflist.rend();++i) - { - if(i->toString().startsWith('#'))continue; - QString sf=i->toString(); + QVariant *data = static_cast(settings->getOptionCustom("FluidSynth/SoundFonts")); + QList sflist = data->toList(); + for (auto i = sflist.rbegin(); i != sflist.rend(); ++i) + { + if (i->toString().startsWith('#')) + continue; + QString sf = i->toString(); #ifdef _WIN32 - char* c=wcsto8bit(sf.toStdWString().c_str()); - fs->loadSFont(c); - free(c); + char *c = wcsto8bit(sf.toStdWString().c_str()); + fs->loadSFont(c); + free(c); #else - fs->loadSFont(sf.toStdString().c_str()); + fs->loadSFont(sf.toStdString().c_str()); #endif - } - delete data; + } + delete data; } int qmpMainWindow::loadFile(QString fns) { #ifdef _WIN32 - char* c=wcsto8bit(fns.toStdWString().c_str()); + char *c = wcsto8bit(fns.toStdWString().c_str()); #else - std::string s=fns.toStdString(); - const char* c=s.c_str(); + std::string s = fns.toStdString(); + const char *c = s.c_str(); #endif - int ret=1; - invokeCallback("main.reset",nullptr); - if(!player->playerLoadFile(c)) - {QMessageBox::critical(this,tr("Error"),tr("%1 is not a valid midi file.").arg(fns));ret=0;} + int ret = 1; + invokeCallback("main.reset", nullptr); + if (!player->playerLoadFile(c)) + { + QMessageBox::critical(this, tr("Error"), tr("%1 is not a valid midi file.").arg(fns)); + ret = 0; + } #ifdef _WIN32 - free(c); + free(c); #endif - return ret; + return ret; } void qmpMainWindow::registerMidiOptions() { - settings->registerOptionBool("MIDI","Disable MIDI Mapping","Midi/DisableMapping",false); - settings->registerOptionBool("MIDI","Send system exclusive messages","Midi/SendSysEx",true); - settings->registerOptionBool("MIDI","Wait for remaining voice before stopping","Midi/WaitVoice",true); - settings->registerOptionEnumInt("MIDI","Text encoding","Midi/TextEncoding",{"Unicode","Big5","Big5-HKSCS","CP949","EUC-JP","EUC-KR","GB18030","KOI8-R","KOI8-U","Macintosh","Shift-JIS"},0); + settings->registerOptionBool("MIDI", "Disable MIDI Mapping", "Midi/DisableMapping", false); + settings->registerOptionBool("MIDI", "Send system exclusive messages", "Midi/SendSysEx", true); + settings->registerOptionBool("MIDI", "Wait for remaining voice before stopping", "Midi/WaitVoice", true); + settings->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 qmpMainWindow::registerBehaviorOptions() { - settings->registerOptionBool("Behavior","Restore last playlist on startup","Behavior/RestorePlaylist",false); - settings->registerOptionBool("Behavior","Add files in the same folder to playlist","Behavior/LoadFolder",false); - settings->registerOptionBool("Behavior","Save dialog status","Behavior/DialogStatus",false); - settings->registerOptionBool("Behavior","Show labels beside icon in toolbar buttons","Behavior/ShowButtonLabel",false); - settings->registerOptionEnumInt("Behavior","Icon Theme","Behavior/IconTheme",{"Auto","Dark","Light"},0); + settings->registerOptionBool("Behavior", "Restore last playlist on startup", "Behavior/RestorePlaylist", false); + settings->registerOptionBool("Behavior", "Add files in the same folder to playlist", "Behavior/LoadFolder", false); + settings->registerOptionBool("Behavior", "Save dialog status", "Behavior/DialogStatus", false); + settings->registerOptionBool("Behavior", "Show labels beside icon in toolbar buttons", "Behavior/ShowButtonLabel", false); + settings->registerOptionEnumInt("Behavior", "Icon Theme", "Behavior/IconTheme", {"Auto", "Dark", "Light"}, 0); } void qmpMainWindow::on_pbPlayPause_clicked() { - playing=!playing; - if(stopped) - { - QString fns=plistw->getFirstItem(); - if(!fns.length()) - { - if(!plistw->on_pbAdd_clicked()){playing=false;return;} - fns=plistw->getFirstItem(); - if(!fns.length())return(void)(playing=false); - }setWindowTitle(QUrl::fromLocalFile(fns).fileName().left(QUrl::fromLocalFile(fns).fileName().lastIndexOf('.'))+" - QMidiPlayer"); - ui->lbFileName->setText(QUrl::fromLocalFile(fns).fileName().left(QUrl::fromLocalFile(fns).fileName().lastIndexOf('.'))); - onfnChanged(); - if(!loadFile(fns))return; - char ts[100]; - sprintf(ts,"%02d:%02d",(int)player->getFtime()/60,(int)player->getFtime()%60); - ui->lbFinTime->setText(ts); - player->playerInit(); - invokeCallback("main.start",nullptr); - internalfluid->setGain(ui->vsMasterVol->value()/250.);efxw->sendEfxChange(); - playerTh=new std::thread([this]{ - player->playerThread(); - if(settings->getOptionBool("Midi/WaitVoice")&&player->isFinished()) - while(internalfluid->getPolyphone()>0) - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - }); + playing = !playing; + if (stopped) + { + QString fns = plistw->getFirstItem(); + if (!fns.length()) + { + if (!plistw->on_pbAdd_clicked()) + { + playing = false; + return; + } + fns = plistw->getFirstItem(); + if (!fns.length()) + return (void)(playing = false); + } + setWindowTitle(QUrl::fromLocalFile(fns).fileName().left(QUrl::fromLocalFile(fns).fileName().lastIndexOf('.')) + " - QMidiPlayer"); + ui->lbFileName->setText(QUrl::fromLocalFile(fns).fileName().left(QUrl::fromLocalFile(fns).fileName().lastIndexOf('.'))); + onfnChanged(); + if (!loadFile(fns)) + return; + char ts[100]; + sprintf(ts, "%02d:%02d", (int)player->getFtime() / 60, (int)player->getFtime() % 60); + ui->lbFinTime->setText(ts); + player->playerInit(); + invokeCallback("main.start", nullptr); + internalfluid->setGain(ui->vsMasterVol->value() / 250.); + efxw->sendEfxChange(); + playerTh = new std::thread([this] + { + player->playerThread(); + if (settings->getOptionBool("Midi/WaitVoice") && player->isFinished()) + while (internalfluid->getPolyphone() > 0) + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + }); #ifdef _WIN32 - SetThreadPriority((void*)playerTh->native_handle(),THREAD_PRIORITY_TIME_CRITICAL); + SetThreadPriority((void *)playerTh->native_handle(), THREAD_PRIORITY_TIME_CRITICAL); #endif - st=std::chrono::steady_clock::now();offset=0; - timer->start(UPDATE_INTERVAL); - stopped=false; - } - else - { - if(!playing) - { - player->playerPanic(); - offset=ui->hsTimer->value()/100.*player->getFtime(); - } - else - { - st=std::chrono::steady_clock::now(); - player->setResumed(); - } - player->setTCpaused(!playing); - invokeCallback("main.pause",nullptr); - } - ui->pbPlayPause->setIcon(QIcon(getThemedIcon(playing?":/img/pause.svg":":/img/play.svg"))); + st = std::chrono::steady_clock::now(); + offset = 0; + timer->start(UPDATE_INTERVAL); + stopped = false; + } + else + { + if (!playing) + { + player->playerPanic(); + offset = ui->hsTimer->value() / 100.*player->getFtime(); + } + else + { + st = std::chrono::steady_clock::now(); + player->setResumed(); + } + player->setTCpaused(!playing); + invokeCallback("main.pause", nullptr); + } + ui->pbPlayPause->setIcon(QIcon(getThemedIcon(playing ? ":/img/pause.svg" : ":/img/play.svg"))); } void qmpMainWindow::on_hsTimer_sliderPressed() { - dragging=true; + dragging = true; } void qmpMainWindow::on_hsTimer_sliderReleased() { - dragging=false; - if(playing) - { - if(ui->hsTimer->value()==100){on_pbNext_clicked();return;} - player->playerPanic(); - player->setTCeptr(player->getStamp(ui->hsTimer->value()),ui->hsTimer->value()); - offset=ui->hsTimer->value()/100.*player->getFtime(); - st=std::chrono::steady_clock::now(); - } - else - { - if(stopped){ui->hsTimer->setValue(0);return;} - player->setTCeptr(player->getStamp(ui->hsTimer->value()),ui->hsTimer->value()); - offset=ui->hsTimer->value()/100.*player->getFtime(); - char ts[100]; - sprintf(ts,"%02d:%02d",(int)(offset)/60,(int)(offset)%60); - ui->lbCurTime->setText(ts); - } - invokeCallback("main.seek",nullptr); -} - -uint32_t qmpMainWindow::getPlaybackPercentage(){return ui->hsTimer->value();} + dragging = false; + if (playing) + { + if (ui->hsTimer->value() == 100) + { + on_pbNext_clicked(); + return; + } + player->playerPanic(); + player->setTCeptr(player->getStamp(ui->hsTimer->value()), ui->hsTimer->value()); + offset = ui->hsTimer->value() / 100.*player->getFtime(); + st = std::chrono::steady_clock::now(); + } + else + { + if (stopped) + { + ui->hsTimer->setValue(0); + return; + } + player->setTCeptr(player->getStamp(ui->hsTimer->value()), ui->hsTimer->value()); + offset = ui->hsTimer->value() / 100.*player->getFtime(); + char ts[100]; + sprintf(ts, "%02d:%02d", (int)(offset) / 60, (int)(offset) % 60); + ui->lbCurTime->setText(ts); + } + invokeCallback("main.seek", nullptr); +} + +uint32_t qmpMainWindow::getPlaybackPercentage() +{ + return ui->hsTimer->value(); +} void qmpMainWindow::playerSeek(uint32_t percentage) { - if(percentage>100)percentage=100; - if(percentage<0)percentage=0; - invokeCallback("main.seek",nullptr); - if(playing) - { - if(percentage==100){on_pbNext_clicked();return;} - player->playerPanic();ui->hsTimer->setValue(percentage); - player->setTCeptr(player->getStamp(percentage),percentage); - offset=percentage/100.*player->getFtime(); - st=std::chrono::steady_clock::now(); - } - else - { - if(stopped){ui->hsTimer->setValue(0);return;} - player->setTCeptr(player->getStamp(percentage),percentage); - offset=percentage/100.*player->getFtime();ui->hsTimer->setValue(percentage); - char ts[100]; - sprintf(ts,"%02d:%02d",(int)(offset)/60,(int)(offset)%60); - ui->lbCurTime->setText(ts); - } + if (percentage > 100) + percentage = 100; + if (percentage < 0) + percentage = 0; + invokeCallback("main.seek", nullptr); + if (playing) + { + if (percentage == 100) + { + on_pbNext_clicked(); + return; + } + player->playerPanic(); + ui->hsTimer->setValue(percentage); + player->setTCeptr(player->getStamp(percentage), percentage); + offset = percentage / 100.*player->getFtime(); + st = std::chrono::steady_clock::now(); + } + else + { + if (stopped) + { + ui->hsTimer->setValue(0); + return; + } + player->setTCeptr(player->getStamp(percentage), percentage); + offset = percentage / 100.*player->getFtime(); + ui->hsTimer->setValue(percentage); + char ts[100]; + sprintf(ts, "%02d:%02d", (int)(offset) / 60, (int)(offset) % 60); + ui->lbCurTime->setText(ts); + } } void qmpMainWindow::on_vsMasterVol_valueChanged() { - if(!stopped)internalfluid->setGain(ui->vsMasterVol->value()/250.); - settings->setOptionRaw("FluidSynth/Gain",ui->vsMasterVol->value()); + if (!stopped) + internalfluid->setGain(ui->vsMasterVol->value() / 250.); + settings->setOptionRaw("FluidSynth/Gain", ui->vsMasterVol->value()); } void qmpMainWindow::on_pbStop_clicked() { - if(!stopped) - { - timer->stop();stopped=true;playing=false; - invokeCallback("main.stop",nullptr); - player->playerDeinit(); - setFuncEnabled("Render",stopped);setFuncEnabled("ReloadSynth",stopped); - player->playerPanic(true); - if(playerTh){playerTh->join();delete playerTh;playerTh=nullptr;} - chnlw->on_pbUnmute_clicked();chnlw->on_pbUnsolo_clicked(); - ui->pbPlayPause->setIcon(QIcon(getThemedIcon(":/img/play.svg"))); - ui->hsTimer->setValue(0); - ui->lbCurPoly->setText("00000");ui->lbMaxPoly->setText("00000"); - ui->lbCurTime->setText("00:00"); - } + if (!stopped) + { + timer->stop(); + stopped = true; + playing = false; + invokeCallback("main.stop", nullptr); + player->playerDeinit(); + setFuncEnabled("Render", stopped); + setFuncEnabled("ReloadSynth", stopped); + player->playerPanic(true); + if (playerTh) + { + playerTh->join(); + delete playerTh; + playerTh = nullptr; + } + chnlw->on_pbUnmute_clicked(); + chnlw->on_pbUnsolo_clicked(); + ui->pbPlayPause->setIcon(QIcon(getThemedIcon(":/img/play.svg"))); + ui->hsTimer->setValue(0); + ui->lbCurPoly->setText("00000"); + ui->lbMaxPoly->setText("00000"); + ui->lbCurTime->setText("00:00"); + } } void qmpMainWindow::dialogClosed() { - if(!settingsw->isVisible())ui->pbSettings->setChecked(false); + if (!settingsw->isVisible()) + ui->pbSettings->setChecked(false); } void qmpMainWindow::on_pbPrev_clicked() { - switchTrack(plistw->getPrevItem()); + switchTrack(plistw->getPrevItem()); } void qmpMainWindow::on_pbNext_clicked() { - switchTrack(plistw->getNextItem()); + switchTrack(plistw->getNextItem()); } void qmpMainWindow::selectionChanged() { - switchTrack(plistw->getSelectedItem()); + switchTrack(plistw->getSelectedItem()); } void qmpMainWindow::on_lbFileName_customContextMenuRequested(const QPoint &pos) { - QMenu menu(ui->lbFileName); - menu.addActions(ui->lbFileName->actions()); - menu.exec(this->pos()+ui->lbFileName->pos()+pos); + QMenu menu(ui->lbFileName); + menu.addActions(ui->lbFileName->actions()); + menu.exec(this->pos() + ui->lbFileName->pos() + pos); } void qmpMainWindow::onfnChanged() { - if(!ui->lbFileName->text().length())return; - QFont f=ui->lbFileName->font();f.setPointSize(18); - QFontMetrics fm(f); - QSize size=fm.size(0,ui->lbFileName->text()); - double fw=ui->lbFileName->width()/(double)size.width(); - double fh=ui->lbFileName->height()/(double)size.height(); - double ps=floor(f.pointSizeF()*(fw18?18:ps); - ui->lbFileName->setFont(f); + if (!ui->lbFileName->text().length()) + return; + QFont f = ui->lbFileName->font(); + f.setPointSize(18); + QFontMetrics fm(f); + QSize size = fm.size(0, ui->lbFileName->text()); + double fw = ui->lbFileName->width() / (double)size.width(); + double fh = ui->lbFileName->height() / (double)size.height(); + double ps = floor(f.pointSizeF() * (fw < fh ? fw : fh)); + if (ps < 6) + ps = 6; + f.setPointSizeF(ps > 18 ? 18 : ps); + ui->lbFileName->setFont(f); } -int qmpMainWindow::registerUIHook(std::string e,ICallBack *callback,void* userdat) +int qmpMainWindow::registerUIHook(std::string e, ICallBack *callback, void *userdat) { - std::map>& m=muicb[e]; - int id=0; - if(m.size())id=m.rbegin()->first+1; - m[id]=std::make_pair(qmpCallBack(callback),userdat); - return id; + std::map> &m = muicb[e]; + int id = 0; + if (m.size()) + id = m.rbegin()->first + 1; + m[id] = std::make_pair(qmpCallBack(callback), userdat); + return id; } -int qmpMainWindow::registerUIHook(std::string e,callback_t callback,void *userdat) +int qmpMainWindow::registerUIHook(std::string e, callback_t callback, void *userdat) { - std::map>& m=muicb[e]; - int id=0; - if(m.size())id=m.rbegin()->first+1; - m[id]=std::make_pair(qmpCallBack(callback),userdat); - return id; + std::map> &m = muicb[e]; + int id = 0; + if (m.size()) + id = m.rbegin()->first + 1; + m[id] = std::make_pair(qmpCallBack(callback), userdat); + return id; } -void qmpMainWindow::unregisterUIHook(std::string e,int hook) +void qmpMainWindow::unregisterUIHook(std::string e, int hook) { - std::map>& m=muicb[e]; - m.erase(hook); + std::map> &m = muicb[e]; + m.erase(hook); } -void qmpMainWindow::registerFunctionality(qmpFuncBaseIntf *i,std::string name,std::string desc,const char *icon,int iconlen,bool checkable) +void qmpMainWindow::registerFunctionality(qmpFuncBaseIntf *i, std::string name, std::string desc, const char *icon, int iconlen, bool checkable) { - if(mfunc.find(name)!=mfunc.end())return; - mfunc[name]=qmpFuncPrivate(i,desc,icon,iconlen,checkable); + if (mfunc.find(name) != mfunc.end()) + return; + mfunc[name] = qmpFuncPrivate(i, desc, icon, iconlen, checkable); } void qmpMainWindow::unregisterFunctionality(std::string name) { - mfunc.erase(name); - for(auto i=enabled_actions.begin();i!=enabled_actions.end();++i) - if(*i==name){enabled_actions.erase(i);break;} - for(auto i=enabled_buttons.begin();i!=enabled_buttons.end();++i) - if(*i==name){enabled_buttons.erase(i);break;} - setupWidget(); + mfunc.erase(name); + for (auto i = enabled_actions.begin(); i != enabled_actions.end(); ++i) + if (*i == name) + { + enabled_actions.erase(i); + break; + } + for (auto i = enabled_buttons.begin(); i != enabled_buttons.end(); ++i) + if (*i == name) + { + enabled_buttons.erase(i); + break; + } + setupWidget(); } -void qmpMainWindow::setFuncState(std::string name,bool state) -{mfunc[name].setChecked(state);} -void qmpMainWindow::setFuncEnabled(std::string name,bool enable) -{mfunc[name].setEnabled(enable);} +void qmpMainWindow::setFuncState(std::string name, bool state) +{ + mfunc[name].setChecked(state); +} +void qmpMainWindow::setFuncEnabled(std::string name, bool enable) +{ + mfunc[name].setEnabled(enable); +} bool qmpMainWindow::isDarkTheme() { - if(!settings->getOptionEnumInt("Behavior/IconTheme")) - { - return ui->centralWidget->palette().color(QPalette::Background).lightness()<128; - } - else return 2-settings->getOptionEnumInt("Behavior/IconTheme"); + if (!settings->getOptionEnumInt("Behavior/IconTheme")) + { + return ui->centralWidget->palette().color(QPalette::Background).lightness() < 128; + } + else return 2 - settings->getOptionEnumInt("Behavior/IconTheme"); } void qmpMainWindow::startRender() { #ifdef _WIN32 - char* ofstr=wcsto8bit((plistw->getSelectedItem()+QString(".wav")).toStdWString().c_str()); - char* ifstr=wcsto8bit(plistw->getSelectedItem().toStdWString().c_str()); - fluidrenderer=new qmpFileRendererFluid(ifstr,ofstr); - playerSetup(fluidrenderer); - fluidrenderer->renderInit(); - free(ofstr);free(ifstr); + char *ofstr = wcsto8bit((plistw->getSelectedItem() + QString(".wav")).toStdWString().c_str()); + char *ifstr = wcsto8bit(plistw->getSelectedItem().toStdWString().c_str()); + fluidrenderer = new qmpFileRendererFluid(ifstr, ofstr); + playerSetup(fluidrenderer); + fluidrenderer->renderInit(); + free(ofstr); + free(ifstr); #else - fluidrenderer=new qmpFileRendererFluid( - plistw->getSelectedItem().toStdString().c_str(), - (plistw->getSelectedItem()+QString(".wav")).toStdString().c_str() - ); - playerSetup(fluidrenderer); - fluidrenderer->renderInit(); + fluidrenderer = new qmpFileRendererFluid( + plistw->getSelectedItem().toStdString().c_str(), + (plistw->getSelectedItem() + QString(".wav")).toStdString().c_str() + ); + playerSetup(fluidrenderer); + fluidrenderer->renderInit(); #endif - loadSoundFont(fluidrenderer); - ui->centralWidget->setEnabled(false); - fluidrenderer->setGain(ui->vsMasterVol->value()/250.); - efxw->sendEfxChange(fluidrenderer);timer->start(UPDATE_INTERVAL); - renderTh=new std::thread(&qmpFileRendererFluid::renderWorker,fluidrenderer); + loadSoundFont(fluidrenderer); + ui->centralWidget->setEnabled(false); + fluidrenderer->setGain(ui->vsMasterVol->value() / 250.); + efxw->sendEfxChange(fluidrenderer); + timer->start(UPDATE_INTERVAL); + renderTh = new std::thread(&qmpFileRendererFluid::renderWorker, fluidrenderer); } void qmpMainWindow::reloadSynth() { - ui->centralWidget->setEnabled(false); - std::future f=std::async(std::launch::async, - [this] - { - internalfluid->deviceDeinit(true); - playerSetup(internalfluid); - internalfluid->deviceInit(); - loadSoundFont(internalfluid); - } - ); - while(f.wait_for(std::chrono::milliseconds(100))==std::future_status::timeout) - QApplication::processEvents(); - ui->centralWidget->setEnabled(true); + ui->centralWidget->setEnabled(false); + std::future f = std::async(std::launch::async, + [this] + { + internalfluid->deviceDeinit(true); + playerSetup(internalfluid); + internalfluid->deviceInit(); + loadSoundFont(internalfluid); + } + ); + while (f.wait_for(std::chrono::milliseconds(100)) == std::future_status::timeout) + QApplication::processEvents(); + ui->centralWidget->setEnabled(true); } -std::map& qmpMainWindow::getFunc() -{return mfunc;} +std::map &qmpMainWindow::getFunc() +{ + return mfunc; +} void qmpMainWindow::setupWidget() { - for(auto i=mfunc.begin();i!=mfunc.end();++i) - { - i->second.setAssignedControl(static_cast(nullptr)); - i->second.setAssignedControl(static_cast(nullptr)); - } - QVariant *v=static_cast(settings->getOptionCustom("Behavior/Toolbar")); - enabled_buttons.clear(); - for(auto i:v->toList()) - enabled_buttons.push_back(i.toString().toStdString()); - delete v; - v=static_cast(settings->getOptionCustom("Behavior/Actions")); - enabled_actions.clear(); - for(auto i:v->toList()) - enabled_actions.push_back(i.toString().toStdString()); - delete v; - QListw=ui->buttonwidget->findChildren("",Qt::FindDirectChildrenOnly); - qDeleteAll(w); - QLista=ui->lbFileName->actions(); - for(int i=0;ilbFileName->removeAction(a[i]); - delete a[i]; - } - for(unsigned i=0;igetOptionBool("Behavior/ShowButtonLabel")) - { - pb->setText(tr(mfunc[enabled_buttons[i]].desc().c_str())); - pb->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Fixed); - } - else - setButtonWidth(pb,32); - pb->setIconSize(QSize(16,16)); - ui->buttonwidget->layout()->addWidget(pb); - mfunc[enabled_buttons[i]].setAssignedControl(pb); - connect(pb,&QReflectivePushButton::onClick,this,&qmpMainWindow::funcReflector); - } - for(unsigned i=0;ilbFileName->addAction(a); - mfunc[enabled_actions[i]].setAssignedControl(a); - connect(a,&QReflectiveAction::onClick,this,&qmpMainWindow::funcReflector); - } - ui->buttonwidget->layout()->setAlignment(Qt::AlignLeft); -} - -void qmpMainWindow::invokeCallback(std::string cat,void* callerdat) -{ - std::map> *mp; - mp=&muicb[cat]; - for(auto&i:*mp) - i.second.first(callerdat,i.second.second); + for (auto i = mfunc.begin(); i != mfunc.end(); ++i) + { + i->second.setAssignedControl(static_cast(nullptr)); + i->second.setAssignedControl(static_cast(nullptr)); + } + QVariant *v = static_cast(settings->getOptionCustom("Behavior/Toolbar")); + enabled_buttons.clear(); + for (auto i : v->toList()) + enabled_buttons.push_back(i.toString().toStdString()); + delete v; + v = static_cast(settings->getOptionCustom("Behavior/Actions")); + enabled_actions.clear(); + for (auto i : v->toList()) + enabled_actions.push_back(i.toString().toStdString()); + delete v; + QListw = ui->buttonwidget->findChildren("", Qt::FindDirectChildrenOnly); + qDeleteAll(w); + QLista = ui->lbFileName->actions(); + for (int i = 0; i < a.size(); ++i) + { + ui->lbFileName->removeAction(a[i]); + delete a[i]; + } + for (unsigned i = 0; i < enabled_buttons.size(); ++i) + { + if (mfunc.find(enabled_buttons[i]) == mfunc.end()) + continue; + QReflectivePushButton *pb = new QReflectivePushButton( + mfunc[enabled_buttons[i]].icon(), + tr(mfunc[enabled_buttons[i]].desc().c_str()), + enabled_buttons[i] + ); + setButtonHeight(pb, 32); + //!!TODO + if (settings->getOptionBool("Behavior/ShowButtonLabel")) + { + pb->setText(tr(mfunc[enabled_buttons[i]].desc().c_str())); + pb->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + } + else + setButtonWidth(pb, 32); + pb->setIconSize(QSize(16, 16)); + ui->buttonwidget->layout()->addWidget(pb); + mfunc[enabled_buttons[i]].setAssignedControl(pb); + connect(pb, &QReflectivePushButton::onClick, this, &qmpMainWindow::funcReflector); + } + for (unsigned i = 0; i < enabled_actions.size(); ++i) + { + if (mfunc.find(enabled_actions[i]) == mfunc.end()) + continue; + QReflectiveAction *a = new QReflectiveAction( + mfunc[enabled_actions[i]].icon(), + tr(mfunc[enabled_actions[i]].desc().c_str()), + enabled_actions[i] + ); + ui->lbFileName->addAction(a); + mfunc[enabled_actions[i]].setAssignedControl(a); + connect(a, &QReflectiveAction::onClick, this, &qmpMainWindow::funcReflector); + } + ui->buttonwidget->layout()->setAlignment(Qt::AlignLeft); +} + +void qmpMainWindow::invokeCallback(std::string cat, void *callerdat) +{ + std::map> *mp; + mp = &muicb[cat]; + for (auto &i : *mp) + i.second.first(callerdat, i.second.second); } void qmpMainWindow::on_pbSettings_clicked() { - if(ui->pbSettings->isChecked())settingsw->show();else settingsw->close(); + if (ui->pbSettings->isChecked()) + settingsw->show(); + else settingsw->close(); } void qmpMainWindow::funcReflector(std::string reflt) { - if(mfunc[reflt].isCheckable()) - { - mfunc[reflt].setChecked(!mfunc[reflt].isChecked()); - if(mfunc[reflt].isChecked()) - mfunc[reflt].i()->show(); - else - mfunc[reflt].i()->close(); - } - else mfunc[reflt].i()->show(); + if (mfunc[reflt].isCheckable()) + { + mfunc[reflt].setChecked(!mfunc[reflt].isChecked()); + if (mfunc[reflt].isChecked()) + mfunc[reflt].i()->show(); + else + mfunc[reflt].i()->close(); + } + else mfunc[reflt].i()->show(); } void qmpMainWindow::on_pushButton_clicked() { - helpw->show(); + helpw->show(); } -qmpFuncPrivate::qmpFuncPrivate(qmpFuncBaseIntf *i,std::string _desc,const char *icon,int iconlen,bool checkable): - _i(i),des(_desc),_checkable(checkable) +qmpFuncPrivate::qmpFuncPrivate(qmpFuncBaseIntf *i, std::string _desc, const char *icon, int iconlen, bool checkable): + _i(i), des(_desc), _checkable(checkable) { - if(icon) - { - QImage img; - if(icon[0]==':'&&icon[1]=='/'||icon[0]=='q'&&icon[1]=='r'&&icon[2]=='c') - img=QImage(QString(icon)); - else - img.loadFromData((uchar*)icon,iconlen); - QPixmap pixm;pixm.convertFromImage(img); - _icon=QIcon(pixm); - }else _icon=QIcon(); - checked=false; - asgna=nullptr;asgnb=nullptr; + if (icon) + { + QImage img; + if (icon[0] == ':' && icon[1] == '/' || icon[0] == 'q' && icon[1] == 'r' && icon[2] == 'c') + img = QImage(QString(icon)); + else + img.loadFromData((uchar *)icon, iconlen); + QPixmap pixm; + pixm.convertFromImage(img); + _icon = QIcon(pixm); + } + else _icon = QIcon(); + checked = false; + asgna = nullptr; + asgnb = nullptr; } void qmpMainWindow::on_pbAdd_clicked() { - if(plistw->on_pbAdd_clicked()) - switchTrack(plistw->getLastItem()); + if (plistw->on_pbAdd_clicked()) + switchTrack(plistw->getLastItem()); } diff --git a/qmidiplayer-desktop/qmpmainwindow.hpp b/qmidiplayer-desktop/qmpmainwindow.hpp index d98029d..28fb82c 100644 --- a/qmidiplayer-desktop/qmpmainwindow.hpp +++ b/qmidiplayer-desktop/qmpmainwindow.hpp @@ -33,79 +33,122 @@ #define getThemedIcon(x) (qmpMainWindow::getInstance()->isDarkTheme()?QString(x).insert(QString(x).lastIndexOf('.'),"_i"):QString(x)) #define getThemedIconc(x) ((qmpMainWindow::getInstance()->isDarkTheme()?QString(x).insert(QString(x).lastIndexOf('.'),"_i"):QString(x)).toStdString().c_str()) -namespace Ui { - class qmpMainWindow; +namespace Ui +{ +class qmpMainWindow; } -class QClickableSlider:public QSlider +class QClickableSlider : public QSlider { - Q_OBJECT - public: - explicit QClickableSlider(QWidget *parent=0):QSlider(parent){} - protected: - void mouseReleaseEvent(QMouseEvent *e) - { - QSlider::mouseReleaseEvent(e); - if(e->buttons()^Qt::LeftButton) - { - double p=e->pos().x()/(double)width(); - setValue(p*(maximum()-minimum())+minimum()); - emit sliderReleased(); - } - } + Q_OBJECT +public: + explicit QClickableSlider(QWidget *parent = 0) : QSlider(parent) {} +protected: + void mouseReleaseEvent(QMouseEvent *e) + { + QSlider::mouseReleaseEvent(e); + if (e->buttons()^Qt::LeftButton) + { + double p = e->pos().x() / (double)width(); + setValue(p * (maximum() - minimum()) + minimum()); + emit sliderReleased(); + } + } }; -class QReflectiveAction:public QAction +class QReflectiveAction : public QAction { - Q_OBJECT - private: - std::string reflt; - signals: - void onClick(std::string s); - public: - explicit QReflectiveAction(const QIcon& icon,const QString& text,const std::string& ref): - QAction(icon,text,nullptr),reflt(ref){ - connect(this,&QAction::triggered,std::bind(&QReflectiveAction::onClick,this,reflt)); - } + Q_OBJECT +private: + std::string reflt; +signals: + void onClick(std::string s); +public: + explicit QReflectiveAction(const QIcon &icon, const QString &text, const std::string &ref): + QAction(icon, text, nullptr), reflt(ref) + { + connect(this, &QAction::triggered, std::bind(&QReflectiveAction::onClick, this, reflt)); + } }; -class QReflectivePushButton:public QPushButton +class QReflectivePushButton : public QPushButton { - Q_OBJECT - private: - std::string reflt; - signals: - void onClick(std::string s); - public: - explicit QReflectivePushButton(const QIcon& icon,const QString& text,const std::string& ref): - QPushButton(icon,""),reflt(ref){ - connect(this,&QPushButton::clicked,std::bind(&QReflectivePushButton::onClick,this,reflt)); - setToolTip(text); - } + Q_OBJECT +private: + std::string reflt; +signals: + void onClick(std::string s); +public: + explicit QReflectivePushButton(const QIcon &icon, const QString &text, const std::string &ref): + QPushButton(icon, QString()), reflt(ref) + { + connect(this, &QPushButton::clicked, std::bind(&QReflectivePushButton::onClick, this, reflt)); + setToolTip(text); + } }; class qmpFuncPrivate { - private: - qmpFuncBaseIntf* _i=nullptr; - QIcon _icon; - std::string des; - bool _checkable,checked; - QReflectiveAction* asgna=nullptr; - QReflectivePushButton* asgnb=nullptr; - public: - qmpFuncPrivate(){} - qmpFuncPrivate(qmpFuncBaseIntf* i,std::string _desc,const char* icon,int iconlen,bool checkable); - ~qmpFuncPrivate(){asgna=nullptr;asgnb=nullptr;} - qmpFuncBaseIntf* i(){return _i;} - void setAssignedControl(QReflectiveAction* a){asgna=a;if(!a)return;asgna->setCheckable(_checkable);asgna->setChecked(checked);} - void setAssignedControl(QReflectivePushButton* a){asgnb=a;if(!a)return;asgnb->setCheckable(_checkable);asgnb->setChecked(checked);} - const QIcon& icon(){return _icon;} - const std::string& desc(){return des;} - bool isCheckable(){return _checkable;} - bool isChecked(){return checked;} - void setEnabled(bool e){if(asgna)asgna->setEnabled(e);if(asgnb)asgnb->setEnabled(e);} - void setChecked(bool _c){checked=_c;if(asgna)asgna->setChecked(checked);if(asgnb)asgnb->setChecked(checked);} +private: + qmpFuncBaseIntf *_i = nullptr; + QIcon _icon; + std::string des; + bool _checkable, checked; + QReflectiveAction *asgna = nullptr; + QReflectivePushButton *asgnb = nullptr; +public: + qmpFuncPrivate() {} + qmpFuncPrivate(qmpFuncBaseIntf *i, std::string _desc, const char *icon, int iconlen, bool checkable); + ~qmpFuncPrivate() + { + asgna = nullptr; + asgnb = nullptr; + } + qmpFuncBaseIntf *i() + { + return _i; + } + void setAssignedControl(QReflectiveAction *a) + { + asgna = a; + if (!a)return; + asgna->setCheckable(_checkable); + asgna->setChecked(checked); + } + void setAssignedControl(QReflectivePushButton *a) + { + asgnb = a; + if (!a)return; + asgnb->setCheckable(_checkable); + asgnb->setChecked(checked); + } + const QIcon &icon() + { + return _icon; + } + const std::string &desc() + { + return des; + } + bool isCheckable() + { + return _checkable; + } + bool isChecked() + { + return checked; + } + void setEnabled(bool e) + { + if (asgna)asgna->setEnabled(e); + if (asgnb)asgnb->setEnabled(e); + } + void setChecked(bool _c) + { + checked = _c; + if (asgna)asgna->setChecked(checked); + if (asgnb)asgnb->setChecked(checked); + } }; class qmpRenderFunc; @@ -114,144 +157,196 @@ class qmpReloadSynthFunc; class qmpCallBack { - private: - int t; - ICallBack* cbc; - callback_t cbf; - public: - qmpCallBack(){t=-1;cbc=nullptr;cbf=nullptr;} - qmpCallBack(ICallBack* _cb){t=0;cbc=_cb;cbf=nullptr;} - qmpCallBack(callback_t _cb){t=1;cbf=_cb;cbc=nullptr;} - void operator ()(void* cbd,void* usrd) - { - if(t<0)return; - if(t)cbf(cbd,usrd); - else cbc->callBack(cbd,usrd); - } +private: + int t; + ICallBack *cbc; + callback_t cbf; +public: + qmpCallBack() + { + t = -1; + cbc = nullptr; + cbf = nullptr; + } + qmpCallBack(ICallBack *_cb) + { + t = 0; + cbc = _cb; + cbf = nullptr; + } + qmpCallBack(callback_t _cb) + { + t = 1; + cbf = _cb; + cbc = nullptr; + } + void operator()(void *cbd, void *usrd) + { + if (t < 0)return; + if (t)cbf(cbd, usrd); + else cbc->callBack(cbd, usrd); + } }; -class qmpMainWindow:public QMainWindow +class qmpMainWindow: public QMainWindow { - Q_OBJECT + Q_OBJECT - public: - explicit qmpMainWindow(QCommandLineParser *clp,QWidget *parent=nullptr); - void init(); - void closeEvent(QCloseEvent *event); - void dropEvent(QDropEvent *event); - void dragEnterEvent(QDragEnterEvent *event); - ~qmpMainWindow(); - CMidiPlayer* getPlayer(){return player;} - qmpMidiOutFluid* getFluid(){return internalfluid;} - qmpSettings* getSettings(){return settings.get();} - QTimer* getTimer(){return timer;} - bool isFinalizing(){return fin;} - QString getFileName(); - void switchTrack(QString s,bool interrupt=true); - std::string getTitle(); - std::wstring getWTitle(); - uint32_t getPlaybackPercentage(); - void playerSeek(uint32_t percentage); - int parseArgs(); - 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* callback,void* userdat); - int registerUIHook(std::string e,callback_t callback,void* userdat); - void unregisterUIHook(std::string e,int hook); - void setFuncState(std::string name,bool state); - void setFuncEnabled(std::string name,bool enable); - bool isDarkTheme(); - void startRender(); - void reloadSynth(); - void setupWidget(); - void invokeCallback(std::string cat,void *callerdat); - std::map& getFunc(); +public: + explicit qmpMainWindow(QCommandLineParser *clp, QWidget *parent = nullptr); + void init(); + void closeEvent(QCloseEvent *event); + void dropEvent(QDropEvent *event); + void dragEnterEvent(QDragEnterEvent *event); + ~qmpMainWindow(); + CMidiPlayer *getPlayer() + { + return player; + } + qmpMidiOutFluid *getFluid() + { + return internalfluid; + } + qmpSettings *getSettings() + { + return settings.get(); + } + QTimer *getTimer() + { + return timer; + } + bool isFinalizing() + { + return fin; + } + QString getFileName(); + void switchTrack(QString s, bool interrupt = true); + std::string getTitle(); + std::wstring getWTitle(); + uint32_t getPlaybackPercentage(); + void playerSeek(uint32_t percentage); + int parseArgs(); + 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 *callback, void *userdat); + int registerUIHook(std::string e, callback_t callback, void *userdat); + void unregisterUIHook(std::string e, int hook); + void setFuncState(std::string name, bool state); + void setFuncEnabled(std::string name, bool enable); + bool isDarkTheme(); + void startRender(); + void reloadSynth(); + void setupWidget(); + void invokeCallback(std::string cat, void *callerdat); + std::map &getFunc(); - private slots: - void on_pbPlayPause_clicked(); - void updateWidgets(); - void on_hsTimer_sliderPressed(); - void on_hsTimer_sliderReleased(); - void on_vsMasterVol_valueChanged(); - void on_pbStop_clicked(); - void on_pbPrev_clicked(); - void on_pbNext_clicked(); - void on_lbFileName_customContextMenuRequested(const QPoint &pos); - void on_pbSettings_clicked(); - void funcReflector(std::string reflt); - void on_pushButton_clicked(); - void on_pbAdd_clicked(); +private slots: + void on_pbPlayPause_clicked(); + void updateWidgets(); + void on_hsTimer_sliderPressed(); + void on_hsTimer_sliderReleased(); + void on_vsMasterVol_valueChanged(); + void on_pbStop_clicked(); + void on_pbPrev_clicked(); + void on_pbNext_clicked(); + void on_lbFileName_customContextMenuRequested(const QPoint &pos); + void on_pbSettings_clicked(); + void funcReflector(std::string reflt); + void on_pushButton_clicked(); + void on_pbAdd_clicked(); - public slots: - void dialogClosed(); - void selectionChanged(); +public slots: + void dialogClosed(); + void selectionChanged(); - private: - Ui::qmpMainWindow *ui; - QTimer *timer; - bool playing,stopped,dragging,fin; - std::thread *playerTh=nullptr; - std::thread *renderTh=nullptr; - std::chrono::steady_clock::time_point st; - double offset; - CMidiPlayer *player; - qmpMidiOutFluid *internalfluid; - qmpFileRendererFluid *fluidrenderer; - qmpPluginManager *pmgr; - QPointer plistw; - QPointer chnlw; - QPointer efxw; - QPointer infow; - QPointer helpw; - std::unique_ptr settings; - QPointer settingsw; - std::map mfunc; - std::unordered_map>> muicb; - qmpRenderFunc* renderf; - qmpPanicFunc* panicf; - qmpReloadSynthFunc* reloadsynf; - std::vector enabled_buttons,enabled_actions; - std::vector argfiles; - QCommandLineParser *clp; +private: + Ui::qmpMainWindow *ui; + QTimer *timer; + bool playing, stopped, dragging, fin; + std::thread *playerTh = nullptr; + std::thread *renderTh = nullptr; + std::chrono::steady_clock::time_point st; + double offset; + CMidiPlayer *player; + qmpMidiOutFluid *internalfluid; + qmpFileRendererFluid *fluidrenderer; + qmpPluginManager *pmgr; + QPointer plistw; + QPointer chnlw; + QPointer efxw; + QPointer infow; + QPointer helpw; + std::unique_ptr settings; + QPointer settingsw; + std::map mfunc; + std::unordered_map>> muicb; + qmpRenderFunc *renderf; + qmpPanicFunc *panicf; + qmpReloadSynthFunc *reloadsynf; + std::vector enabled_buttons, enabled_actions; + std::vector argfiles; + QCommandLineParser *clp; - void onfnChanged(); - void playerSetup(IFluidSettings *fs); - void loadSoundFont(IFluidSettings *fs); - int loadFile(QString fns); - void registerMidiOptions(); - void registerBehaviorOptions(); + void onfnChanged(); + void playerSetup(IFluidSettings *fs); + void loadSoundFont(IFluidSettings *fs); + int loadFile(QString fns); + void registerMidiOptions(); + void registerBehaviorOptions(); - private: - static qmpMainWindow* ref; - public: static qmpMainWindow* getInstance(){return ref;} +private: + static qmpMainWindow *ref; +public: + static qmpMainWindow *getInstance() + { + return ref; + } }; -class qmpRenderFunc:public qmpFuncBaseIntf +class qmpRenderFunc: public qmpFuncBaseIntf { - private: - qmpMainWindow *p; - public: - qmpRenderFunc(qmpMainWindow *par){p=par;} - void show(){p->startRender();} - void close(){} +private: + qmpMainWindow *p; +public: + qmpRenderFunc(qmpMainWindow *par) + { + p = par; + } + void show() + { + p->startRender(); + } + void close() {} }; -class qmpPanicFunc:public qmpFuncBaseIntf +class qmpPanicFunc: public qmpFuncBaseIntf { - private: - qmpMainWindow *p; - public: - qmpPanicFunc(qmpMainWindow *par){p=par;} - void show(){p->getPlayer()->playerPanic();} - void close(){} +private: + qmpMainWindow *p; +public: + qmpPanicFunc(qmpMainWindow *par) + { + p = par; + } + void show() + { + p->getPlayer()->playerPanic(); + } + void close() {} }; -class qmpReloadSynthFunc:public qmpFuncBaseIntf +class qmpReloadSynthFunc: public qmpFuncBaseIntf { - private: - qmpMainWindow *p; - public: - qmpReloadSynthFunc(qmpMainWindow *par){p=par;} - void show(){p->reloadSynth();} - void close(){} +private: + qmpMainWindow *p; +public: + qmpReloadSynthFunc(qmpMainWindow *par) + { + p = par; + } + void show() + { + p->reloadSynth(); + } + void close() {} }; #endif // QMPMAINWINDOW_H diff --git a/qmidiplayer-desktop/qmpplistwindow.cpp b/qmidiplayer-desktop/qmpplistwindow.cpp index 5b46fb6..55cc980 100644 --- a/qmidiplayer-desktop/qmpplistwindow.cpp +++ b/qmidiplayer-desktop/qmpplistwindow.cpp @@ -13,340 +13,378 @@ #define setButtonHeight(x,h) {x->setMaximumHeight(h*(logicalDpiY()/96.));x->setMinimumHeight(h*(logicalDpiY()/96.));} qmpPlistWindow::qmpPlistWindow(QWidget *parent): - QWidget(parent,Qt::Dialog), - ui(new Ui::qmpPlistWindow) + QWidget(parent, Qt::Dialog), + ui(new Ui::qmpPlistWindow) { - ui->setupUi(this); - setButtonHeight(ui->pbAdd,36);setButtonHeight(ui->pbAddFolder,36); - setButtonHeight(ui->pbClear,36);setButtonHeight(ui->pbLoad,36); - setButtonHeight(ui->pbRemove,36);setButtonHeight(ui->pbRepeat,36); - setButtonHeight(ui->pbSave,36);setButtonHeight(ui->pbShuffle,36); - connect(this,&qmpPlistWindow::selectionChanging,(qmpMainWindow*)parent,&qmpMainWindow::selectionChanged); - repeat=0;shuffle=0; - settings=qmpMainWindow::getInstance()->getSettings(); - if(settings->getOptionBool("Behavior/RestorePlaylist")) - { - QSettings* plist=new QSettings(QStandardPaths::writableLocation(QStandardPaths::StandardLocation::ConfigLocation)+QString("/qmpplist"), - QSettings::IniFormat); - int fc=plist->value("Playlist/FileCount",0).toInt(); - ui->lwFiles->clear();for(int i=0;ilwFiles->addItem(plist->value("Playlist/File"+QString("%1").arg(i,5,10,QChar('0')),"").toString()); - repeat=plist->value("Playlist/Repeat",0).toInt(); - shuffle=plist->value("Playlist/Shuffle",0).toInt(); - switch(shuffle) - { - case 1: - ui->pbShuffle->setIcon(QIcon(getThemedIcon(":/img/shuffle.svg"))); - ui->pbShuffle->setText("Shuffle On"); - break; - case 0: - default: - ui->pbShuffle->setIcon(QIcon(getThemedIcon(":/img/shuffle-off.svg"))); - ui->pbShuffle->setText("Shuffle Off"); - break; - } - switch(repeat) - { - case 0: - ui->pbRepeat->setIcon(QIcon(getThemedIcon(":/img/repeat-non.svg"))); - ui->pbRepeat->setText("Repeat Off"); - break; - case 1: - ui->pbRepeat->setIcon(QIcon(getThemedIcon(":/img/repeat-one.svg"))); - ui->pbRepeat->setText("Repeat One"); - break; - case 2: - ui->pbRepeat->setIcon(QIcon(getThemedIcon(":/img/repeat-all.svg"))); - ui->pbRepeat->setText("Repeat All"); - break; - } - delete plist; - } - ui->pbAdd->setIcon(QIcon(getThemedIcon(":/img/add.svg"))); - ui->pbRemove->setIcon(QIcon(getThemedIcon(":/img/remove.svg"))); - ui->pbClear->setIcon(QIcon(getThemedIcon(":/img/clear.svg"))); - ui->pbAddFolder->setIcon(QIcon(getThemedIcon(":/img/addfolder.svg"))); - ui->pbSave->setIcon(QIcon(getThemedIcon(":/img/save.svg"))); - ui->pbLoad->setIcon(QIcon(getThemedIcon(":/img/load.svg"))); - qmpMainWindow::getInstance()->registerFunctionality( - plistf=new qmpPlistFunc(this), - std::string("Playlist"), - tr("Playlist").toStdString(), - getThemedIconc(":/img/list.svg"), - 0, - true - ); - if(settings->getOptionRaw("DialogStatus/PListW",QRect(-999,-999,999,999)).toRect()!=QRect(-999,-999,999,999)) - setGeometry(settings->getOptionRaw("DialogStatus/PListW",QRect(-999,-999,999,999)).toRect()); - if(settings->getOptionRaw("DialogStatus/PListWShown",0).toInt()) - {show();qmpMainWindow::getInstance()->setFuncState("Playlist",true);} + ui->setupUi(this); + setButtonHeight(ui->pbAdd, 36); + setButtonHeight(ui->pbAddFolder, 36); + setButtonHeight(ui->pbClear, 36); + setButtonHeight(ui->pbLoad, 36); + setButtonHeight(ui->pbRemove, 36); + setButtonHeight(ui->pbRepeat, 36); + setButtonHeight(ui->pbSave, 36); + setButtonHeight(ui->pbShuffle, 36); + connect(this, &qmpPlistWindow::selectionChanging, (qmpMainWindow *)parent, &qmpMainWindow::selectionChanged); + repeat = 0; + shuffle = 0; + settings = qmpMainWindow::getInstance()->getSettings(); + if (settings->getOptionBool("Behavior/RestorePlaylist")) + { + QSettings *plist = new QSettings(QStandardPaths::writableLocation(QStandardPaths::StandardLocation::ConfigLocation) + QString("/qmpplist"), + QSettings::IniFormat); + int fc = plist->value("Playlist/FileCount", 0).toInt(); + ui->lwFiles->clear(); + for (int i = 0; i < fc; ++i) + ui->lwFiles->addItem(plist->value("Playlist/File" + QString("%1").arg(i, 5, 10, QChar('0')), "").toString()); + repeat = plist->value("Playlist/Repeat", 0).toInt(); + shuffle = plist->value("Playlist/Shuffle", 0).toInt(); + switch (shuffle) + { + case 1: + ui->pbShuffle->setIcon(QIcon(getThemedIcon(":/img/shuffle.svg"))); + ui->pbShuffle->setText("Shuffle On"); + break; + case 0: + default: + ui->pbShuffle->setIcon(QIcon(getThemedIcon(":/img/shuffle-off.svg"))); + ui->pbShuffle->setText("Shuffle Off"); + break; + } + switch (repeat) + { + case 0: + ui->pbRepeat->setIcon(QIcon(getThemedIcon(":/img/repeat-non.svg"))); + ui->pbRepeat->setText("Repeat Off"); + break; + case 1: + ui->pbRepeat->setIcon(QIcon(getThemedIcon(":/img/repeat-one.svg"))); + ui->pbRepeat->setText("Repeat One"); + break; + case 2: + ui->pbRepeat->setIcon(QIcon(getThemedIcon(":/img/repeat-all.svg"))); + ui->pbRepeat->setText("Repeat All"); + break; + } + delete plist; + } + ui->pbAdd->setIcon(QIcon(getThemedIcon(":/img/add.svg"))); + ui->pbRemove->setIcon(QIcon(getThemedIcon(":/img/remove.svg"))); + ui->pbClear->setIcon(QIcon(getThemedIcon(":/img/clear.svg"))); + ui->pbAddFolder->setIcon(QIcon(getThemedIcon(":/img/addfolder.svg"))); + ui->pbSave->setIcon(QIcon(getThemedIcon(":/img/save.svg"))); + ui->pbLoad->setIcon(QIcon(getThemedIcon(":/img/load.svg"))); + qmpMainWindow::getInstance()->registerFunctionality( + plistf = new qmpPlistFunc(this), + std::string("Playlist"), + tr("Playlist").toStdString(), + getThemedIconc(":/img/list.svg"), + 0, + true + ); + if (settings->getOptionRaw("DialogStatus/PListW", QRect(-999, -999, 999, 999)).toRect() != QRect(-999, -999, 999, 999)) + setGeometry(settings->getOptionRaw("DialogStatus/PListW", QRect(-999, -999, 999, 999)).toRect()); + if (settings->getOptionRaw("DialogStatus/PListWShown", 0).toInt()) + { + show(); + qmpMainWindow::getInstance()->setFuncState("Playlist", true); + } } qmpPlistWindow::~qmpPlistWindow() { - qmpMainWindow::getInstance()->unregisterFunctionality("Playlist"); - delete plistf; - delete ui; + qmpMainWindow::getInstance()->unregisterFunctionality("Playlist"); + delete plistf; + delete ui; } void qmpPlistWindow::showEvent(QShowEvent *event) { - if(settings->getOptionBool("Behavior/DialogStatus")) - { - settings->setOptionRaw("DialogStatus/PListWShown",1); - } - if(settings->getOptionRaw("DialogStatus/PListW",QRect(-999,-999,999,999)).toRect()!=QRect(-999,-999,999,999)) - setGeometry(settings->getOptionRaw("DialogStatus/PListW",QRect(-999,-999,999,999)).toRect()); - event->accept(); + if (settings->getOptionBool("Behavior/DialogStatus")) + { + settings->setOptionRaw("DialogStatus/PListWShown", 1); + } + if (settings->getOptionRaw("DialogStatus/PListW", QRect(-999, -999, 999, 999)).toRect() != QRect(-999, -999, 999, 999)) + setGeometry(settings->getOptionRaw("DialogStatus/PListW", QRect(-999, -999, 999, 999)).toRect()); + event->accept(); } void qmpPlistWindow::closeEvent(QCloseEvent *event) { - if(settings->getOptionBool("Behavior/DialogStatus")) - { - settings->setOptionRaw("DialogStatus/PListW",geometry()); - } - setVisible(false); - if(!qmpMainWindow::getInstance()->isFinalizing()) - while(ui->lwFiles->count()>1)delete ui->lwFiles->item(0); - if(!qmpMainWindow::getInstance()->isFinalizing()&&settings->getOptionBool("Behavior/DialogStatus")) - { - settings->setOptionRaw("DialogStatus/PListWShown",0); - } - if(qmpMainWindow::getInstance()->isFinalizing()&&settings->getOptionBool("Behavior/RestorePlaylist")) - { - QSettings* plist=new QSettings(QStandardPaths::writableLocation(QStandardPaths::StandardLocation::ConfigLocation)+QString("/qmpplist"), - QSettings::IniFormat); - plist->setValue("Playlist/FileCount",ui->lwFiles->count()); - for(int i=0;ilwFiles->count();++i) - plist->setValue("Playlist/File"+QString("%1").arg(i,5,10,QChar('0')),ui->lwFiles->item(i)->text()); - plist->setValue("Playlist/Repeat",repeat); - plist->setValue("Playlist/Shuffle",shuffle); - plist->sync(); - delete plist; - } - qmpMainWindow::getInstance()->setFuncState("Playlist",false); - event->accept(); + if (settings->getOptionBool("Behavior/DialogStatus")) + { + settings->setOptionRaw("DialogStatus/PListW", geometry()); + } + setVisible(false); + if (!qmpMainWindow::getInstance()->isFinalizing()) + while (ui->lwFiles->count() > 1) + delete ui->lwFiles->item(0); + if (!qmpMainWindow::getInstance()->isFinalizing() && settings->getOptionBool("Behavior/DialogStatus")) + { + settings->setOptionRaw("DialogStatus/PListWShown", 0); + } + if (qmpMainWindow::getInstance()->isFinalizing() && settings->getOptionBool("Behavior/RestorePlaylist")) + { + QSettings *plist = new QSettings(QStandardPaths::writableLocation(QStandardPaths::StandardLocation::ConfigLocation) + QString("/qmpplist"), + QSettings::IniFormat); + plist->setValue("Playlist/FileCount", ui->lwFiles->count()); + for (int i = 0; i < ui->lwFiles->count(); ++i) + plist->setValue("Playlist/File" + QString("%1").arg(i, 5, 10, QChar('0')), ui->lwFiles->item(i)->text()); + plist->setValue("Playlist/Repeat", repeat); + plist->setValue("Playlist/Shuffle", shuffle); + plist->sync(); + delete plist; + } + qmpMainWindow::getInstance()->setFuncState("Playlist", false); + event->accept(); } void qmpPlistWindow::dropEvent(QDropEvent *event) { - QList l=event->mimeData()->urls(); - QStringList sl; - for(int i=0;i l = event->mimeData()->urls(); + QStringList sl; + for (int i = 0; i < l.size(); ++i) + sl.push_back(l.at(i).toLocalFile()); + insertItems(sl); } void qmpPlistWindow::dragEnterEvent(QDragEnterEvent *event) { - //if(event->mimeData()->hasFormat("application/x-midi")) - event->acceptProposedAction(); + //if(event->mimeData()->hasFormat("application/x-midi")) + event->acceptProposedAction(); } void qmpPlistWindow::emptyList() { - ui->lwFiles->clear(); + ui->lwFiles->clear(); } void qmpPlistWindow::insertItem(QString i) { - ui->lwFiles->addItem(new QListWidgetItem(i)); + ui->lwFiles->addItem(new QListWidgetItem(i)); } void qmpPlistWindow::insertItems(QStringList il) { - ui->lwFiles->addItems(il); + ui->lwFiles->addItems(il); } int qmpPlistWindow::on_pbAdd_clicked() { - QStringList sl; - if(settings->getOptionBool("Behavior/DialogStatus")) - sl=QFileDialog::getOpenFileNames(this,"Add File",settings->getOptionRaw("DialogStatus/FileDialogPath","").toString(),"Midi files (*.mid *.midi)"); - else - sl=QFileDialog::getOpenFileNames(this,"Add File","","Midi files (*.mid *.midi *.rmi)"); - if(sl.empty())return 0; - for(int i=0;ilwFiles->addItem(new QListWidgetItem(sl.at(i))); - if(!isVisible())while(ui->lwFiles->count()>1)delete ui->lwFiles->item(0); - if(settings->getOptionBool("Behavior/DialogStatus")) - settings->setOptionRaw("DialogStatus/FileDialogPath", - QUrl(sl.at(0)).toString(QUrl::RemoveFilename)); - return 1; + QStringList sl; + if (settings->getOptionBool("Behavior/DialogStatus")) + sl = QFileDialog::getOpenFileNames(this, "Add File", settings->getOptionRaw("DialogStatus/FileDialogPath", "").toString(), "Midi files (*.mid *.midi)"); + else + sl = QFileDialog::getOpenFileNames(this, "Add File", "", "Midi files (*.mid *.midi *.rmi)"); + if (sl.empty()) + return 0; + for (int i = 0; i < sl.size(); ++i) + ui->lwFiles->addItem(new QListWidgetItem(sl.at(i))); + if (!isVisible()) + while (ui->lwFiles->count() > 1) + delete ui->lwFiles->item(0); + if (settings->getOptionBool("Behavior/DialogStatus")) + settings->setOptionRaw("DialogStatus/FileDialogPath", + QUrl(sl.at(0)).toString(QUrl::RemoveFilename)); + return 1; } void qmpPlistWindow::on_pbAddFolder_clicked() { - QDirIterator di(QFileDialog::getExistingDirectory(this,"Add Folder")); - while(di.hasNext()) - { - QString c=di.next(); - if((c.endsWith(".mid")||c.endsWith(".midi")||c.endsWith(".rmi"))&&fluid_is_midifile(c.toStdString().c_str())) - ui->lwFiles->addItem(new QListWidgetItem(c)); - } + QDirIterator di(QFileDialog::getExistingDirectory(this, "Add Folder")); + while (di.hasNext()) + { + QString c = di.next(); + if ((c.endsWith(".mid") || c.endsWith(".midi") || c.endsWith(".rmi")) && fluid_is_midifile(c.toStdString().c_str())) + ui->lwFiles->addItem(new QListWidgetItem(c)); + } } void qmpPlistWindow::on_pbRemove_clicked() { - QList sl=ui->lwFiles->selectedItems(); - for(int i=0;ilwFiles->removeItemWidget(sl.at(i)); - delete sl.at(i); - } + QList sl = ui->lwFiles->selectedItems(); + for (int i = 0; i < sl.size(); ++i) + { + ui->lwFiles->removeItemWidget(sl.at(i)); + delete sl.at(i); + } } void qmpPlistWindow::on_pbClear_clicked() { - while(ui->lwFiles->count()>0) - { - QListWidgetItem *d=ui->lwFiles->item(0); - ui->lwFiles->removeItemWidget(d); - delete d; - } + while (ui->lwFiles->count() > 0) + { + QListWidgetItem *d = ui->lwFiles->item(0); + ui->lwFiles->removeItemWidget(d); + delete d; + } } void qmpPlistWindow::on_pbRepeat_clicked() { - ++repeat;repeat%=3; - switch(repeat) - { - case 0: - ui->pbRepeat->setIcon(QIcon(getThemedIcon(":/img/repeat-non.svg"))); - ui->pbRepeat->setText(tr("Repeat Off")); - break; - case 1: - ui->pbRepeat->setIcon(QIcon(getThemedIcon(":/img/repeat-one.svg"))); - ui->pbRepeat->setText(tr("Repeat One")); - break; - case 2: - ui->pbRepeat->setIcon(QIcon(getThemedIcon(":/img/repeat-all.svg"))); - ui->pbRepeat->setText(tr("Repeat All")); - break; - } + ++repeat; + repeat %= 3; + switch (repeat) + { + case 0: + ui->pbRepeat->setIcon(QIcon(getThemedIcon(":/img/repeat-non.svg"))); + ui->pbRepeat->setText(tr("Repeat Off")); + break; + case 1: + ui->pbRepeat->setIcon(QIcon(getThemedIcon(":/img/repeat-one.svg"))); + ui->pbRepeat->setText(tr("Repeat One")); + break; + case 2: + ui->pbRepeat->setIcon(QIcon(getThemedIcon(":/img/repeat-all.svg"))); + ui->pbRepeat->setText(tr("Repeat All")); + break; + } } void qmpPlistWindow::on_pbShuffle_clicked() { - shuffle=1-shuffle; - switch(shuffle) - { - case 1: - ui->pbShuffle->setIcon(QIcon(getThemedIcon(":/img/shuffle.svg"))); - ui->pbShuffle->setText(tr("Shuffle On")); - break; - case 0: - default: - ui->pbShuffle->setIcon(QIcon(getThemedIcon(":/img/shuffle-off.svg"))); - ui->pbShuffle->setText(tr("Shuffle Off")); - break; - } + shuffle = 1 - shuffle; + switch (shuffle) + { + case 1: + ui->pbShuffle->setIcon(QIcon(getThemedIcon(":/img/shuffle.svg"))); + ui->pbShuffle->setText(tr("Shuffle On")); + break; + case 0: + default: + ui->pbShuffle->setIcon(QIcon(getThemedIcon(":/img/shuffle-off.svg"))); + ui->pbShuffle->setText(tr("Shuffle Off")); + break; + } } QString qmpPlistWindow::getFirstItem(bool a) { - if(ui->lwFiles->count()==0)return QString(); - int id=0; - if(shuffle&&!a)id=rand()%ui->lwFiles->count(); - ui->lwFiles->setCurrentRow(id); - return ui->lwFiles->item(id)->text(); + if (ui->lwFiles->count() == 0) + return QString(); + int id = 0; + if (shuffle && !a) + id = rand() % ui->lwFiles->count(); + ui->lwFiles->setCurrentRow(id); + return ui->lwFiles->item(id)->text(); } QString qmpPlistWindow::getLastItem(bool a) { - if(ui->lwFiles->count()==0)return QString(); - int id=ui->lwFiles->count()-1; - if(shuffle&&!a)id=rand()%ui->lwFiles->count(); - ui->lwFiles->setCurrentRow(id); - return ui->lwFiles->item(id)->text(); + if (ui->lwFiles->count() == 0) + return QString(); + int id = ui->lwFiles->count() - 1; + if (shuffle && !a) + id = rand() % ui->lwFiles->count(); + ui->lwFiles->setCurrentRow(id); + return ui->lwFiles->item(id)->text(); } QString qmpPlistWindow::getNextItem() { - if(ui->lwFiles->count()==0)return QString(); - if(repeat==1)return ui->lwFiles->item(ui->lwFiles->currentRow())->text(); - int id=ui->lwFiles->currentRow();++id;id%=ui->lwFiles->count(); - if(shuffle)id=rand()%ui->lwFiles->count(); - ui->lwFiles->setCurrentRow(id); - return ui->lwFiles->item(id)->text(); + if (ui->lwFiles->count() == 0) + return QString(); + if (repeat == 1) + return ui->lwFiles->item(ui->lwFiles->currentRow())->text(); + int id = ui->lwFiles->currentRow(); + ++id; + id %= ui->lwFiles->count(); + if (shuffle) + id = rand() % ui->lwFiles->count(); + ui->lwFiles->setCurrentRow(id); + return ui->lwFiles->item(id)->text(); } QString qmpPlistWindow::getPrevItem() { - if(ui->lwFiles->count()==0)return QString(); - if(repeat==1)return ui->lwFiles->item(ui->lwFiles->currentRow())->text(); - int id=ui->lwFiles->currentRow();--id; - id<0?id+=ui->lwFiles->count():0; - if(shuffle)id=rand()%ui->lwFiles->count(); - ui->lwFiles->setCurrentRow(id); - return ui->lwFiles->item(id)->text(); + if (ui->lwFiles->count() == 0) + return QString(); + if (repeat == 1) + return ui->lwFiles->item(ui->lwFiles->currentRow())->text(); + int id = ui->lwFiles->currentRow(); + --id; + id < 0 ? id += ui->lwFiles->count() : 0; + if (shuffle) + id = rand() % ui->lwFiles->count(); + ui->lwFiles->setCurrentRow(id); + return ui->lwFiles->item(id)->text(); } QString qmpPlistWindow::getSelectedItem() { - if(ui->lwFiles->count()==0)return QString(); - return ui->lwFiles->item(ui->lwFiles->currentRow())->text(); + if (ui->lwFiles->count() == 0) + return QString(); + return ui->lwFiles->item(ui->lwFiles->currentRow())->text(); +} +int qmpPlistWindow::getRepeat() +{ + return repeat; } -int qmpPlistWindow::getRepeat(){return repeat;} void qmpPlistWindow::on_lwFiles_itemDoubleClicked() { - emit selectionChanging(); + emit selectionChanging(); } void qmpPlistWindow::on_pbSave_clicked() { - QSettings* plist=new QSettings(QFileDialog::getSaveFileName(this,tr("Save playlist"),""), - QSettings::IniFormat); - plist->setValue("Playlist/FileCount",ui->lwFiles->count()); - for(int i=0;ilwFiles->count();++i) - plist->setValue("Playlist/File"+QString("%1").arg(i,5,10,QChar('0')),ui->lwFiles->item(i)->text()); - plist->setValue("Playlist/Repeat",repeat); - plist->setValue("Playlist/Shuffle",shuffle); - plist->sync(); - delete plist; + QSettings *plist = new QSettings(QFileDialog::getSaveFileName(this, tr("Save playlist"), ""), + QSettings::IniFormat); + plist->setValue("Playlist/FileCount", ui->lwFiles->count()); + for (int i = 0; i < ui->lwFiles->count(); ++i) + plist->setValue("Playlist/File" + QString("%1").arg(i, 5, 10, QChar('0')), ui->lwFiles->item(i)->text()); + plist->setValue("Playlist/Repeat", repeat); + plist->setValue("Playlist/Shuffle", shuffle); + plist->sync(); + delete plist; } void qmpPlistWindow::on_pbLoad_clicked() { - QSettings* plist=new QSettings(QFileDialog::getOpenFileName(this,tr("Load playlist"),""), - QSettings::IniFormat); - int fc=plist->value("Playlist/FileCount",0).toInt(); - if(!fc){delete plist;return;} - ui->lwFiles->clear();for(int i=0;ilwFiles->addItem(plist->value("Playlist/File"+QString("%1").arg(i,5,10,QChar('0')),"").toString()); - repeat=plist->value("Playlist/Repeat",0).toInt(); - shuffle=plist->value("Playlist/Shuffle",0).toInt(); - switch(shuffle) - { - case 1: - ui->pbShuffle->setIcon(QIcon(":/img/shuffle.svg")); - ui->pbShuffle->setText(tr("Shuffle On")); - break; - case 0: - default: - ui->pbShuffle->setIcon(QIcon(":/img/shuffle-off.svg")); - ui->pbShuffle->setText(tr("Shuffle Off")); - break; - } - switch(repeat) - { - case 0: - ui->pbRepeat->setIcon(QIcon(":/img/repeat-non.svg")); - ui->pbRepeat->setText(tr("Repeat Off")); - break; - case 1: - ui->pbRepeat->setIcon(QIcon(":/img/repeat-one.svg")); - ui->pbRepeat->setText(tr("Repeat One")); - break; - case 2: - ui->pbRepeat->setIcon(QIcon(":/img/repeat-all.svg")); - ui->pbRepeat->setText(tr("Repeat All")); - break; - } - delete plist; + QSettings *plist = new QSettings(QFileDialog::getOpenFileName(this, tr("Load playlist"), ""), + QSettings::IniFormat); + int fc = plist->value("Playlist/FileCount", 0).toInt(); + if (!fc) + { + delete plist; + return; + } + ui->lwFiles->clear(); + for (int i = 0; i < fc; ++i) + ui->lwFiles->addItem(plist->value("Playlist/File" + QString("%1").arg(i, 5, 10, QChar('0')), "").toString()); + repeat = plist->value("Playlist/Repeat", 0).toInt(); + shuffle = plist->value("Playlist/Shuffle", 0).toInt(); + switch (shuffle) + { + case 1: + ui->pbShuffle->setIcon(QIcon(":/img/shuffle.svg")); + ui->pbShuffle->setText(tr("Shuffle On")); + break; + case 0: + default: + ui->pbShuffle->setIcon(QIcon(":/img/shuffle-off.svg")); + ui->pbShuffle->setText(tr("Shuffle Off")); + break; + } + switch (repeat) + { + case 0: + ui->pbRepeat->setIcon(QIcon(":/img/repeat-non.svg")); + ui->pbRepeat->setText(tr("Repeat Off")); + break; + case 1: + ui->pbRepeat->setIcon(QIcon(":/img/repeat-one.svg")); + ui->pbRepeat->setText(tr("Repeat One")); + break; + case 2: + ui->pbRepeat->setIcon(QIcon(":/img/repeat-all.svg")); + ui->pbRepeat->setText(tr("Repeat All")); + break; + } + delete plist; } qmpPlistFunc::qmpPlistFunc(qmpPlistWindow *par) -{p=par;} +{ + p = par; +} void qmpPlistFunc::show() { - p->show(); + p->show(); } void qmpPlistFunc::close() { - p->close(); + p->close(); } diff --git a/qmidiplayer-desktop/qmpplistwindow.hpp b/qmidiplayer-desktop/qmpplistwindow.hpp index afd3ae3..7d93345 100644 --- a/qmidiplayer-desktop/qmpplistwindow.hpp +++ b/qmidiplayer-desktop/qmpplistwindow.hpp @@ -10,63 +10,64 @@ #include #include "../include/qmpcorepublic.hpp" -namespace Ui { - class qmpPlistWindow; +namespace Ui +{ +class qmpPlistWindow; } class qmpPlistWindow; class qmpSettings; -class qmpPlistFunc:public qmpFuncBaseIntf +class qmpPlistFunc: public qmpFuncBaseIntf { - private: - qmpPlistWindow* p; - public: - qmpPlistFunc(qmpPlistWindow *par); - void show(); - void close(); +private: + qmpPlistWindow *p; +public: + qmpPlistFunc(qmpPlistWindow *par); + void show(); + void close(); }; -class qmpPlistWindow:public QWidget +class qmpPlistWindow: public QWidget { - Q_OBJECT + Q_OBJECT - public: - explicit qmpPlistWindow(QWidget *parent=0); - ~qmpPlistWindow(); - void showEvent(QShowEvent *event); - void closeEvent(QCloseEvent *event); - void dropEvent(QDropEvent *event); - void dragEnterEvent(QDragEnterEvent *event); - int getRepeat(); - QString getFirstItem(bool a=false); - QString getLastItem(bool a=false); - QString getNextItem(); - QString getPrevItem(); - QString getSelectedItem(); - void emptyList(); - void insertItem(QString i); - void insertItems(QStringList il); - signals: - void selectionChanging(); +public: + explicit qmpPlistWindow(QWidget *parent = 0); + ~qmpPlistWindow(); + void showEvent(QShowEvent *event); + void closeEvent(QCloseEvent *event); + void dropEvent(QDropEvent *event); + void dragEnterEvent(QDragEnterEvent *event); + int getRepeat(); + QString getFirstItem(bool a = false); + QString getLastItem(bool a = false); + QString getNextItem(); + QString getPrevItem(); + QString getSelectedItem(); + void emptyList(); + void insertItem(QString i); + void insertItems(QStringList il); +signals: + void selectionChanging(); - public slots: - int on_pbAdd_clicked(); - private slots: - void on_pbAddFolder_clicked(); - void on_pbRemove_clicked(); - void on_pbClear_clicked(); - void on_pbRepeat_clicked(); - void on_pbShuffle_clicked(); - void on_lwFiles_itemDoubleClicked(); - void on_pbSave_clicked(); - void on_pbLoad_clicked(); +public slots: + int on_pbAdd_clicked(); +private slots: + void on_pbAddFolder_clicked(); + void on_pbRemove_clicked(); + void on_pbClear_clicked(); + void on_pbRepeat_clicked(); + void on_pbShuffle_clicked(); + void on_lwFiles_itemDoubleClicked(); + void on_pbSave_clicked(); + void on_pbLoad_clicked(); - private: - qmpPlistFunc* plistf; - Ui::qmpPlistWindow *ui; - int shuffle,repeat;//rep 0=off 1=one 2=all - qmpSettings* settings; +private: + qmpPlistFunc *plistf; + Ui::qmpPlistWindow *ui; + int shuffle, repeat; //rep 0=off 1=one 2=all + qmpSettings *settings; }; #endif // QMPPLISTWINDOW_H diff --git a/qmidiplayer-desktop/qmpplugin.cpp b/qmidiplayer-desktop/qmpplugin.cpp index 9cd1f35..cdea00c 100644 --- a/qmidiplayer-desktop/qmpplugin.cpp +++ b/qmidiplayer-desktop/qmpplugin.cpp @@ -9,265 +9,461 @@ #include "qmpplugin.hpp" #include "qmpmainwindow.hpp" #include "qmpsettingswindow.hpp" -qmpPluginAPIImpl* qmpPluginManager::pluginAPI=nullptr; -qmpMainWindow* qmpPluginManager::mainwindow=nullptr; +qmpPluginAPIImpl *qmpPluginManager::pluginAPI = nullptr; +qmpMainWindow *qmpPluginManager::mainwindow = nullptr; #ifdef _WIN32 #include #include std::string wstr2str(std::wstring s) { - std::wstring_convert,wchar_t> wsc; - return wsc.to_bytes(s); + std::wstring_convert, wchar_t> wsc; + return wsc.to_bytes(s); } void qmpPluginManager::scanPlugins(const std::vector &pp) { - QDirIterator *dir; - std::vector cpluginpaths; - std::wstring_convert,wchar_t> wsc; - for(auto p:pp)cpluginpaths.push_back(wsc.from_bytes(p)); - dir=new QDirIterator(QCoreApplication::applicationDirPath()+"/plugins/"); - while(dir->hasNext()) - { - dir->next(); - if(dir->fileInfo().suffix()=="dll") - cpluginpaths.push_back(QCoreApplication::applicationDirPath().toStdWString()+std::wstring(L"/plugins/")+dir->fileName().toStdWString()); - } - delete dir; - for(unsigned i=0;ipluginGetName()),std::string(intf->pluginGetVersion()),wstr2str(cpluginpaths[i]),intf)); - } + QDirIterator *dir; + std::vector cpluginpaths; + std::wstring_convert, wchar_t> wsc; + for (auto p : pp) + cpluginpaths.push_back(wsc.from_bytes(p)); + dir = new QDirIterator(QCoreApplication::applicationDirPath() + "/plugins/"); + while (dir->hasNext()) + { + dir->next(); + if (dir->fileInfo().suffix() == "dll") + cpluginpaths.push_back(QCoreApplication::applicationDirPath().toStdWString() + std::wstring(L"/plugins/") + dir->fileName().toStdWString()); + } + delete dir; + for (unsigned i = 0; i < cpluginpaths.size(); ++i) + { + HMODULE hso = LoadLibraryW(cpluginpaths[i].c_str()); + if (!hso) + { + fprintf(stderr, "Error while loading library: %d\n", GetLastError()); + continue; + } + FARPROC hndi = GetProcAddress(hso, "qmpPluginGetInterface"); + if (!hndi) + { + fprintf(stderr, "plugin %s doesn't seem to be a qmidiplayer plugin.\n", wstr2str(cpluginpaths[i]).c_str()); + continue; + } + FARPROC hndiv = GetProcAddress(hso, "qmpPluginGetAPIRev"); + if (!hndiv) + { + fprintf(stderr, "plugin %s is incompatible with this version of qmidiplayer.\n", wstr2str(cpluginpaths[i]).c_str()); + continue; + } + qmpPluginAPIRevEntry getv = (qmpPluginAPIRevEntry)hndiv; + if (strcmp(getv(), QMP_PLUGIN_API_REV)) + { + fprintf(stderr, "plugin %s is incompatible with this version of qmidiplayer.\n", wstr2str(cpluginpaths[i]).c_str()); + continue; + } + qmpPluginEntry e = (qmpPluginEntry)hndi; + qmpPluginIntf *intf = e(pluginAPI); + plugins.push_back(qmpPlugin(std::string(intf->pluginGetName()), std::string(intf->pluginGetVersion()), wstr2str(cpluginpaths[i]), intf)); + } } #else void qmpPluginManager::scanPlugins(const std::vector &pp) { - QDirIterator *dir; - std::vector cpluginpaths(pp); + QDirIterator *dir; + std::vector cpluginpaths(pp); #ifdef NON_PORTABLE - QString pdir=QString(QT_STRINGIFY(INSTALL_PREFIX))+"/lib/qmidiplayer/"; - dir=new QDirIterator(pdir); - while(dir->hasNext()) - { - dir->next(); - if(dir->fileInfo().suffix()=="so") - cpluginpaths.push_back((pdir+dir->fileName()).toStdString()); - } - delete dir; + QString pdir = QString(QT_STRINGIFY(INSTALL_PREFIX)) + "/lib/qmidiplayer/"; + dir = new QDirIterator(pdir); + while (dir->hasNext()) + { + dir->next(); + if (dir->fileInfo().suffix() == "so") + cpluginpaths.push_back((pdir + dir->fileName()).toStdString()); + } + delete dir; #endif - dir=new QDirIterator(QCoreApplication::applicationDirPath()+"/plugins/"); - while(dir->hasNext()) - { - dir->next(); - if(dir->fileInfo().suffix()=="so") - cpluginpaths.push_back(QCoreApplication::applicationDirPath().toStdString()+std::string("/plugins/")+dir->fileName().toStdString()); - } - delete dir; - for(unsigned i=0;ipluginGetName()),std::string(intf->pluginGetVersion()),std::string(cpluginpaths[i]),intf)); - } + dir = new QDirIterator(QCoreApplication::applicationDirPath() + "/plugins/"); + while (dir->hasNext()) + { + dir->next(); + if (dir->fileInfo().suffix() == "so") + cpluginpaths.push_back(QCoreApplication::applicationDirPath().toStdString() + std::string("/plugins/") + dir->fileName().toStdString()); + } + delete dir; + for (unsigned i = 0; i < cpluginpaths.size(); ++i) + { + void *hso = dlopen(cpluginpaths[i].c_str(), RTLD_LAZY); + if (!hso) + { + fprintf(stderr, "%s\n", dlerror()); + continue; + } + void *hndi = dlsym(hso, "qmpPluginGetInterface"); + if (!hndi) + { + fprintf(stderr, "file %s doesn't seem to be a qmidiplayer plugin.\n", cpluginpaths[i].c_str()); + continue; + } + void *hndiv = dlsym(hso, "qmpPluginGetAPIRev"); + if (!hndiv) + { + fprintf(stderr, "file %s is incompatible with this version of qmidiplayer.\n", cpluginpaths[i].c_str()); + continue; + } + qmpPluginAPIRevEntry getv = (qmpPluginAPIRevEntry)hndiv; + if (strcmp(getv(), QMP_PLUGIN_API_REV)) + { + fprintf(stderr, "file %s is incompatible with this version of qmidiplayer.\n", cpluginpaths[i].c_str()); + continue; + } + qmpPluginEntry e = (qmpPluginEntry)hndi; + qmpPluginIntf *intf = e(pluginAPI); + plugins.push_back(qmpPlugin(std::string(intf->pluginGetName()), std::string(intf->pluginGetVersion()), std::string(cpluginpaths[i]), intf)); + } } #endif qmpPluginManager::qmpPluginManager() { - mainwindow=qmpMainWindow::getInstance(); - pluginAPI=new qmpPluginAPIImpl(); + mainwindow = qmpMainWindow::getInstance(); + pluginAPI = new qmpPluginAPIImpl(); } qmpPluginManager::~qmpPluginManager() { - for(unsigned i=0;ideinit(); - delete plugins[i].pinterface; - } - mainwindow=nullptr;delete pluginAPI; + for (unsigned i = 0; i < plugins.size(); ++i) + { + if (plugins[i].initialized) + plugins[i].pinterface->deinit(); + delete plugins[i].pinterface; + } + mainwindow = nullptr; + delete pluginAPI; } std::vector *qmpPluginManager::getPlugins() { - return &plugins; + return &plugins; } void qmpPluginManager::initPlugins() { - for(unsigned i=0;iinit();plugins[i].initialized=true; - } + for (unsigned i = 0; i < plugins.size(); ++i) + { + if (!plugins[i].enabled) + continue; + fprintf(stderr, "Loaded plugin: %s\n", plugins[i].path.c_str()); + plugins[i].pinterface->init(); + plugins[i].initialized = true; + } } void qmpPluginManager::deinitPlugins() { - for(unsigned i=0;ideinit(); - plugins[i].enabled=plugins[i].initialized=false; - } + for (unsigned i = 0; i < plugins.size(); ++i) + { + if (plugins[i].initialized) + plugins[i].pinterface->deinit(); + plugins[i].enabled = plugins[i].initialized = false; + } } -qmpPluginAPIImpl::qmpPluginAPIImpl(){} -qmpPluginAPIImpl::~qmpPluginAPIImpl(){} +qmpPluginAPIImpl::qmpPluginAPIImpl() {} +qmpPluginAPIImpl::~qmpPluginAPIImpl() {} #define qmw qmpPluginManager::mainwindow uint32_t qmpPluginAPIImpl::getDivision() -{return qmw&&qmw->getPlayer()?qmw->getPlayer()->getDivision():0;} +{ + return qmw && qmw->getPlayer() ? qmw->getPlayer()->getDivision() : 0; +} uint32_t qmpPluginAPIImpl::getRawTempo() -{return qmw&&qmw->getPlayer()?qmw->getPlayer()->getRawTempo():0;} +{ + return qmw && qmw->getPlayer() ? qmw->getPlayer()->getRawTempo() : 0; +} double qmpPluginAPIImpl::getRealTempo() -{return qmw&&qmw->getPlayer()?qmw->getPlayer()->getTempo():0;} +{ + return qmw && qmw->getPlayer() ? qmw->getPlayer()->getTempo() : 0; +} uint32_t qmpPluginAPIImpl::getTimeSig() -{int n,d=0,t;qmw&&qmw->getPlayer()?qmw->getPlayer()->getCurrentTimeSignature(&n,&t):void(0);for(;t>>=1;++d);return n<<8|d;} +{ + int n, d = 0, t; + qmw &&qmw->getPlayer() ? qmw->getPlayer()->getCurrentTimeSignature(&n, &t) : void(0); + for (; t >>= 1; ++d); + return n << 8 | d; +} int qmpPluginAPIImpl::getKeySig() -{return qmw&&qmw->getPlayer()?qmw->getPlayer()->getCurrentKeySignature():0;} +{ + return qmw && qmw->getPlayer() ? qmw->getPlayer()->getCurrentKeySignature() : 0; +} uint32_t qmpPluginAPIImpl::getNoteCount() -{return qmw&&qmw->getPlayer()?qmw->getPlayer()->getFileNoteCount():0;} +{ + return qmw && qmw->getPlayer() ? qmw->getPlayer()->getFileNoteCount() : 0; +} uint32_t qmpPluginAPIImpl::getMaxTick() -{return qmw&&qmw->getPlayer()?qmw->getPlayer()->getMaxTick():0;} +{ + return qmw && qmw->getPlayer() ? qmw->getPlayer()->getMaxTick() : 0; +} uint32_t qmpPluginAPIImpl::getCurrentPolyphone() -{return qmw&&qmw->getPlayer()?qmw->getFluid()->getPolyphone():0;} +{ + return qmw && qmw->getPlayer() ? qmw->getFluid()->getPolyphone() : 0; +} uint32_t qmpPluginAPIImpl::getMaxPolyphone() -{return qmw&&qmw->getPlayer()?qmw->getFluid()->getMaxPolyphone():0;} +{ + return qmw && qmw->getPlayer() ? qmw->getFluid()->getMaxPolyphone() : 0; +} uint32_t qmpPluginAPIImpl::getCurrentTimeStamp() -{return qmw&&qmw->getPlayer()?qmw->getPlayer()->getTick():0;} +{ + return qmw && qmw->getPlayer() ? qmw->getPlayer()->getTick() : 0; +} uint32_t qmpPluginAPIImpl::getCurrentPlaybackPercentage() -{return qmw?qmw->getPlaybackPercentage():0;} -int qmpPluginAPIImpl::getChannelCC(int ch,int cc) -{return qmw&&qmw->getPlayer()?qmw->getPlayer()->getCC(ch,cc):0;} +{ + return qmw ? qmw->getPlaybackPercentage() : 0; +} +int qmpPluginAPIImpl::getChannelCC(int ch, int cc) +{ + return qmw && qmw->getPlayer() ? qmw->getPlayer()->getCC(ch, cc) : 0; +} int qmpPluginAPIImpl::getChannelPreset(int ch) { - uint16_t b;uint8_t p;std::string nm; - if(qmw&&qmw->getPlayer()) - { - if(qmw->getPlayer()->getChannelOutputDevice(ch)->getChannelPreset(ch,&b,&p,nm))return p; - return qmw->getPlayer()->getCC(ch,128); - } - return 0; + uint16_t b; + uint8_t p; + std::string nm; + if (qmw && qmw->getPlayer()) + { + if (qmw->getPlayer()->getChannelOutputDevice(ch)->getChannelPreset(ch, &b, &p, nm)) + return p; + return qmw->getPlayer()->getCC(ch, 128); + } + return 0; } void qmpPluginAPIImpl::playerSeek(uint32_t percentage) -{if(qmw)qmw->playerSeek(percentage);} +{ + if (qmw) + qmw->playerSeek(percentage); +} double qmpPluginAPIImpl::getPitchBend(int ch) -{return qmw&&qmw->getPlayer()?qmw->getPlayer()->getPitchBend(ch):0;} -void qmpPluginAPIImpl::getPitchBendRaw(int ch,uint32_t *pb,uint32_t *pbr) { - if(qmw&&qmw->getPlayer()) - qmw->getPlayer()->getPitchBendRaw(ch,pb,pbr); + return qmw && qmw->getPlayer() ? qmw->getPlayer()->getPitchBend(ch) : 0; +} +void qmpPluginAPIImpl::getPitchBendRaw(int ch, uint32_t *pb, uint32_t *pbr) +{ + if (qmw && qmw->getPlayer()) + qmw->getPlayer()->getPitchBendRaw(ch, pb, pbr); } bool qmpPluginAPIImpl::getChannelMask(int ch) -{return qmw&&qmw->getPlayer()?qmw->getPlayer()->getChannelMask(ch):false;} +{ + return qmw && qmw->getPlayer() ? qmw->getPlayer()->getChannelMask(ch) : false; +} std::string qmpPluginAPIImpl::getTitle() -{return qmw?qmw->getTitle():"";} +{ + return qmw ? qmw->getTitle() : ""; +} std::wstring qmpPluginAPIImpl::getWTitle() -{return qmw?qmw->getWTitle():L"";} +{ + return qmw ? qmw->getWTitle() : L""; +} std::string qmpPluginAPIImpl::getChannelPresetString(int ch) { - uint16_t b;uint8_t p;char ret[320];ret[0]=0; - std::string nm; - if(qmw&&qmw->getPlayer()) - { - int r=qmw->getPlayer()->getChannelOutputDevice(ch)->getChannelPreset(ch,&b,&p,nm); - if(!r) - { - b=qmw->getPlayer()->getCC(ch,0)<<7|qmw->getPlayer()->getCC(ch,32); - p=qmw->getPlayer()->getCC(ch,128); - nm=qmw->getPlayer()->getChannelOutputDevice(ch)->getPresetName(b,p); - } - snprintf(ret,320,"%03d:%03d %s",b,p,nm.c_str()); - } - return std::string(ret); -} -bool qmpPluginAPIImpl::isDarkTheme(){return qmw?qmw->isDarkTheme():false;} -void* qmpPluginAPIImpl::getMainWindow(){return (void*)qmw;} + uint16_t b; + uint8_t p; + char ret[320]; + ret[0] = 0; + std::string nm; + if (qmw && qmw->getPlayer()) + { + int r = qmw->getPlayer()->getChannelOutputDevice(ch)->getChannelPreset(ch, &b, &p, nm); + if (!r) + { + b = qmw->getPlayer()->getCC(ch, 0) << 7 | qmw->getPlayer()->getCC(ch, 32); + p = qmw->getPlayer()->getCC(ch, 128); + nm = qmw->getPlayer()->getChannelOutputDevice(ch)->getPresetName(b, p); + } + snprintf(ret, 320, "%03d:%03d %s", b, p, nm.c_str()); + } + return std::string(ret); +} +bool qmpPluginAPIImpl::isDarkTheme() +{ + return qmw ? qmw->isDarkTheme() : false; +} +void *qmpPluginAPIImpl::getMainWindow() +{ + return (void *)qmw; +} -void qmpPluginAPIImpl::discardCurrentEvent(){if(qmw&&qmw->getPlayer())qmw->getPlayer()->discardCurrentEvent();} -void qmpPluginAPIImpl::commitEventChange(SEvent d){if(qmw&&qmw->getPlayer())qmw->getPlayer()->commitEventChange(d);} -void qmpPluginAPIImpl::callEventReaderCB(SEvent d){if(qmw&&qmw->getPlayer())qmw->getPlayer()->callEventReaderCB(d);} -void qmpPluginAPIImpl::setFuncState(std::string name,bool state){if(qmw)qmw->setFuncState(name,state);} -void qmpPluginAPIImpl::setFuncEnabled(std::string name,bool enable){if(qmw)qmw->setFuncEnabled(name,enable);} +void qmpPluginAPIImpl::discardCurrentEvent() +{ + if (qmw && qmw->getPlayer()) + qmw->getPlayer()->discardCurrentEvent(); +} +void qmpPluginAPIImpl::commitEventChange(SEvent d) +{ + if (qmw && qmw->getPlayer()) + qmw->getPlayer()->commitEventChange(d); +} +void qmpPluginAPIImpl::callEventReaderCB(SEvent d) +{ + if (qmw && qmw->getPlayer()) + qmw->getPlayer()->callEventReaderCB(d); +} +void qmpPluginAPIImpl::setFuncState(std::string name, bool state) +{ + if (qmw) + qmw->setFuncState(name, state); +} +void qmpPluginAPIImpl::setFuncEnabled(std::string name, bool enable) +{ + if (qmw) + qmw->setFuncEnabled(name, enable); +} void qmpPluginAPIImpl::registerMidiOutDevice(qmpMidiOutDevice *dev, std::string name) -{qmw->getPlayer()->registerMidiOutDevice(dev,name);} +{ + qmw->getPlayer()->registerMidiOutDevice(dev, name); +} void qmpPluginAPIImpl::unregisterMidiOutDevice(std::string name) -{qmw->getPlayer()->unregisterMidiOutDevice(name);} -int qmpPluginAPIImpl::registerEventHandlerIntf(ICallBack *cb,void *userdata) -{return qmw->getPlayer()->setEventHandlerCB(cb,userdata);} +{ + qmw->getPlayer()->unregisterMidiOutDevice(name); +} +int qmpPluginAPIImpl::registerEventHandlerIntf(ICallBack *cb, void *userdata) +{ + return qmw->getPlayer()->setEventHandlerCB(cb, userdata); +} void qmpPluginAPIImpl::unregisterEventHandlerIntf(int intfhandle) -{qmw->getPlayer()->unsetEventHandlerCB(intfhandle);} -int qmpPluginAPIImpl::registerEventReaderIntf(ICallBack *cb,void *userdata) -{return qmw->getPlayer()->setEventReaderCB(cb,userdata);} +{ + qmw->getPlayer()->unsetEventHandlerCB(intfhandle); +} +int qmpPluginAPIImpl::registerEventReaderIntf(ICallBack *cb, void *userdata) +{ + return qmw->getPlayer()->setEventReaderCB(cb, userdata); +} void qmpPluginAPIImpl::unregisterEventReaderIntf(int intfhandle) -{qmw->getPlayer()->unsetEventReaderCB(intfhandle);} -int qmpPluginAPIImpl::registerUIHook(std::string e,ICallBack* cb,void* userdat) -{return qmw->registerUIHook(e,cb,userdat);} -int qmpPluginAPIImpl::registerUIHook(std::string e,callback_t cb,void* userdat) -{return qmw->registerUIHook(e,cb,userdat);} -void qmpPluginAPIImpl::unregisterUIHook(std::string e,int hook) -{qmw->unregisterUIHook(e,hook);} -void qmpPluginAPIImpl::registerFunctionality(qmpFuncBaseIntf *i,std::string name,std::string desc,const char *icon,int iconlen,bool checkable) -{qmw->registerFunctionality(i,name,desc,icon,iconlen,checkable);} +{ + qmw->getPlayer()->unsetEventReaderCB(intfhandle); +} +int qmpPluginAPIImpl::registerUIHook(std::string e, ICallBack *cb, void *userdat) +{ + return qmw->registerUIHook(e, cb, userdat); +} +int qmpPluginAPIImpl::registerUIHook(std::string e, callback_t cb, void *userdat) +{ + return qmw->registerUIHook(e, cb, userdat); +} +void qmpPluginAPIImpl::unregisterUIHook(std::string e, int hook) +{ + qmw->unregisterUIHook(e, hook); +} +void qmpPluginAPIImpl::registerFunctionality(qmpFuncBaseIntf *i, std::string name, std::string desc, const char *icon, int iconlen, bool checkable) +{ + qmw->registerFunctionality(i, name, desc, icon, iconlen, checkable); +} void qmpPluginAPIImpl::unregisterFunctionality(std::string name) -{qmw->unregisterFunctionality(name);} -int qmpPluginAPIImpl::registerFileReadFinishedHandlerIntf(ICallBack* cb,void* userdata) -{return qmw->getPlayer()->setFileReadFinishedCB(cb,userdata);} +{ + qmw->unregisterFunctionality(name); +} +int qmpPluginAPIImpl::registerFileReadFinishedHandlerIntf(ICallBack *cb, void *userdata) +{ + return qmw->getPlayer()->setFileReadFinishedCB(cb, userdata); +} void qmpPluginAPIImpl::unregisterFileReadFinishedHandlerIntf(int intfhandle) -{qmw->getPlayer()->unsetFileReadFinishedCB(intfhandle);} -void qmpPluginAPIImpl::registerFileReader(qmpFileReader* reader,std::string name) -{qmw->getPlayer()->registerReader(reader,name);} +{ + qmw->getPlayer()->unsetFileReadFinishedCB(intfhandle); +} +void qmpPluginAPIImpl::registerFileReader(qmpFileReader *reader, std::string name) +{ + qmw->getPlayer()->registerReader(reader, name); +} void qmpPluginAPIImpl::unregisterFileReader(std::string name) -{qmw->getPlayer()->unregisterReader(name);} -int qmpPluginAPIImpl::registerEventHandler(callback_t cb,void *userdata,bool post) -{return qmw->getPlayer()->registerEventHandler(cb,userdata,post);} +{ + qmw->getPlayer()->unregisterReader(name); +} +int qmpPluginAPIImpl::registerEventHandler(callback_t cb, void *userdata, bool post) +{ + return qmw->getPlayer()->registerEventHandler(cb, userdata, post); +} void qmpPluginAPIImpl::unregisterEventHandler(int id) -{qmw->getPlayer()->unregisterEventHandler(id);} -int qmpPluginAPIImpl::registerEventReadHandler(callback_t cb,void *userdata) -{return qmw->getPlayer()->registerEventReadHandler(cb,userdata);} +{ + qmw->getPlayer()->unregisterEventHandler(id); +} +int qmpPluginAPIImpl::registerEventReadHandler(callback_t cb, void *userdata) +{ + return qmw->getPlayer()->registerEventReadHandler(cb, userdata); +} void qmpPluginAPIImpl::unregisterEventReadHandler(int id) -{qmw->getPlayer()->unregisterEventReadHandler(id);} -int qmpPluginAPIImpl::registerFileReadFinishHook(callback_t cb,void *userdata) -{return qmw->getPlayer()->registerFileReadFinishHook(cb,userdata);} +{ + qmw->getPlayer()->unregisterEventReadHandler(id); +} +int qmpPluginAPIImpl::registerFileReadFinishHook(callback_t cb, void *userdata) +{ + return qmw->getPlayer()->registerFileReadFinishHook(cb, userdata); +} void qmpPluginAPIImpl::unregisterFileReadFinishHook(int id) -{qmw->getPlayer()->unregisterFileReadFinishHook(id);} +{ + qmw->getPlayer()->unregisterFileReadFinishHook(id); +} -void qmpPluginAPIImpl::registerOptionInt(std::string tab,std::string desc,std::string key,int min,int max,int defaultval) -{qmw->getSettings()->registerOptionInt(tab,desc,key,min,max,defaultval);} -int qmpPluginAPIImpl::getOptionInt(std::string key){return qmw->getSettings()->getOptionInt(key);} -void qmpPluginAPIImpl::setOptionInt(std::string key,int val){qmw->getSettings()->setOptionInt(key,val);} -void qmpPluginAPIImpl::registerOptionUint(std::string tab,std::string desc,std::string key,unsigned min,unsigned max,unsigned defaultval) -{qmw->getSettings()->registerOptionUint(tab,desc,key,min,max,defaultval);} -unsigned qmpPluginAPIImpl::getOptionUint(std::string key){return qmw->getSettings()->getOptionUint(key);} -void qmpPluginAPIImpl::setOptionUint(std::string key,unsigned val){qmw->getSettings()->setOptionUint(key,val);} -void qmpPluginAPIImpl::registerOptionBool(std::string tab,std::string desc,std::string key,bool defaultval) -{qmw->getSettings()->registerOptionBool(tab,desc,key,defaultval);} -bool qmpPluginAPIImpl::getOptionBool(std::string key){return qmw->getSettings()->getOptionBool(key);} -void qmpPluginAPIImpl::setOptionBool(std::string key,bool val){qmw->getSettings()->setOptionBool(key,val);} -void qmpPluginAPIImpl::registerOptionDouble(std::string tab,std::string desc,std::string key,double min,double max,double defaultval) -{qmw->getSettings()->registerOptionDouble(tab,desc,key,min,max,defaultval);} -double qmpPluginAPIImpl::getOptionDouble(std::string key){return qmw->getSettings()->getOptionDouble(key);} -void qmpPluginAPIImpl::setOptionDouble(std::string key,double val){qmw->getSettings()->setOptionDouble(key,val);} -void qmpPluginAPIImpl::registerOptionString(std::string tab,std::string desc,std::string key,std::string defaultval,bool ispath) -{qmw->getSettings()->registerOptionString(tab,desc,key,defaultval,ispath);} -std::string qmpPluginAPIImpl::getOptionString(std::string key){return qmw->getSettings()->getOptionString(key);} -void qmpPluginAPIImpl::setOptionString(std::string key,std::string val){return qmw->getSettings()->setOptionString(key,val);} -void qmpPluginAPIImpl::registerOptionEnumInt(std::string tab,std::string desc,std::string key,std::vector options,int defaultval) -{qmw->getSettings()->registerOptionEnumInt(tab,desc,key,options,defaultval);} -int qmpPluginAPIImpl::getOptionEnumInt(std::string key){return qmw->getSettings()->getOptionEnumInt(key);} -void qmpPluginAPIImpl::setOptionEnumInt(std::string key,int val){return qmw->getSettings()->setOptionEnumInt(key,val);} +void qmpPluginAPIImpl::registerOptionInt(std::string tab, std::string desc, std::string key, int min, int max, int defaultval) +{ + qmw->getSettings()->registerOptionInt(tab, desc, key, min, max, defaultval); +} +int qmpPluginAPIImpl::getOptionInt(std::string key) +{ + return qmw->getSettings()->getOptionInt(key); +} +void qmpPluginAPIImpl::setOptionInt(std::string key, int val) +{ + qmw->getSettings()->setOptionInt(key, val); +} +void qmpPluginAPIImpl::registerOptionUint(std::string tab, std::string desc, std::string key, unsigned min, unsigned max, unsigned defaultval) +{ + qmw->getSettings()->registerOptionUint(tab, desc, key, min, max, defaultval); +} +unsigned qmpPluginAPIImpl::getOptionUint(std::string key) +{ + return qmw->getSettings()->getOptionUint(key); +} +void qmpPluginAPIImpl::setOptionUint(std::string key, unsigned val) +{ + qmw->getSettings()->setOptionUint(key, val); +} +void qmpPluginAPIImpl::registerOptionBool(std::string tab, std::string desc, std::string key, bool defaultval) +{ + qmw->getSettings()->registerOptionBool(tab, desc, key, defaultval); +} +bool qmpPluginAPIImpl::getOptionBool(std::string key) +{ + return qmw->getSettings()->getOptionBool(key); +} +void qmpPluginAPIImpl::setOptionBool(std::string key, bool val) +{ + qmw->getSettings()->setOptionBool(key, val); +} +void qmpPluginAPIImpl::registerOptionDouble(std::string tab, std::string desc, std::string key, double min, double max, double defaultval) +{ + qmw->getSettings()->registerOptionDouble(tab, desc, key, min, max, defaultval); +} +double qmpPluginAPIImpl::getOptionDouble(std::string key) +{ + return qmw->getSettings()->getOptionDouble(key); +} +void qmpPluginAPIImpl::setOptionDouble(std::string key, double val) +{ + qmw->getSettings()->setOptionDouble(key, val); +} +void qmpPluginAPIImpl::registerOptionString(std::string tab, std::string desc, std::string key, std::string defaultval, bool ispath) +{ + qmw->getSettings()->registerOptionString(tab, desc, key, defaultval, ispath); +} +std::string qmpPluginAPIImpl::getOptionString(std::string key) +{ + return qmw->getSettings()->getOptionString(key); +} +void qmpPluginAPIImpl::setOptionString(std::string key, std::string val) +{ + return qmw->getSettings()->setOptionString(key, val); +} +void qmpPluginAPIImpl::registerOptionEnumInt(std::string tab, std::string desc, std::string key, std::vector options, int defaultval) +{ + qmw->getSettings()->registerOptionEnumInt(tab, desc, key, options, defaultval); +} +int qmpPluginAPIImpl::getOptionEnumInt(std::string key) +{ + return qmw->getSettings()->getOptionEnumInt(key); +} +void qmpPluginAPIImpl::setOptionEnumInt(std::string key, int val) +{ + return qmw->getSettings()->setOptionEnumInt(key, val); +} diff --git a/qmidiplayer-desktop/qmpplugin.hpp b/qmidiplayer-desktop/qmpplugin.hpp index 99dedcd..778f90f 100644 --- a/qmidiplayer-desktop/qmpplugin.hpp +++ b/qmidiplayer-desktop/qmpplugin.hpp @@ -7,104 +7,110 @@ #include "../include/qmpcorepublic.hpp" struct qmpPlugin { - std::string name,version,path; - qmpPluginIntf* pinterface; - bool enabled,initialized; - qmpPlugin(std::string _n,std::string _v,std::string _p,qmpPluginIntf* _i) - {name=_n;version=_v;path=_p;pinterface=_i;enabled=initialized=false;} + std::string name, version, path; + qmpPluginIntf *pinterface; + bool enabled, initialized; + qmpPlugin(std::string _n, std::string _v, std::string _p, qmpPluginIntf *_i) + { + name = _n; + version = _v; + path = _p; + pinterface = _i; + enabled = initialized = false; + } }; class qmpMainWindow; class qmpSettings; -class qmpPluginAPIImpl:public qmpPluginAPI +class qmpPluginAPIImpl: public qmpPluginAPI { public: - qmpPluginAPIImpl(); - ~qmpPluginAPIImpl(); - 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(); + qmpPluginAPIImpl(); + ~qmpPluginAPIImpl(); + 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 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 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); + 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); }; class qmpPluginManager { - private: - std::vector plugins; - static qmpPluginAPIImpl* pluginAPI; - static qmpMainWindow* mainwindow; - static qmpSettings* settings; - public: - qmpPluginManager(); - ~qmpPluginManager(); - std::vector *getPlugins(); - void scanPlugins(const std::vector &pp); - void initPlugins(); - void deinitPlugins(); - friend class qmpPluginAPIImpl; - friend class qmpMainWindow; +private: + std::vector plugins; + static qmpPluginAPIImpl *pluginAPI; + static qmpMainWindow *mainwindow; + static qmpSettings *settings; +public: + qmpPluginManager(); + ~qmpPluginManager(); + std::vector *getPlugins(); + void scanPlugins(const std::vector &pp); + void initPlugins(); + void deinitPlugins(); + friend class qmpPluginAPIImpl; + friend class qmpMainWindow; }; #endif // QMPPLUGIN_H diff --git a/qmidiplayer-desktop/qmppresetselect.cpp b/qmidiplayer-desktop/qmppresetselect.cpp index 821eced..51bb7d4 100644 --- a/qmidiplayer-desktop/qmppresetselect.cpp +++ b/qmidiplayer-desktop/qmppresetselect.cpp @@ -4,132 +4,153 @@ #include "qmpmainwindow.hpp" qmpPresetSelector::qmpPresetSelector(QWidget *parent) : - QDialog(parent), - ui(new Ui::qmpPresetSelector) + QDialog(parent), + ui(new Ui::qmpPresetSelector) { - ui->setupUi(this); + ui->setupUi(this); } qmpPresetSelector::~qmpPresetSelector() { - delete ui; + delete ui; } void qmpPresetSelector::showEvent(QShowEvent *e) { - memset(presets,0,sizeof(presets)); - if(!qmpMainWindow::getInstance()->getFluid()->getSFCount())return e->ignore(); - ui->lwBankSelect->clear(); - ui->lwPresetSelect->clear(); - e->accept(); + memset(presets, 0, sizeof(presets)); + if (!qmpMainWindow::getInstance()->getFluid()->getSFCount()) + return e->ignore(); + ui->lwBankSelect->clear(); + ui->lwPresetSelect->clear(); + e->accept(); } void qmpPresetSelector::setupWindow(int chid) { - CMidiPlayer *plyr=qmpMainWindow::getInstance()->getPlayer(); - ch=chid;int r;char name[256]; - uint16_t b;uint8_t p; - std::string pstname; - sprintf(name,"Preset Selection - Channel #%d",ch+1); - setWindowTitle(name); - r=plyr->getChannelOutputDevice(ch)->getChannelPreset(ch,&b,&p,pstname); - if(!r){b=plyr->getCC(ch,0)<<7|plyr->getCC(ch,32);p=plyr->getCC(ch,128);} - ui->lwBankSelect->blockSignals(true); - ui->lwBankSelect->clear(); - ui->lwPresetSelect->clear(); - ui->lwBankSelect->blockSignals(false); - if(plyr->getChannelOutputDevice(ch)->getBankList().empty()){ - ui->lwPresetSelect->setEnabled(false); - ui->lwBankSelect->setEnabled(false); - ui->spCustomLSB->setEnabled(true); - ui->spCustomMSB->setEnabled(true); - ui->spCustomPC->setEnabled(true); - ui->spCustomMSB->setValue(plyr->getCC(chid,0)); - ui->spCustomLSB->setValue(plyr->getCC(chid,32)); - ui->spCustomPC->setValue(p); - } - else{ - ui->lwPresetSelect->setEnabled(true); - ui->lwBankSelect->setEnabled(true); - ui->spCustomLSB->setEnabled(false); - ui->spCustomMSB->setEnabled(false); - ui->spCustomPC->setEnabled(false); - ui->lwBankSelect->blockSignals(true); - for(auto&i:plyr->getChannelOutputDevice(ch)->getBankList()) - { - snprintf(name,256,"%03d %s",i.first,i.second.c_str()); - ui->lwBankSelect->addItem(name); - if(i.first==b)ui->lwBankSelect->setCurrentRow(ui->lwBankSelect->count()-1); - } - ui->lwBankSelect->blockSignals(false); - for(auto&i:plyr->getChannelOutputDevice(ch)->getPresets(b)) - { - snprintf(name,256,"%03d %s",i.first,i.second.c_str()); - ui->lwPresetSelect->addItem(name); - if(i.first==p)ui->lwPresetSelect->setCurrentRow(ui->lwPresetSelect->count()-1); - } - } + CMidiPlayer *plyr = qmpMainWindow::getInstance()->getPlayer(); + ch = chid; + int r; + char name[256]; + uint16_t b; + uint8_t p; + std::string pstname; + sprintf(name, "Preset Selection - Channel #%d", ch + 1); + setWindowTitle(name); + r = plyr->getChannelOutputDevice(ch)->getChannelPreset(ch, &b, &p, pstname); + if (!r) + { + b = plyr->getCC(ch, 0) << 7 | plyr->getCC(ch, 32); + p = plyr->getCC(ch, 128); + } + ui->lwBankSelect->blockSignals(true); + ui->lwBankSelect->clear(); + ui->lwPresetSelect->clear(); + ui->lwBankSelect->blockSignals(false); + if (plyr->getChannelOutputDevice(ch)->getBankList().empty()) + { + ui->lwPresetSelect->setEnabled(false); + ui->lwBankSelect->setEnabled(false); + ui->spCustomLSB->setEnabled(true); + ui->spCustomMSB->setEnabled(true); + ui->spCustomPC->setEnabled(true); + ui->spCustomMSB->setValue(plyr->getCC(chid, 0)); + ui->spCustomLSB->setValue(plyr->getCC(chid, 32)); + ui->spCustomPC->setValue(p); + } + else + { + ui->lwPresetSelect->setEnabled(true); + ui->lwBankSelect->setEnabled(true); + ui->spCustomLSB->setEnabled(false); + ui->spCustomMSB->setEnabled(false); + ui->spCustomPC->setEnabled(false); + ui->lwBankSelect->blockSignals(true); + for (auto &i : plyr->getChannelOutputDevice(ch)->getBankList()) + { + snprintf(name, 256, "%03d %s", i.first, i.second.c_str()); + ui->lwBankSelect->addItem(name); + if (i.first == b) + ui->lwBankSelect->setCurrentRow(ui->lwBankSelect->count() - 1); + } + ui->lwBankSelect->blockSignals(false); + for (auto &i : plyr->getChannelOutputDevice(ch)->getPresets(b)) + { + snprintf(name, 256, "%03d %s", i.first, i.second.c_str()); + ui->lwPresetSelect->addItem(name); + if (i.first == p) + ui->lwPresetSelect->setCurrentRow(ui->lwPresetSelect->count() - 1); + } + } } void qmpPresetSelector::on_pbCancel_clicked() { - close(); + close(); } void qmpPresetSelector::on_pbOk_clicked() { - CMidiPlayer *plyr=qmpMainWindow::getInstance()->getPlayer(); - if(plyr->getChannelOutput(ch)){ - if(ui->spCustomMSB->isEnabled()) - plyr->setChannelPreset(ch,(ui->spCustomMSB->value()<<7)|ui->spCustomLSB->value(),ui->spCustomPC->value()); - else - { - if(!ui->lwBankSelect->currentItem()||!ui->lwPresetSelect->currentItem())return (void)close(); - int b=ui->lwBankSelect->currentItem()->text().split(' ').first().toInt(); - int p=ui->lwPresetSelect->currentItem()->text().split(' ').first().toInt(); - plyr->setChannelPreset(ch,b,p); - } - } - else{ - if(!ui->lwBankSelect->currentItem()||!ui->lwPresetSelect->currentItem())return (void)close(); - int b,p; - b=ui->lwBankSelect->currentItem()->text().toInt(); - p=ui->lwPresetSelect->currentItem()->text().split(' ').first().toInt(); - std::string s=qmpMainWindow::getInstance()->getSettings()->getOptionEnumIntOptName("FluidSynth/BankSelect"); - if(s=="XG"){ - if(b==128)b=127<<7; - } - else if(s=="GS")b<<=7; - plyr->setChannelPreset(ch,b,p); - } - qmpMainWindow::getInstance()->invokeCallback("preset.set",nullptr); - close(); + CMidiPlayer *plyr = qmpMainWindow::getInstance()->getPlayer(); + if (plyr->getChannelOutput(ch)) + { + if (ui->spCustomMSB->isEnabled()) + plyr->setChannelPreset(ch, (ui->spCustomMSB->value() << 7) | ui->spCustomLSB->value(), ui->spCustomPC->value()); + else + { + if (!ui->lwBankSelect->currentItem() || !ui->lwPresetSelect->currentItem()) + return (void)close(); + int b = ui->lwBankSelect->currentItem()->text().split(' ').first().toInt(); + int p = ui->lwPresetSelect->currentItem()->text().split(' ').first().toInt(); + plyr->setChannelPreset(ch, b, p); + } + } + else + { + if (!ui->lwBankSelect->currentItem() || !ui->lwPresetSelect->currentItem()) + return (void)close(); + int b, p; + b = ui->lwBankSelect->currentItem()->text().toInt(); + p = ui->lwPresetSelect->currentItem()->text().split(' ').first().toInt(); + std::string s = qmpMainWindow::getInstance()->getSettings()->getOptionEnumIntOptName("FluidSynth/BankSelect"); + if (s == "XG") + { + if (b == 128) + b = 127 << 7; + } + else if (s == "GS") + b <<= 7; + plyr->setChannelPreset(ch, b, p); + } + qmpMainWindow::getInstance()->invokeCallback("preset.set", nullptr); + close(); } void qmpPresetSelector::on_lwPresetSelect_itemDoubleClicked() { - on_pbOk_clicked(); + on_pbOk_clicked(); } void qmpPresetSelector::on_lwBankSelect_currentRowChanged() { - ui->lwPresetSelect->clear(); - if(!ui->lwBankSelect->currentItem())return; - char name[256];int b; - sscanf(ui->lwBankSelect->currentItem()->text().toStdString().c_str(),"%d",&b); - CMidiPlayer *plyr=qmpMainWindow::getInstance()->getPlayer(); - for(auto&i:plyr->getChannelOutputDevice(ch)->getPresets(b)) - { - snprintf(name,256,"%03d %s",i.first,i.second.c_str()); - ui->lwPresetSelect->addItem(name); - } + ui->lwPresetSelect->clear(); + if (!ui->lwBankSelect->currentItem()) + return; + char name[256]; + int b; + sscanf(ui->lwBankSelect->currentItem()->text().toStdString().c_str(), "%d", &b); + CMidiPlayer *plyr = qmpMainWindow::getInstance()->getPlayer(); + for (auto &i : plyr->getChannelOutputDevice(ch)->getPresets(b)) + { + snprintf(name, 256, "%03d %s", i.first, i.second.c_str()); + ui->lwPresetSelect->addItem(name); + } } void qmpPresetSelector::on_buttonBox_accepted() { - on_pbOk_clicked(); + on_pbOk_clicked(); } void qmpPresetSelector::on_buttonBox_rejected() { - on_pbCancel_clicked(); + on_pbCancel_clicked(); } diff --git a/qmidiplayer-desktop/qmppresetselect.hpp b/qmidiplayer-desktop/qmppresetselect.hpp index 0186578..6eaf2bf 100644 --- a/qmidiplayer-desktop/qmppresetselect.hpp +++ b/qmidiplayer-desktop/qmppresetselect.hpp @@ -4,36 +4,37 @@ #include #include -namespace Ui { - class qmpPresetSelector; +namespace Ui +{ +class qmpPresetSelector; } -class qmpPresetSelector:public QDialog +class qmpPresetSelector: public QDialog { - Q_OBJECT + Q_OBJECT - public: - explicit qmpPresetSelector(QWidget *parent = 0); - ~qmpPresetSelector(); - void showEvent(QShowEvent* e); - void setupWindow(int chid); +public: + explicit qmpPresetSelector(QWidget *parent = 0); + ~qmpPresetSelector(); + void showEvent(QShowEvent *e); + void setupWindow(int chid); - private slots: +private slots: - void on_lwBankSelect_currentRowChanged(); + void on_lwBankSelect_currentRowChanged(); - void on_lwPresetSelect_itemDoubleClicked(); + void on_lwPresetSelect_itemDoubleClicked(); - void on_buttonBox_accepted(); + void on_buttonBox_accepted(); - void on_buttonBox_rejected(); + void on_buttonBox_rejected(); - private: - Ui::qmpPresetSelector *ui; - char presets[129][128][24]; - void on_pbCancel_clicked(); - void on_pbOk_clicked(); - int ch; +private: + Ui::qmpPresetSelector *ui; + char presets[129][128][24]; + void on_pbCancel_clicked(); + void on_pbOk_clicked(); + int ch; }; #endif // QMPPRESETSELECT_H diff --git a/qmidiplayer-desktop/qmpsettings.cpp b/qmidiplayer-desktop/qmpsettings.cpp index cdc96b8..8ba0d5e 100644 --- a/qmidiplayer-desktop/qmpsettings.cpp +++ b/qmidiplayer-desktop/qmpsettings.cpp @@ -4,245 +4,245 @@ #define QMP_CONFIGURATION_FILE_REV 1 -QSettings* qmpSettings::settings=nullptr; +QSettings *qmpSettings::settings = nullptr; qmpSettings::qmpSettings() { - qRegisterMetaTypeStreamOperators>(); - QString confpath=QStandardPaths::writableLocation(QStandardPaths::StandardLocation::ConfigLocation)+QString("/qmprc"); - settings=new QSettings(confpath,QSettings::IniFormat); - if(settings->value("ConfigurationFileRevision").toInt()!=QMP_CONFIGURATION_FILE_REV&& - QFile::exists(confpath)) - { - qWarning("Your current configuration file is not compatible with this version of QMidiPlayer. " - "QMidiPlayer will start with its default configuration. A backup of the old configuration " - "is automatically saved as qmprc.old."); - QFile::remove(confpath+".old"); - QFile::copy(confpath,confpath+".old"); - settings->clear(); - settings->setValue("ConfigurationFileRevision",QMP_CONFIGURATION_FILE_REV); - } + qRegisterMetaTypeStreamOperators>(); + QString confpath = QStandardPaths::writableLocation(QStandardPaths::StandardLocation::ConfigLocation) + QString("/qmprc"); + settings = new QSettings(confpath, QSettings::IniFormat); + if (settings->value("ConfigurationFileRevision").toInt() != QMP_CONFIGURATION_FILE_REV && + QFile::exists(confpath)) + { + qWarning("Your current configuration file is not compatible with this version of QMidiPlayer. " + "QMidiPlayer will start with its default configuration. A backup of the old configuration " + "is automatically saved as qmprc.old."); + QFile::remove(confpath + ".old"); + QFile::copy(confpath, confpath + ".old"); + settings->clear(); + settings->setValue("ConfigurationFileRevision", QMP_CONFIGURATION_FILE_REV); + } } qmpSettings::~qmpSettings() { - delete settings; - settings=nullptr; + delete settings; + settings = nullptr; } -void qmpSettings::registerOptionInt(std::string tab,std::string desc,std::string key,int min,int max,int defaultval) +void qmpSettings::registerOptionInt(std::string tab, std::string desc, std::string key, int min, int max, int defaultval) { - optionlist.push_back(key); - options[key]=qmpOption(tab,desc,qmpOption::ParameterType::parameter_int,nullptr,defaultval,min,max); + optionlist.push_back(key); + options[key] = qmpOption(tab, desc, qmpOption::ParameterType::parameter_int, nullptr, defaultval, min, max); } int qmpSettings::getOptionInt(std::string key) { - if(options.find(key)!=options.end()&&options[key].type==qmpOption::ParameterType::parameter_int) - return settings->value(QString(key.c_str()),options[key].defaultval).toInt(); - qWarning("Unregistered option or mismatching option type: %s.",key.c_str()); - return options[key].defaultval.toInt(); + if (options.find(key) != options.end() && options[key].type == qmpOption::ParameterType::parameter_int) + return settings->value(QString(key.c_str()), options[key].defaultval).toInt(); + qWarning("Unregistered option or mismatching option type: %s.", key.c_str()); + return options[key].defaultval.toInt(); } -void qmpSettings::setOptionInt(std::string key,int val) +void qmpSettings::setOptionInt(std::string key, int val) { - if(options.find(key)!=options.end()&&options[key].type==qmpOption::ParameterType::parameter_int) - settings->setValue(QString(key.c_str()),val); - else - qWarning("Unregistered option or mismatching option type: %s.",key.c_str()); - //call qmpSettingsWindow::load(key)? + if (options.find(key) != options.end() && options[key].type == qmpOption::ParameterType::parameter_int) + settings->setValue(QString(key.c_str()), val); + else + qWarning("Unregistered option or mismatching option type: %s.", key.c_str()); + //call qmpSettingsWindow::load(key)? } -void qmpSettings::registerOptionUint(std::string tab,std::string desc,std::string key,unsigned min, unsigned max,unsigned defaultval) +void qmpSettings::registerOptionUint(std::string tab, std::string desc, std::string key, unsigned min, unsigned max, unsigned defaultval) { - optionlist.push_back(key); - options[key]=qmpOption(tab,desc,qmpOption::ParameterType::parameter_uint,nullptr,defaultval,min,max); + optionlist.push_back(key); + options[key] = qmpOption(tab, desc, qmpOption::ParameterType::parameter_uint, nullptr, defaultval, min, max); } unsigned qmpSettings::getOptionUint(std::string key) { - if(options.find(key)!=options.end()&&options[key].type==qmpOption::ParameterType::parameter_uint) - return settings->value(QString(key.c_str()),options[key].defaultval).toUInt(); - qWarning("Unregistered option or mismatching option type: %s.",key.c_str()); - return options[key].defaultval.toUInt(); + if (options.find(key) != options.end() && options[key].type == qmpOption::ParameterType::parameter_uint) + return settings->value(QString(key.c_str()), options[key].defaultval).toUInt(); + qWarning("Unregistered option or mismatching option type: %s.", key.c_str()); + return options[key].defaultval.toUInt(); } -void qmpSettings::setOptionUint(std::string key,unsigned val) +void qmpSettings::setOptionUint(std::string key, unsigned val) { - if(options.find(key)!=options.end()&&options[key].type==qmpOption::ParameterType::parameter_uint) - settings->setValue(QString(key.c_str()),val); - else - qWarning("Unregistered option or mismatching option type: %s.",key.c_str()); + if (options.find(key) != options.end() && options[key].type == qmpOption::ParameterType::parameter_uint) + settings->setValue(QString(key.c_str()), val); + else + qWarning("Unregistered option or mismatching option type: %s.", key.c_str()); } -void qmpSettings::registerOptionBool(std::string tab,std::string desc,std::string key,bool defaultval) +void qmpSettings::registerOptionBool(std::string tab, std::string desc, std::string key, bool defaultval) { - optionlist.push_back(key); - options[key]=qmpOption(tab,desc,qmpOption::ParameterType::parameter_bool,nullptr,defaultval); + optionlist.push_back(key); + options[key] = qmpOption(tab, desc, qmpOption::ParameterType::parameter_bool, nullptr, defaultval); } bool qmpSettings::getOptionBool(std::string key) { - if(options.find(key)!=options.end()&&options[key].type==qmpOption::ParameterType::parameter_bool) - return settings->value(QString(key.c_str()),options[key].defaultval).toBool(); - qWarning("Unregistered option or mismatching option type: %s.",key.c_str()); - return options[key].defaultval.toBool(); + if (options.find(key) != options.end() && options[key].type == qmpOption::ParameterType::parameter_bool) + return settings->value(QString(key.c_str()), options[key].defaultval).toBool(); + qWarning("Unregistered option or mismatching option type: %s.", key.c_str()); + return options[key].defaultval.toBool(); } -void qmpSettings::setOptionBool(std::string key,bool val) +void qmpSettings::setOptionBool(std::string key, bool val) { - if(options.find(key)!=options.end()&&options[key].type==qmpOption::ParameterType::parameter_bool) - settings->setValue(QString(key.c_str()),val); - else - qWarning("Unregistered option or mismatching option type: %s.",key.c_str()); + if (options.find(key) != options.end() && options[key].type == qmpOption::ParameterType::parameter_bool) + settings->setValue(QString(key.c_str()), val); + else + qWarning("Unregistered option or mismatching option type: %s.", key.c_str()); } void qmpSettings::registerOptionDouble(std::string tab, std::string desc, std::string key, double min, double max, double defaultval) { - optionlist.push_back(key); - options[key]=qmpOption(tab,desc,qmpOption::ParameterType::parameter_double,nullptr,defaultval,min,max); + optionlist.push_back(key); + options[key] = qmpOption(tab, desc, qmpOption::ParameterType::parameter_double, nullptr, defaultval, min, max); } double qmpSettings::getOptionDouble(std::string key) { - if(options.find(key)!=options.end()&&options[key].type==qmpOption::ParameterType::parameter_double) - return settings->value(QString(key.c_str()),options[key].defaultval).toDouble(); - qWarning("Unregistered option or mismatching option type: %s.",key.c_str()); - return options[key].defaultval.toDouble(); + if (options.find(key) != options.end() && options[key].type == qmpOption::ParameterType::parameter_double) + return settings->value(QString(key.c_str()), options[key].defaultval).toDouble(); + qWarning("Unregistered option or mismatching option type: %s.", key.c_str()); + return options[key].defaultval.toDouble(); } -void qmpSettings::setOptionDouble(std::string key,double val) +void qmpSettings::setOptionDouble(std::string key, double val) { - if(options.find(key)!=options.end()&&options[key].type==qmpOption::ParameterType::parameter_double) - settings->setValue(QString(key.c_str()),val); - else - qWarning("Unregistered option or mismatching option type: %s.",key.c_str()); + if (options.find(key) != options.end() && options[key].type == qmpOption::ParameterType::parameter_double) + settings->setValue(QString(key.c_str()), val); + else + qWarning("Unregistered option or mismatching option type: %s.", key.c_str()); } -void qmpSettings::registerOptionString(std::string tab,std::string desc,std::string key,std::string defaultval,bool is_url) +void qmpSettings::registerOptionString(std::string tab, std::string desc, std::string key, std::string defaultval, bool is_url) { - optionlist.push_back(key); - options[key]=qmpOption(tab,desc, - is_url?qmpOption::ParameterType::parameter_url:qmpOption::ParameterType::parameter_str, - nullptr,QString(defaultval.c_str())); + optionlist.push_back(key); + options[key] = qmpOption(tab, desc, + is_url ? qmpOption::ParameterType::parameter_url : qmpOption::ParameterType::parameter_str, + nullptr, QString(defaultval.c_str())); } std::string qmpSettings::getOptionString(std::string key) { - if(options.find(key)!=options.end()&& - (options[key].type==qmpOption::ParameterType::parameter_str||options[key].type==qmpOption::ParameterType::parameter_url)) - return settings->value(QString(key.c_str()),options[key].defaultval).toString().toStdString(); - qWarning("Unregistered option or mismatching option type: %s.",key.c_str()); - return options[key].defaultval.toString().toStdString(); + if (options.find(key) != options.end() && + (options[key].type == qmpOption::ParameterType::parameter_str || options[key].type == qmpOption::ParameterType::parameter_url)) + return settings->value(QString(key.c_str()), options[key].defaultval).toString().toStdString(); + qWarning("Unregistered option or mismatching option type: %s.", key.c_str()); + return options[key].defaultval.toString().toStdString(); } -void qmpSettings::setOptionString(std::string key,std::string val) +void qmpSettings::setOptionString(std::string key, std::string val) { - if(options.find(key)!=options.end()&& - (options[key].type==qmpOption::ParameterType::parameter_str||options[key].type==qmpOption::ParameterType::parameter_url)) - settings->setValue(QString(key.c_str()),QString(val.c_str())); - else - qWarning("Unregistered option or mismatching option type: %s.",key.c_str()); + if (options.find(key) != options.end() && + (options[key].type == qmpOption::ParameterType::parameter_str || options[key].type == qmpOption::ParameterType::parameter_url)) + settings->setValue(QString(key.c_str()), QString(val.c_str())); + else + qWarning("Unregistered option or mismatching option type: %s.", key.c_str()); } -void qmpSettings::registerOptionEnumInt(std::string tab,std::string desc,std::string key,std::vector enumlist,int defaultval) +void qmpSettings::registerOptionEnumInt(std::string tab, std::string desc, std::string key, std::vector enumlist, int defaultval) { - optionlist.push_back(key); - options[key]=qmpOption(tab,desc,qmpOption::ParameterType::parameter_enum,nullptr,defaultval); - options[key].enumlist=enumlist; + optionlist.push_back(key); + options[key] = qmpOption(tab, desc, qmpOption::ParameterType::parameter_enum, nullptr, defaultval); + options[key].enumlist = enumlist; } int qmpSettings::getOptionEnumInt(std::string key) { - if(options.find(key)!=options.end()&&options[key].type==qmpOption::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 - { - qWarning("Invalid value set for option \"%s\".",key.c_str()); - return options[key].defaultval.toInt(); - } - } - qWarning("Unregistered option or mismatching option type: %s.",key.c_str()); - return options[key].defaultval.toInt(); + if (options.find(key) != options.end() && options[key].type == qmpOption::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 + { + qWarning("Invalid value set for option \"%s\".", key.c_str()); + return options[key].defaultval.toInt(); + } + } + qWarning("Unregistered option or mismatching option type: %s.", key.c_str()); + return options[key].defaultval.toInt(); } std::string qmpSettings::getOptionEnumIntOptName(std::string key) { - if(options.find(key)!=options.end()&&options[key].type==qmpOption::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 - { - qWarning("Invalid value set for option \"%s\".",key.c_str()); - return options[key].enumlist[static_cast(options[key].defaultval.toInt())]; - } - } - qWarning("Unregistered option or mismatching option type: %s.",key.c_str()); - return options[key].enumlist[static_cast(options[key].defaultval.toInt())]; + if (options.find(key) != options.end() && options[key].type == qmpOption::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 + { + qWarning("Invalid value set for option \"%s\".", key.c_str()); + return options[key].enumlist[static_cast(options[key].defaultval.toInt())]; + } + } + qWarning("Unregistered option or mismatching option type: %s.", key.c_str()); + return options[key].enumlist[static_cast(options[key].defaultval.toInt())]; } -void qmpSettings::setOptionEnumInt(std::string key,int val) +void qmpSettings::setOptionEnumInt(std::string key, int val) { - if(options.find(key)!=options.end()&&options[key].type==qmpOption::ParameterType::parameter_enum) - { - if(static_cast(val)setValue(QString(key.c_str()),QString(options[key].enumlist[static_cast(val)].c_str())); - else - qWarning("Trying to set invalid value for option \"%s\".",key.c_str()); - } - else - qWarning("Unregistered option or mismatching option type: %s.",key.c_str()); + if (options.find(key) != options.end() && options[key].type == qmpOption::ParameterType::parameter_enum) + { + if (static_cast(val) < options[key].enumlist.size()) + settings->setValue(QString(key.c_str()), QString(options[key].enumlist[static_cast(val)].c_str())); + else + qWarning("Trying to set invalid value for option \"%s\".", key.c_str()); + } + else + qWarning("Unregistered option or mismatching option type: %s.", key.c_str()); } -void qmpSettings::setOptionEnumIntOptName(std::string key,std::string valname) +void qmpSettings::setOptionEnumIntOptName(std::string key, std::string valname) { - if(options.find(key)!=options.end()&&options[key].type==qmpOption::ParameterType::parameter_enum) - { - auto curidx=std::find(options[key].enumlist.begin(),options[key].enumlist.end(),valname); - if(curidx!=options[key].enumlist.end()) - settings->setValue(QString(key.c_str()),QString(valname.c_str())); - else - qWarning("Trying to set invalid value for option \"%s\".",key.c_str()); - } - else - qWarning("Unregistered option or mismatching option type: %s.",key.c_str()); + if (options.find(key) != options.end() && options[key].type == qmpOption::ParameterType::parameter_enum) + { + auto curidx = std::find(options[key].enumlist.begin(), options[key].enumlist.end(), valname); + if (curidx != options[key].enumlist.end()) + settings->setValue(QString(key.c_str()), QString(valname.c_str())); + else + qWarning("Trying to set invalid value for option \"%s\".", key.c_str()); + } + else + qWarning("Unregistered option or mismatching option type: %s.", key.c_str()); } -void qmpSettings::registerOptionCustom(std::string tab,std::string desc,std::string key,void* widget, void* defaultval,std::function save_func,std::function load_func) +void qmpSettings::registerOptionCustom(std::string tab, std::string desc, std::string key, void *widget, void *defaultval, std::function save_func, std::function load_func) { - optionlist.push_back(key); - options[key]=qmpOption(tab,desc,qmpOption::parameter_custom, - static_cast(widget), - *static_cast(defaultval), - QVariant(),QVariant(),save_func,load_func); + optionlist.push_back(key); + options[key] = qmpOption(tab, desc, qmpOption::parameter_custom, + static_cast(widget), + *static_cast(defaultval), + QVariant(), QVariant(), save_func, load_func); } -void* qmpSettings::getOptionCustom(std::string key) +void *qmpSettings::getOptionCustom(std::string key) { - if(options.find(key)!=options.end()||options[key].type!=qmpOption::ParameterType::parameter_custom) - return static_cast(new QVariant(settings->value(QString(key.c_str()),options[key].defaultval))); - qWarning("Unregistered option or mismatching option type: %s.",key.c_str()); - return nullptr; + if (options.find(key) != options.end() || options[key].type != qmpOption::ParameterType::parameter_custom) + return static_cast(new QVariant(settings->value(QString(key.c_str()), options[key].defaultval))); + qWarning("Unregistered option or mismatching option type: %s.", key.c_str()); + return nullptr; } -void qmpSettings::setOptionCustom(std::string key,void *val) +void qmpSettings::setOptionCustom(std::string key, void *val) { - if(options.find(key)!=options.end()||options[key].type!=qmpOption::ParameterType::parameter_custom) - settings->setValue(QString(key.c_str()),*static_cast(val)); - else - qWarning("Unregistered option or mismatching option type: %s.",key.c_str()); + if (options.find(key) != options.end() || options[key].type != qmpOption::ParameterType::parameter_custom) + settings->setValue(QString(key.c_str()), *static_cast(val)); + else + qWarning("Unregistered option or mismatching option type: %s.", key.c_str()); } -void qmpSettings::setOptionRaw(QString key,QVariant val) +void qmpSettings::setOptionRaw(QString key, QVariant val) { - settings->setValue(key,val); + settings->setValue(key, val); } -QVariant qmpSettings::getOptionRaw(QString key,QVariant defval) +QVariant qmpSettings::getOptionRaw(QString key, QVariant defval) { - return settings->value(key,defval); + return settings->value(key, defval); } -QDataStream &operator<<(QDataStream &out,const QPair &o) +QDataStream &operator<<(QDataStream &out, const QPair &o) { - out<>(QDataStream &in,QPair &o) +QDataStream &operator>>(QDataStream &in, QPair &o) { - in>>o.first>>o.second; - return in; + in >> o.first >> o.second; + return in; } diff --git a/qmidiplayer-desktop/qmpsettings.hpp b/qmidiplayer-desktop/qmpsettings.hpp index ff46970..2fb894f 100644 --- a/qmidiplayer-desktop/qmpsettings.hpp +++ b/qmidiplayer-desktop/qmpsettings.hpp @@ -10,79 +10,80 @@ struct qmpOption { - enum ParameterType{ - parameter_int=0, - parameter_uint, - parameter_bool, - parameter_double, - parameter_str, - parameter_enum, - parameter_url, - parameter_custom=0x100 - }; + enum ParameterType + { + parameter_int = 0, + parameter_uint, + parameter_bool, + parameter_double, + parameter_str, + parameter_enum, + parameter_url, + parameter_custom = 0x100 + }; - std::string tab; - std::string desc; - ParameterType type; - QWidget* widget; - QVariant defaultval,minv,maxv; - std::function save_func; - std::function load_func; - std::vector enumlist; + std::string tab; + std::string desc; + ParameterType type; + QWidget *widget; + QVariant defaultval, minv, maxv; + std::function save_func; + std::function load_func; + std::vector enumlist; - qmpOption():widget(nullptr){} - qmpOption(std::string _tab,std::string _desc, - ParameterType _t,QWidget* _w=nullptr, - QVariant _def=QVariant(),QVariant _min=QVariant(),QVariant _max=QVariant(), - std::function _save=nullptr,std::function _load=nullptr): - tab(_tab), - desc(_desc), - type(_t), - widget(_w), - defaultval(_def), - minv(_min), - maxv(_max), - save_func(_save), - load_func(_load){} + qmpOption(): widget(nullptr) {} + qmpOption(std::string _tab, std::string _desc, + ParameterType _t, QWidget *_w = nullptr, + QVariant _def = QVariant(), QVariant _min = QVariant(), QVariant _max = QVariant(), + std::function _save = nullptr, std::function _load = nullptr): + tab(_tab), + desc(_desc), + type(_t), + widget(_w), + defaultval(_def), + minv(_min), + maxv(_max), + save_func(_save), + load_func(_load) {} }; class qmpSettings { - public: - qmpSettings(); - ~qmpSettings(); - 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 registerOptionCustom(std::string tab,std::string desc,std::string key,void* widget,void* defaultval,std::function save_func,std::function load_func); - void* getOptionCustom(std::string key); - void setOptionCustom(std::string key,void* val); +public: + qmpSettings(); + ~qmpSettings(); + 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 registerOptionCustom(std::string tab, std::string desc, std::string key, void *widget, void *defaultval, std::function save_func, std::function load_func); + void *getOptionCustom(std::string key); + void setOptionCustom(std::string key, void *val); - void setOptionRaw(QString key,QVariant val); - QVariant getOptionRaw(QString key,QVariant defval=QVariant()); + void setOptionRaw(QString key, QVariant val); + QVariant getOptionRaw(QString key, QVariant defval = QVariant()); - private: - static QSettings *settings; - std::map options; - std::vector optionlist; +private: + static QSettings *settings; + std::map options; + std::vector optionlist; - friend class qmpSettingsWindow; + friend class qmpSettingsWindow; }; #endif diff --git a/qmidiplayer-desktop/qmpsettingswindow.cpp b/qmidiplayer-desktop/qmpsettingswindow.cpp index 8d4a964..03e4cd1 100644 --- a/qmidiplayer-desktop/qmpsettingswindow.cpp +++ b/qmidiplayer-desktop/qmpsettingswindow.cpp @@ -12,568 +12,593 @@ #include "ui_qmpsettingswindow.h" #include "qmpmainwindow.hpp" -qmpSettingsWindow::qmpSettingsWindow(qmpSettings *qmpsettings,QWidget *parent) : - QDialog(parent), - ui(new Ui::qmpSettingsWindow) +qmpSettingsWindow::qmpSettingsWindow(qmpSettings *qmpsettings, QWidget *parent) : + QDialog(parent), + ui(new Ui::qmpSettingsWindow) { - ui->setupUi(this);customOptions.clear();customOptPages.clear(); - connect(this,&qmpSettingsWindow::dialogClosing,(qmpMainWindow*)parent,&qmpMainWindow::dialogClosed); - settings=qmpsettings; - cwt=new qmpCustomizeWindow(this); - cwa=new qmpCustomizeWindow(this); - dps=new qmpDevPropDialog(this); - devpriod=new qmpDevicePriorityDialog(this); + ui->setupUi(this); + customOptions.clear(); + customOptPages.clear(); + connect(this, &qmpSettingsWindow::dialogClosing, (qmpMainWindow *)parent, &qmpMainWindow::dialogClosed); + settings = qmpsettings; + cwt = new qmpCustomizeWindow(this); + cwa = new qmpCustomizeWindow(this); + dps = new qmpDevPropDialog(this); + devpriod = new qmpDevicePriorityDialog(this); } qmpSettingsWindow::~qmpSettingsWindow() { - delete ui; + delete ui; } void qmpSettingsWindow::closeEvent(QCloseEvent *event) { - setVisible(false); - loadOption(); - emit dialogClosing(); - event->accept(); + setVisible(false); + loadOption(); + emit dialogClosing(); + event->accept(); } void qmpSettingsWindow::hideEvent(QHideEvent *event) { - emit dialogClosing(); - event->accept(); + emit dialogClosing(); + event->accept(); } void qmpSettingsWindow::on_buttonBox_accepted() { - saveOption(); - qmpMainWindow::getInstance()->setupWidget(); - emit dialogClosing(); + saveOption(); + qmpMainWindow::getInstance()->setupWidget(); + emit dialogClosing(); } void qmpSettingsWindow::on_buttonBox_rejected() { - loadOption(); - emit dialogClosing(); + loadOption(); + emit dialogClosing(); } void qmpSettingsWindow::updatePluginList(qmpPluginManager *pmgr) { - std::vector *plugins=pmgr->getPlugins(); - QVariant *data=static_cast(settings->getOptionCustom("DisabledPlugins")); - QList disabled_plugins_l=static_cast(data)->toList(); - delete data; - std::set disabled_plugins_s; - for(auto &i:disabled_plugins_l) - disabled_plugins_s.insert(i.toString().toStdString()); - for(unsigned i=0;isize();++i) - { - bool enabled=disabled_plugins_s.find(plugins->at(i).name)==disabled_plugins_s.end(); - plugins->at(i).enabled=enabled; - } + std::vector *plugins = pmgr->getPlugins(); + QVariant *data = static_cast(settings->getOptionCustom("DisabledPlugins")); + QList disabled_plugins_l = static_cast(data)->toList(); + delete data; + std::set disabled_plugins_s; + for (auto &i : disabled_plugins_l) + disabled_plugins_s.insert(i.toString().toStdString()); + for (unsigned i = 0; i < plugins->size(); ++i) + { + bool enabled = disabled_plugins_s.find(plugins->at(i).name) == disabled_plugins_s.end(); + plugins->at(i).enabled = enabled; + } } void qmpSettingsWindow::postInit() { - setupWidgets(); - int sf=0; - QVariant *data=static_cast(settings->getOptionCustom("FluidSynth/SoundFonts")); - for(auto i:data->toList()) - if(!i.toString().startsWith('#')) - { - sf=1; - break; - } - delete data; - std::string selecteddev; - std::vector devs=qmpMainWindow::getInstance()->getPlayer()->getMidiOutDevices(); - std::set devset; - for(auto dev:devs)devset.insert(dev); - QVariant *devpriov=static_cast(qmpMainWindow::getInstance()->getSettings()->getOptionCustom("Midi/DevicePriority")); - QList devprio=devpriov->toList(); - delete devpriov; - for(auto &setdev:devprio) - if(devset.find(setdev.toString().toStdString())!=devset.end()) - { - selecteddev=setdev.toString().toStdString(); - break; - } - if(selecteddev=="Internal FluidSynth"&&!sf) - { - if(QMessageBox::question(this, - tr("No soundfont loaded"), - tr("Internal fluidsynth is the only available MIDI output but it has no soundfont set. " - "Would you like to setup soundfonts now? You may have to reload the internal synth afterwards."))==QMessageBox::Yes) - { - show(); - ui->tabWidget->setCurrentWidget(qobject_cast(pageForTab("SoundFonts")->parent())); - } - } + setupWidgets(); + int sf = 0; + QVariant *data = static_cast(settings->getOptionCustom("FluidSynth/SoundFonts")); + for (auto i : data->toList()) + if (!i.toString().startsWith('#')) + { + sf = 1; + break; + } + delete data; + std::string selecteddev; + std::vector devs = qmpMainWindow::getInstance()->getPlayer()->getMidiOutDevices(); + std::set devset; + for (auto dev : devs) + devset.insert(dev); + QVariant *devpriov = static_cast(qmpMainWindow::getInstance()->getSettings()->getOptionCustom("Midi/DevicePriority")); + QList devprio = devpriov->toList(); + delete devpriov; + for (auto &setdev : devprio) + if (devset.find(setdev.toString().toStdString()) != devset.end()) + { + selecteddev = setdev.toString().toStdString(); + break; + } + if (selecteddev == "Internal FluidSynth" && !sf) + { + if (QMessageBox::question(this, + tr("No soundfont loaded"), + tr("Internal fluidsynth is the only available MIDI output but it has no soundfont set. " + "Would you like to setup soundfonts now? You may have to reload the internal synth afterwards.")) == QMessageBox::Yes) + { + show(); + ui->tabWidget->setCurrentWidget(qobject_cast(pageForTab("SoundFonts")->parent())); + } + } } void qmpSettingsWindow::registerCustomizeWidgetOptions() { - QPushButton *pbCustomizeToolbar=new QPushButton(tr("Customize...")); - QPushButton *pbCustomizeActions=new QPushButton(tr("Customize...")); - QVariant toolbar_def_val=QList({"Channel","Playlist","Effects","Visualization"}); - QVariant actions_def_val=QList({"FileInfo","Render","Panic","ReloadSynth"}); - settings->registerOptionCustom("Behavior","Customize toolbar","Behavior/Toolbar",pbCustomizeToolbar,&toolbar_def_val,std::bind(&qmpCustomizeWindow::save,cwt),std::bind(&qmpCustomizeWindow::load,cwt,std::placeholders::_1)); - settings->registerOptionCustom("Behavior","Customize actions","Behavior/Actions",pbCustomizeActions,&actions_def_val,std::bind(&qmpCustomizeWindow::save,cwa),std::bind(&qmpCustomizeWindow::load,cwa,std::placeholders::_1)); - connect(pbCustomizeToolbar,&QPushButton::clicked,[this]{loadOption("Behavior/Toolbar");cwt->show();}); - connect(pbCustomizeActions,&QPushButton::clicked,[this]{loadOption("Behavior/Actions");cwa->show();}); - connect(cwt,&QDialog::accepted,[this]{saveOption("Behavior/Toolbar");qmpMainWindow::getInstance()->setupWidget();}); - connect(cwa,&QDialog::accepted,[this]{saveOption("Behavior/Actions");qmpMainWindow::getInstance()->setupWidget();}); - connect(cwt,&QDialog::rejected,[this]{loadOption("Behavior/Toolbar");}); - connect(cwa,&QDialog::rejected,[this]{loadOption("Behavior/Actions");}); - qmpMainWindow::getInstance()->setupWidget(); + QPushButton *pbCustomizeToolbar = new QPushButton(tr("Customize...")); + QPushButton *pbCustomizeActions = new QPushButton(tr("Customize...")); + QVariant toolbar_def_val = QList({"Channel", "Playlist", "Effects", "Visualization"}); + QVariant actions_def_val = QList({"FileInfo", "Render", "Panic", "ReloadSynth"}); + settings->registerOptionCustom("Behavior", "Customize toolbar", "Behavior/Toolbar", pbCustomizeToolbar, &toolbar_def_val, std::bind(&qmpCustomizeWindow::save, cwt), std::bind(&qmpCustomizeWindow::load, cwt, std::placeholders::_1)); + settings->registerOptionCustom("Behavior", "Customize actions", "Behavior/Actions", pbCustomizeActions, &actions_def_val, std::bind(&qmpCustomizeWindow::save, cwa), std::bind(&qmpCustomizeWindow::load, cwa, std::placeholders::_1)); + connect(pbCustomizeToolbar, &QPushButton::clicked, [this] {loadOption("Behavior/Toolbar"); cwt->show();}); + connect(pbCustomizeActions, &QPushButton::clicked, [this] {loadOption("Behavior/Actions"); cwa->show();}); + connect(cwt, &QDialog::accepted, [this] {saveOption("Behavior/Toolbar"); qmpMainWindow::getInstance()->setupWidget();}); + connect(cwa, &QDialog::accepted, [this] {saveOption("Behavior/Actions"); qmpMainWindow::getInstance()->setupWidget();}); + connect(cwt, &QDialog::rejected, [this] {loadOption("Behavior/Toolbar");}); + connect(cwa, &QDialog::rejected, [this] {loadOption("Behavior/Actions");}); + qmpMainWindow::getInstance()->setupWidget(); } void qmpSettingsWindow::registerSoundFontOption() { - QWidget *sfpanel=new QWidget(); - sfpanel->setLayout(new QVBoxLayout); - sfpanel->layout()->setMargin(0); - QTableWidget *twsf=new QTableWidget(); - twsf->setColumnCount(2); - twsf->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeMode::ResizeToContents); - twsf->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection); - twsf->setSelectionBehavior(QAbstractItemView::SelectionBehavior::SelectRows); - twsf->setHorizontalHeaderLabels({tr("E"),tr("Path")}); - twsf->setHorizontalScrollMode(QAbstractItemView::ScrollMode::ScrollPerPixel); - twsf->setVerticalScrollMode(QAbstractItemView::ScrollMode::ScrollPerPixel); - sfpanel->layout()->addWidget(twsf); - QWidget *controls=new QWidget(); - controls->setLayout(new QHBoxLayout); - controls->layout()->setMargin(0); - QPushButton *pbsfadd=new QPushButton(style()->standardIcon(QStyle::StandardPixmap::SP_DialogOpenButton),QString()); - QPushButton *pbsfrem=new QPushButton(style()->standardIcon(QStyle::StandardPixmap::SP_DialogDiscardButton),QString()); - QPushButton *pbsfmup=new QPushButton(style()->standardIcon(QStyle::StandardPixmap::SP_ArrowUp),QString()); - QPushButton *pbsfmdn=new QPushButton(style()->standardIcon(QStyle::StandardPixmap::SP_ArrowDown),QString()); - controls->layout()->addWidget(pbsfadd); - controls->layout()->addWidget(pbsfrem); - controls->layout()->addWidget(pbsfmup); - controls->layout()->addWidget(pbsfmdn); - sfpanel->layout()->addWidget(controls); + QWidget *sfpanel = new QWidget(); + sfpanel->setLayout(new QVBoxLayout); + sfpanel->layout()->setMargin(0); + QTableWidget *twsf = new QTableWidget(); + twsf->setColumnCount(2); + twsf->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeMode::ResizeToContents); + twsf->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection); + twsf->setSelectionBehavior(QAbstractItemView::SelectionBehavior::SelectRows); + twsf->setHorizontalHeaderLabels({tr("E"), tr("Path")}); + twsf->setHorizontalScrollMode(QAbstractItemView::ScrollMode::ScrollPerPixel); + twsf->setVerticalScrollMode(QAbstractItemView::ScrollMode::ScrollPerPixel); + sfpanel->layout()->addWidget(twsf); + QWidget *controls = new QWidget(); + controls->setLayout(new QHBoxLayout); + controls->layout()->setMargin(0); + QPushButton *pbsfadd = new QPushButton(style()->standardIcon(QStyle::StandardPixmap::SP_DialogOpenButton), QString()); + QPushButton *pbsfrem = new QPushButton(style()->standardIcon(QStyle::StandardPixmap::SP_DialogDiscardButton), QString()); + QPushButton *pbsfmup = new QPushButton(style()->standardIcon(QStyle::StandardPixmap::SP_ArrowUp), QString()); + QPushButton *pbsfmdn = new QPushButton(style()->standardIcon(QStyle::StandardPixmap::SP_ArrowDown), QString()); + controls->layout()->addWidget(pbsfadd); + controls->layout()->addWidget(pbsfrem); + controls->layout()->addWidget(pbsfmup); + controls->layout()->addWidget(pbsfmdn); + sfpanel->layout()->addWidget(controls); - connect(pbsfadd,&QPushButton::clicked,[twsf,this]{ - QStringList sl=QFileDialog::getOpenFileNames(this,"Add File","","SoundFont files (*.sf2)"); - for(int i=0;iinsertRow(twsf->rowCount()); - QTableWidgetItem *sfn,*sfe; - twsf->setItem(twsf->rowCount()-1,1,sfn=new QTableWidgetItem(sl[i])); - twsf->setItem(twsf->rowCount()-1,0,sfe=new QTableWidgetItem()); - sfe->setCheckState(Qt::CheckState::Unchecked); - sfn->setFlags(Qt::ItemFlag::ItemIsEnabled|Qt::ItemFlag::ItemIsSelectable); - sfe->setFlags(Qt::ItemFlag::ItemIsEnabled|Qt::ItemFlag::ItemIsSelectable|Qt::ItemFlag::ItemIsUserCheckable); - } - }); - connect(pbsfrem,&QPushButton::clicked,[twsf]{ - QList sl=twsf->selectedItems(); - for(int i=0;iremoveRow(twsf->row(sl[i])); - }); - connect(pbsfmup,&QPushButton::clicked,[twsf]{ - int cid=twsf->currentRow();if(!cid)return; - QTableWidgetItem *ci=twsf->takeItem(cid,1); - QTableWidgetItem *ce=twsf->takeItem(cid,0); - twsf->removeRow(cid); - twsf->insertRow(cid-1); - twsf->setItem(cid-1,0,ce); - twsf->setItem(cid-1,1,ci); - twsf->setCurrentCell(cid-1,1); - }); - connect(pbsfmdn,&QPushButton::clicked,[twsf]{ - int cid=twsf->currentRow();if(cid==twsf->rowCount()-1)return; - QTableWidgetItem *ci=twsf->takeItem(cid,1); - QTableWidgetItem *ce=twsf->takeItem(cid,0); - twsf->removeRow(cid); - twsf->insertRow(cid+1); - twsf->setItem(cid+1,0,ce); - twsf->setItem(cid+1,1,ci); - twsf->setCurrentCell(cid+1,1); - }); + connect(pbsfadd, &QPushButton::clicked, [twsf, this] + { + QStringList sl = QFileDialog::getOpenFileNames(this, "Add File", "", "SoundFont files (*.sf2)"); + for (int i = 0; i < sl.size(); ++i) + { + twsf->insertRow(twsf->rowCount()); + QTableWidgetItem *sfn, *sfe; + twsf->setItem(twsf->rowCount() - 1, 1, sfn = new QTableWidgetItem(sl[i])); + twsf->setItem(twsf->rowCount() - 1, 0, sfe = new QTableWidgetItem()); + sfe->setCheckState(Qt::CheckState::Unchecked); + sfn->setFlags(Qt::ItemFlag::ItemIsEnabled | Qt::ItemFlag::ItemIsSelectable); + sfe->setFlags(Qt::ItemFlag::ItemIsEnabled | Qt::ItemFlag::ItemIsSelectable | Qt::ItemFlag::ItemIsUserCheckable); + } + }); + connect(pbsfrem, &QPushButton::clicked, [twsf] + { + QList sl = twsf->selectedItems(); + for (int i = 0; i < sl.size(); ++i) + twsf->removeRow(twsf->row(sl[i])); + }); + connect(pbsfmup, &QPushButton::clicked, [twsf] + { + int cid = twsf->currentRow(); + if (!cid) + return; + QTableWidgetItem *ci = twsf->takeItem(cid, 1); + QTableWidgetItem *ce = twsf->takeItem(cid, 0); + twsf->removeRow(cid); + twsf->insertRow(cid - 1); + twsf->setItem(cid - 1, 0, ce); + twsf->setItem(cid - 1, 1, ci); + twsf->setCurrentCell(cid - 1, 1); + }); + connect(pbsfmdn, &QPushButton::clicked, [twsf] + { + int cid = twsf->currentRow(); if (cid == twsf->rowCount() - 1) + return; + QTableWidgetItem *ci = twsf->takeItem(cid, 1); + QTableWidgetItem *ce = twsf->takeItem(cid, 0); + twsf->removeRow(cid); + twsf->insertRow(cid + 1); + twsf->setItem(cid + 1, 0, ce); + twsf->setItem(cid + 1, 1, ci); + twsf->setCurrentCell(cid + 1, 1); + }); - QVariant sf_def_val=QList(); - auto save_func=[twsf]()->void*{ - QList sflist; - for(int i=0;irowCount();++i) - { - QString sfs=twsf->item(i,1)->text(); - if(twsf->item(i,0)->checkState()==Qt::CheckState::Unchecked) - sfs="#"+sfs; - sflist.push_back(sfs); - } - return new QVariant(sflist); - }; - auto load_func=[twsf](void* data){ - QList sflist=static_cast(data)->toList(); - twsf->clearContents(); - twsf->setRowCount(0); - for(int i=0;iinsertRow(i); - QTableWidgetItem *sfn,*sfe; - QString sf=sflist[i].toString(); - bool enabled=!sf.startsWith('#'); - if(!enabled)sf=sf.mid(1); - twsf->setItem(i,1,sfn=new QTableWidgetItem(sf)); - twsf->setItem(i,0,sfe=new QTableWidgetItem()); - sfn->setFlags(Qt::ItemFlag::ItemIsEnabled|Qt::ItemFlag::ItemIsSelectable); - sfe->setFlags(Qt::ItemFlag::ItemIsEnabled|Qt::ItemFlag::ItemIsSelectable|Qt::ItemFlag::ItemIsUserCheckable); - sfe->setCheckState(enabled?Qt::CheckState::Checked:Qt::CheckState::Unchecked); - } - }; - settings->registerOptionCustom("SoundFonts","","FluidSynth/SoundFonts",sfpanel,&sf_def_val,save_func,load_func); + QVariant sf_def_val = QList(); + auto save_func = [twsf]()->void * + { + QList sflist; + for (int i = 0; i < twsf->rowCount(); ++i) + { + QString sfs = twsf->item(i, 1)->text(); + if (twsf->item(i, 0)->checkState() == Qt::CheckState::Unchecked) + sfs = "#" + sfs; + sflist.push_back(sfs); + } + return new QVariant(sflist); + }; + auto load_func = [twsf](void *data) + { + QList sflist = static_cast(data)->toList(); + twsf->clearContents(); + twsf->setRowCount(0); + for (int i = 0; i < sflist.size(); ++i) + { + twsf->insertRow(i); + QTableWidgetItem *sfn, *sfe; + QString sf = sflist[i].toString(); + bool enabled = !sf.startsWith('#'); + if (!enabled) + sf = sf.mid(1); + twsf->setItem(i, 1, sfn = new QTableWidgetItem(sf)); + twsf->setItem(i, 0, sfe = new QTableWidgetItem()); + sfn->setFlags(Qt::ItemFlag::ItemIsEnabled | Qt::ItemFlag::ItemIsSelectable); + sfe->setFlags(Qt::ItemFlag::ItemIsEnabled | Qt::ItemFlag::ItemIsSelectable | Qt::ItemFlag::ItemIsUserCheckable); + sfe->setCheckState(enabled ? Qt::CheckState::Checked : Qt::CheckState::Unchecked); + } + }; + settings->registerOptionCustom("SoundFonts", "", "FluidSynth/SoundFonts", sfpanel, &sf_def_val, save_func, load_func); } void qmpSettingsWindow::registerPluginOption(qmpPluginManager *pmgr) { - QTableWidget *twplugins=new QTableWidget(); - twplugins->setColumnCount(4); - twplugins->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeMode::ResizeToContents); - twplugins->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection); - twplugins->setSelectionBehavior(QAbstractItemView::SelectionBehavior::SelectRows); - twplugins->setHorizontalHeaderLabels({tr("E"),tr("Plugin Name"),tr("Version"),tr("Path")}); - twplugins->setHorizontalScrollMode(QAbstractItemView::ScrollMode::ScrollPerPixel); - twplugins->setVerticalScrollMode(QAbstractItemView::ScrollMode::ScrollPerPixel); - QVariant ep_def_val=QList(); - auto save_func=[twplugins,this]()->void*{ - QVariant *data=static_cast(settings->getOptionCustom("DisabledPlugins")); - QList disabled_plugins_ol=static_cast(data)->toList(); - delete data; - std::set disabled_plugins_s; - for(auto &i:disabled_plugins_ol) - disabled_plugins_s.insert(i.toString().toStdString()); - for(int i=0;irowCount();++i) - { - QString pn=twplugins->item(i,1)->text(); - if(twplugins->item(i,0)->checkState()==Qt::CheckState::Unchecked) - disabled_plugins_s.insert(pn.toStdString()); - else - disabled_plugins_s.erase(pn.toStdString()); - } - QList disabled_plugins; - for(auto &i:disabled_plugins_s) - disabled_plugins.push_back(QString(i.c_str())); - return new QVariant(disabled_plugins); - }; - auto load_func=[twplugins,pmgr](void* data){ - QList disabled_plugins_l=static_cast(data)->toList(); - std::set disabled_plugins; - for(auto i:disabled_plugins_l) - disabled_plugins.insert(i.toString().toStdString()); + QTableWidget *twplugins = new QTableWidget(); + twplugins->setColumnCount(4); + twplugins->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeMode::ResizeToContents); + twplugins->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection); + twplugins->setSelectionBehavior(QAbstractItemView::SelectionBehavior::SelectRows); + twplugins->setHorizontalHeaderLabels({tr("E"), tr("Plugin Name"), tr("Version"), tr("Path")}); + twplugins->setHorizontalScrollMode(QAbstractItemView::ScrollMode::ScrollPerPixel); + twplugins->setVerticalScrollMode(QAbstractItemView::ScrollMode::ScrollPerPixel); + QVariant ep_def_val = QList(); + auto save_func = [twplugins, this]()->void * + { + QVariant *data = static_cast(settings->getOptionCustom("DisabledPlugins")); + QList disabled_plugins_ol = static_cast(data)->toList(); + delete data; + std::set disabled_plugins_s; + for (auto &i : disabled_plugins_ol) + disabled_plugins_s.insert(i.toString().toStdString()); + for (int i = 0; i < twplugins->rowCount(); ++i) + { + QString pn = twplugins->item(i, 1)->text(); + if (twplugins->item(i, 0)->checkState() == Qt::CheckState::Unchecked) + disabled_plugins_s.insert(pn.toStdString()); + else + disabled_plugins_s.erase(pn.toStdString()); + } + QList disabled_plugins; + for (auto &i : disabled_plugins_s) + disabled_plugins.push_back(QString(i.c_str())); + return new QVariant(disabled_plugins); + }; + auto load_func = [twplugins, pmgr](void *data) + { + QList disabled_plugins_l = static_cast(data)->toList(); + std::set disabled_plugins; + for (auto i : disabled_plugins_l) + disabled_plugins.insert(i.toString().toStdString()); - twplugins->clearContents(); - twplugins->setRowCount(0); + twplugins->clearContents(); + twplugins->setRowCount(0); - std::vector *plugins=pmgr->getPlugins(); - for(int i=0;static_cast(i)size();++i) - { - twplugins->insertRow(i); - qmpPlugin &p=plugins->at(static_cast(i)); - QTableWidgetItem *icb; - twplugins->setItem(i,0,icb=new QTableWidgetItem()); - bool enabled=disabled_plugins.find(p.name)==disabled_plugins.end(); - icb->setCheckState(enabled?Qt::CheckState::Checked:Qt::CheckState::Unchecked); - icb->setFlags(Qt::ItemFlag::ItemIsEnabled|Qt::ItemFlag::ItemIsSelectable|Qt::ItemFlag::ItemIsUserCheckable); - twplugins->setItem(i,1,new QTableWidgetItem(p.name.c_str())); - twplugins->setItem(i,2,new QTableWidgetItem(p.version.c_str())); - twplugins->setItem(i,3,new QTableWidgetItem(p.path.c_str())); - for(int j=1;j<=3;++j) - twplugins->item(i,j)->setFlags(Qt::ItemFlag::ItemIsEnabled|Qt::ItemFlag::ItemIsSelectable); - } - }; - settings->registerOptionCustom("Plugins","","DisabledPlugins",twplugins,&ep_def_val,save_func,load_func); + std::vector *plugins = pmgr->getPlugins(); + for (int i = 0; static_cast(i) < plugins->size(); ++i) + { + twplugins->insertRow(i); + qmpPlugin &p = plugins->at(static_cast(i)); + QTableWidgetItem *icb; + twplugins->setItem(i, 0, icb = new QTableWidgetItem()); + bool enabled = disabled_plugins.find(p.name) == disabled_plugins.end(); + icb->setCheckState(enabled ? Qt::CheckState::Checked : Qt::CheckState::Unchecked); + icb->setFlags(Qt::ItemFlag::ItemIsEnabled | Qt::ItemFlag::ItemIsSelectable | Qt::ItemFlag::ItemIsUserCheckable); + twplugins->setItem(i, 1, new QTableWidgetItem(p.name.c_str())); + twplugins->setItem(i, 2, new QTableWidgetItem(p.version.c_str())); + twplugins->setItem(i, 3, new QTableWidgetItem(p.path.c_str())); + for (int j = 1; j <= 3; ++j) + twplugins->item(i, j)->setFlags(Qt::ItemFlag::ItemIsEnabled | Qt::ItemFlag::ItemIsSelectable); + } + }; + settings->registerOptionCustom("Plugins", "", "DisabledPlugins", twplugins, &ep_def_val, save_func, load_func); } void qmpSettingsWindow::registerExtraMidiOptions() { - QPushButton *pbDevPrio=new QPushButton("..."); - connect(pbDevPrio,&QPushButton::clicked,[this]{loadOption("Midi/DevicePriority");devpriod->show();}); - connect(devpriod,&QDialog::accepted,[this]{saveOption("Midi/DevicePriority");}); - connect(devpriod,&QDialog::rejected,[this]{loadOption("Midi/DevicePriority");}); - QVariant devprio_def_val=QList({"Internal FluidSynth"}); - settings->registerOptionCustom("MIDI","Select MIDI output devices","Midi/DevicePriority",pbDevPrio,&devprio_def_val,std::bind(&qmpDevicePriorityDialog::save,devpriod),std::bind(&qmpDevicePriorityDialog::load,devpriod,std::placeholders::_1)); + QPushButton *pbDevPrio = new QPushButton("..."); + connect(pbDevPrio, &QPushButton::clicked, [this] {loadOption("Midi/DevicePriority"); devpriod->show();}); + connect(devpriod, &QDialog::accepted, [this] {saveOption("Midi/DevicePriority");}); + connect(devpriod, &QDialog::rejected, [this] {loadOption("Midi/DevicePriority");}); + QVariant devprio_def_val = QList({"Internal FluidSynth"}); + settings->registerOptionCustom("MIDI", "Select MIDI output devices", "Midi/DevicePriority", pbDevPrio, &devprio_def_val, std::bind(&qmpDevicePriorityDialog::save, devpriod), std::bind(&qmpDevicePriorityDialog::load, devpriod, std::placeholders::_1)); - QPushButton *pbDevProp=new QPushButton("..."); - connect(pbDevProp,&QPushButton::clicked,[this]{loadOption("Midi/DeviceInitializationFiles");dps->show();}); - connect(dps,&QDialog::accepted,[this]{saveOption("Midi/DeviceInitializationFiles");}); - connect(dps,&QDialog::rejected,[this]{loadOption("Midi/DeviceInitializationFiles");}); - QVariant devprop_def_val=QList({}); - settings->registerOptionCustom("MIDI","External MIDI device setup","Midi/DeviceInitializationFiles",pbDevProp,&devprop_def_val,std::bind(&qmpDevPropDialog::save,dps),std::bind(&qmpDevPropDialog::load,dps,std::placeholders::_1)); + QPushButton *pbDevProp = new QPushButton("..."); + connect(pbDevProp, &QPushButton::clicked, [this] {loadOption("Midi/DeviceInitializationFiles"); dps->show();}); + connect(dps, &QDialog::accepted, [this] {saveOption("Midi/DeviceInitializationFiles");}); + connect(dps, &QDialog::rejected, [this] {loadOption("Midi/DeviceInitializationFiles");}); + QVariant devprop_def_val = QList({}); + settings->registerOptionCustom("MIDI", "External MIDI device setup", "Midi/DeviceInitializationFiles", pbDevProp, &devprop_def_val, std::bind(&qmpDevPropDialog::save, dps), std::bind(&qmpDevPropDialog::load, dps, std::placeholders::_1)); } void qmpSettingsWindow::saveOption(std::string key) { - auto save_opt=[this](std::string& key)->QVariant - { - qmpOption &o=settings->options[key]; - QVariant ret; - switch(o.type) - { - case qmpOption::ParameterType::parameter_int: - { - QSpinBox *sb=qobject_cast(o.widget); - if(sb) - ret=sb->value(); - } - break; - case qmpOption::ParameterType::parameter_uint: - { - QHexSpinBox *sb=qobject_cast(o.widget); - if(sb) - { - int val=sb->value(); - ret=reinterpret_cast(val); - } - } - break; - case qmpOption::ParameterType::parameter_bool: - { - QCheckBox *cb=qobject_cast(o.widget); - if(cb) - ret=cb->isChecked(); - } - break; - case qmpOption::ParameterType::parameter_double: - { - QDoubleSpinBox *sb=qobject_cast(o.widget); - if(sb) - ret=sb->value(); - } - break; - case qmpOption::ParameterType::parameter_str: - { - QLineEdit *le=qobject_cast(o.widget); - if(le) - ret=le->text(); - } - break; - case qmpOption::ParameterType::parameter_enum: - { - QComboBox *cb=qobject_cast(o.widget); - if(cb) - ret=cb->currentText(); - } - break; - case qmpOption::ParameterType::parameter_url: - { - QFileEdit *fe=qobject_cast(o.widget); - if(fe) - ret=fe->text(); - } - break; - default: - if(o.save_func) - { - QVariant* var=static_cast(o.save_func()); - ret=QVariant(*var); - delete var; - } - break; - } - return ret; - }; - if(key.length()) - { - QVariant r=save_opt(key); - if(r.isValid()) - settings->settings->setValue(QString(key.c_str()),r); - } - else for(std::string& key:settings->optionlist) - { - QVariant r=save_opt(key); - if(r.isValid()) - settings->settings->setValue(QString(key.c_str()),r); - } - settings->settings->sync(); + auto save_opt = [this](std::string & key)->QVariant + { + qmpOption &o = settings->options[key]; + QVariant ret; + switch (o.type) + { + case qmpOption::ParameterType::parameter_int: + { + QSpinBox *sb = qobject_cast(o.widget); + if (sb) + ret = sb->value(); + } + break; + case qmpOption::ParameterType::parameter_uint: + { + QHexSpinBox *sb = qobject_cast(o.widget); + if (sb) + { + int val = sb->value(); + ret = reinterpret_cast(val); + } + } + break; + case qmpOption::ParameterType::parameter_bool: + { + QCheckBox *cb = qobject_cast(o.widget); + if (cb) + ret = cb->isChecked(); + } + break; + case qmpOption::ParameterType::parameter_double: + { + QDoubleSpinBox *sb = qobject_cast(o.widget); + if (sb) + ret = sb->value(); + } + break; + case qmpOption::ParameterType::parameter_str: + { + QLineEdit *le = qobject_cast(o.widget); + if (le) + ret = le->text(); + } + break; + case qmpOption::ParameterType::parameter_enum: + { + QComboBox *cb = qobject_cast(o.widget); + if (cb) + ret = cb->currentText(); + } + break; + case qmpOption::ParameterType::parameter_url: + { + QFileEdit *fe = qobject_cast(o.widget); + if (fe) + ret = fe->text(); + } + break; + default: + if (o.save_func) + { + QVariant *var = static_cast(o.save_func()); + ret = QVariant(*var); + delete var; + } + break; + } + return ret; + }; + if (key.length()) + { + QVariant r = save_opt(key); + if (r.isValid()) + settings->settings->setValue(QString(key.c_str()), r); + } + else for (std::string &key : settings->optionlist) + { + QVariant r = save_opt(key); + if (r.isValid()) + settings->settings->setValue(QString(key.c_str()), r); + } + settings->settings->sync(); } void qmpSettingsWindow::loadOption(std::string key) { - auto load_opt=[this](std::string& key) - { - qmpOption &o=settings->options[key]; - switch(o.type) - { - case qmpOption::ParameterType::parameter_int: - { - QSpinBox *sb=qobject_cast(o.widget); - if(sb) - sb->setValue(settings->getOptionInt(key)); - } - break; - case qmpOption::ParameterType::parameter_uint: - { - QHexSpinBox *sb=qobject_cast(o.widget); - if(sb) - sb->setValue(settings->getOptionUint(key)); - } - break; - case qmpOption::ParameterType::parameter_bool: - { - QCheckBox *cb=qobject_cast(o.widget); - if(cb) - cb->setChecked(settings->getOptionBool(key)); - } - break; - case qmpOption::ParameterType::parameter_double: - { - QDoubleSpinBox *sb=qobject_cast(o.widget); - if(sb) - sb->setValue(settings->getOptionDouble(key)); - } - break; - case qmpOption::ParameterType::parameter_str: - { - QLineEdit *le=qobject_cast(o.widget); - if(le) - le->setText(QString(settings->getOptionString(key).c_str())); - } - break; - case qmpOption::ParameterType::parameter_enum: - { - QComboBox *cb=qobject_cast(o.widget); - if(cb) - cb->setCurrentIndex(settings->getOptionEnumInt(key)); - } - break; - case qmpOption::ParameterType::parameter_url: - { - QFileEdit *fe=qobject_cast(o.widget); - if(fe) - fe->setText(QString(settings->getOptionString(key).c_str())); - } - break; - default: - if(o.load_func) - { - void *var=settings->getOptionCustom(key); - o.load_func(var); - delete static_cast(var); - } - break; - } - }; - if(key.length())load_opt(key); - else for(std::string& key:settings->optionlist) - load_opt(key); + auto load_opt = [this](std::string & key) + { + qmpOption &o = settings->options[key]; + switch (o.type) + { + case qmpOption::ParameterType::parameter_int: + { + QSpinBox *sb = qobject_cast(o.widget); + if (sb) + sb->setValue(settings->getOptionInt(key)); + } + break; + case qmpOption::ParameterType::parameter_uint: + { + QHexSpinBox *sb = qobject_cast(o.widget); + if (sb) + sb->setValue(settings->getOptionUint(key)); + } + break; + case qmpOption::ParameterType::parameter_bool: + { + QCheckBox *cb = qobject_cast(o.widget); + if (cb) + cb->setChecked(settings->getOptionBool(key)); + } + break; + case qmpOption::ParameterType::parameter_double: + { + QDoubleSpinBox *sb = qobject_cast(o.widget); + if (sb) + sb->setValue(settings->getOptionDouble(key)); + } + break; + case qmpOption::ParameterType::parameter_str: + { + QLineEdit *le = qobject_cast(o.widget); + if (le) + le->setText(QString(settings->getOptionString(key).c_str())); + } + break; + case qmpOption::ParameterType::parameter_enum: + { + QComboBox *cb = qobject_cast(o.widget); + if (cb) + cb->setCurrentIndex(settings->getOptionEnumInt(key)); + } + break; + case qmpOption::ParameterType::parameter_url: + { + QFileEdit *fe = qobject_cast(o.widget); + if (fe) + fe->setText(QString(settings->getOptionString(key).c_str())); + } + break; + default: + if (o.load_func) + { + void *var = settings->getOptionCustom(key); + o.load_func(var); + delete static_cast(var); + } + break; + } + }; + if (key.length()) + load_opt(key); + else for (std::string &key : settings->optionlist) + load_opt(key); } void qmpSettingsWindow::setupWidgets() { - for(std::string& key:settings->optionlist) - { - if(!settings->options[key].desc.length()&&settings->options[key].type!=qmpOption::ParameterType::parameter_custom) - continue; - QWidget *optw=nullptr; - qmpOption &o=settings->options[key]; - switch(o.type) - { - case qmpOption::ParameterType::parameter_int: - { - QSpinBox *sb=new QSpinBox; - sb->setMinimum(o.minv.toInt()); - sb->setMaximum(o.maxv.toInt()); - sb->setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Fixed); - optw=sb; - } - break; - case qmpOption::ParameterType::parameter_uint: - { - QHexSpinBox *sb=new QHexSpinBox; - sb->setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Fixed); - optw=sb; - } - break; - case qmpOption::ParameterType::parameter_bool: - { - QCheckBox *cb=new QCheckBox(QString(o.desc.c_str())); - cb->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); - optw=cb; - } - break; - case qmpOption::ParameterType::parameter_double: - { - QDoubleSpinBox *sb=new QDoubleSpinBox; - sb->setMinimum(o.minv.toDouble()); - sb->setMaximum(o.maxv.toDouble()); - sb->setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Fixed); - optw=sb; - } - break; - case qmpOption::ParameterType::parameter_str: - { - QLineEdit* te=new QLineEdit(); - te->setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Fixed); - optw=te; - } - break; - case qmpOption::ParameterType::parameter_enum: - { - QComboBox* cb=new QComboBox(); - for(std::string& item:o.enumlist)cb->addItem(QString(item.c_str())); - cb->setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Fixed); - optw=cb; - } - break; - case qmpOption::ParameterType::parameter_url: - { - QFileEdit* fe=new QFileEdit(); - fe->setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Fixed); - optw=fe; - } - break; - default: - optw=o.widget; - break; - } - o.widget=optw; - QGridLayout* page=pageForTab(o.tab); - if(o.type==qmpOption::ParameterType::parameter_bool|| - (o.type==qmpOption::parameter_custom&&!o.desc.length())) - { - int row=page->rowCount(); - page->addWidget(o.widget,row,0,1,2); - } - else - { - QLabel* lb=new QLabel(o.desc.c_str(),page->parentWidget()); - lb->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); - int row=page->rowCount(); - page->addWidget(lb,row,0); - page->addWidget(o.widget,row,1); - } - } - loadOption(); + for (std::string &key : settings->optionlist) + { + if (!settings->options[key].desc.length() && settings->options[key].type != qmpOption::ParameterType::parameter_custom) + continue; + QWidget *optw = nullptr; + qmpOption &o = settings->options[key]; + switch (o.type) + { + case qmpOption::ParameterType::parameter_int: + { + QSpinBox *sb = new QSpinBox; + sb->setMinimum(o.minv.toInt()); + sb->setMaximum(o.maxv.toInt()); + sb->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + optw = sb; + } + break; + case qmpOption::ParameterType::parameter_uint: + { + QHexSpinBox *sb = new QHexSpinBox; + sb->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + optw = sb; + } + break; + case qmpOption::ParameterType::parameter_bool: + { + QCheckBox *cb = new QCheckBox(QString(o.desc.c_str())); + cb->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + optw = cb; + } + break; + case qmpOption::ParameterType::parameter_double: + { + QDoubleSpinBox *sb = new QDoubleSpinBox; + sb->setMinimum(o.minv.toDouble()); + sb->setMaximum(o.maxv.toDouble()); + sb->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + optw = sb; + } + break; + case qmpOption::ParameterType::parameter_str: + { + QLineEdit *te = new QLineEdit(); + te->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + optw = te; + } + break; + case qmpOption::ParameterType::parameter_enum: + { + QComboBox *cb = new QComboBox(); + for (std::string &item : o.enumlist) + cb->addItem(QString(item.c_str())); + cb->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + optw = cb; + } + break; + case qmpOption::ParameterType::parameter_url: + { + QFileEdit *fe = new QFileEdit(); + fe->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + optw = fe; + } + break; + default: + optw = o.widget; + break; + } + o.widget = optw; + QGridLayout *page = pageForTab(o.tab); + if (o.type == qmpOption::ParameterType::parameter_bool || + (o.type == qmpOption::parameter_custom && !o.desc.length())) + { + int row = page->rowCount(); + page->addWidget(o.widget, row, 0, 1, 2); + } + else + { + QLabel *lb = new QLabel(o.desc.c_str(), page->parentWidget()); + lb->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + int row = page->rowCount(); + page->addWidget(lb, row, 0); + page->addWidget(o.widget, row, 1); + } + } + loadOption(); } -QGridLayout* qmpSettingsWindow::pageForTab(std::string tab) +QGridLayout *qmpSettingsWindow::pageForTab(std::string tab) { - if(customOptPages.find(tab)!=customOptPages.end()) - return customOptPages[tab]; - QWidget* w=new QWidget; - QGridLayout* page=new QGridLayout(w); - w->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); - ui->tabWidget->addTab(w,QString(tab.c_str())); - customOptPages[tab]=page; - return page; + if (customOptPages.find(tab) != customOptPages.end()) + return customOptPages[tab]; + QWidget *w = new QWidget; + QGridLayout *page = new QGridLayout(w); + w->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + ui->tabWidget->addTab(w, QString(tab.c_str())); + customOptPages[tab] = page; + return page; } -QFileEdit::QFileEdit(QWidget *par):QWidget(par) +QFileEdit::QFileEdit(QWidget *par): QWidget(par) { - QHBoxLayout *layout=new QHBoxLayout(this); - layout->setMargin(0); - le=new QLineEdit(this); - layout->addWidget(le); - tb=new QToolButton(this); - tb->setText("..."); - layout->addWidget(tb); - connect(tb,&QToolButton::clicked,this,&QFileEdit::chooseFile); + QHBoxLayout *layout = new QHBoxLayout(this); + layout->setMargin(0); + le = new QLineEdit(this); + layout->addWidget(le); + tb = new QToolButton(this); + tb->setText("..."); + layout->addWidget(tb); + connect(tb, &QToolButton::clicked, this, &QFileEdit::chooseFile); +} +QString QFileEdit::text() +{ + return le->text(); +} +void QFileEdit::setText(const QString &s) +{ + le->setText(s); } -QString QFileEdit::text(){return le->text();} -void QFileEdit::setText(const QString& s){le->setText(s);} void QFileEdit::chooseFile() { - QString s=QFileDialog::getOpenFileName(nullptr,tr("Select a file"),QFileInfo(text()).dir().absolutePath()); - if(s.length())setText(s); + QString s = QFileDialog::getOpenFileName(nullptr, tr("Select a file"), QFileInfo(text()).dir().absolutePath()); + if (s.length()) + setText(s); } diff --git a/qmidiplayer-desktop/qmpsettingswindow.hpp b/qmidiplayer-desktop/qmpsettingswindow.hpp index 5243ca9..c564c01 100644 --- a/qmidiplayer-desktop/qmpsettingswindow.hpp +++ b/qmidiplayer-desktop/qmpsettingswindow.hpp @@ -17,98 +17,108 @@ #include "qmpcustomizewindow.hpp" #include "qmpdevpropdialog.hpp" -namespace Ui { - class qmpSettingsWindow; +namespace Ui +{ +class qmpSettingsWindow; } class QLineEdit; class QToolButton; -class QFileEdit:public QWidget +class QFileEdit : public QWidget { - Q_OBJECT - private: - QLineEdit *le; - QToolButton *tb; - private slots: - void chooseFile(); - public: - QFileEdit(QWidget* par=nullptr); - QString text(); - void setText(const QString& s); + Q_OBJECT +private: + QLineEdit *le; + QToolButton *tb; +private slots: + void chooseFile(); +public: + QFileEdit(QWidget *par = nullptr); + QString text(); + void setText(const QString &s); }; -class QHexSpinBox:public QSpinBox +class QHexSpinBox: public QSpinBox { - Q_OBJECT - public: - QHexSpinBox(QWidget *parent=0):QSpinBox(parent) - { - setPrefix("0x"); - setDisplayIntegerBase(16); - setRange(-0x80000000,0x7FFFFFFF); - } - protected: - QString textFromValue(int value)const - { - return QString::number(u(value),16).toUpper(); - } - int valueFromText(const QString &text)const - { - return i(text.toUInt(nullptr,16)); - } - QValidator::State validate(QString &input,int &pos)const - { - QString t=input; - if(t.startsWith("0x"))t.remove(0,2); - pos-=t.size()-t.trimmed().size();t=t.trimmed(); - if(t.isEmpty())return QValidator::Intermediate; - input=QString("0x")+t.toUpper(); - bool okay;t.toUInt(&okay,16); - if(!okay)return QValidator::Invalid; - return QValidator::Acceptable; - } - inline unsigned int u(int i)const - {return reinterpret_cast(i);} - inline int i(unsigned int u)const - {return reinterpret_cast(u);} + Q_OBJECT +public: + QHexSpinBox(QWidget *parent = nullptr) : QSpinBox(parent) + { + setPrefix("0x"); + setDisplayIntegerBase(16); + setRange(-0x80000000, 0x7FFFFFFF); + } +protected: + QString textFromValue(int value)const + { + return QString::number(u(value), 16).toUpper(); + } + int valueFromText(const QString &text)const + { + return i(text.toUInt(nullptr, 16)); + } + QValidator::State validate(QString &input, int &pos)const + { + QString t = input; + if (t.startsWith("0x")) + t.remove(0, 2); + pos -= t.size() - t.trimmed().size(); + t = t.trimmed(); + if (t.isEmpty()) + return QValidator::Intermediate; + input = QString("0x") + t.toUpper(); + bool okay; + t.toUInt(&okay, 16); + if (!okay) + return QValidator::Invalid; + return QValidator::Acceptable; + } + inline unsigned int u(int i)const + { + return reinterpret_cast(i); + } + inline int i(unsigned int u)const + { + return reinterpret_cast(u); + } }; class qmpDevicePriorityDialog; -class qmpSettingsWindow:public QDialog +class qmpSettingsWindow : public QDialog { - Q_OBJECT + Q_OBJECT - public: - explicit qmpSettingsWindow(qmpSettings *qmpsettings,QWidget *parent=nullptr); - ~qmpSettingsWindow(); - void closeEvent(QCloseEvent *event); - void hideEvent(QHideEvent *event); - void updatePluginList(qmpPluginManager *pmgr); - void postInit(); - void registerCustomizeWidgetOptions(); - void registerSoundFontOption(); - void registerPluginOption(qmpPluginManager *pmgr); - void registerExtraMidiOptions(); - signals: - void dialogClosing(); +public: + explicit qmpSettingsWindow(qmpSettings *qmpsettings, QWidget *parent = nullptr); + ~qmpSettingsWindow(); + void closeEvent(QCloseEvent *event); + void hideEvent(QHideEvent *event); + void updatePluginList(qmpPluginManager *pmgr); + void postInit(); + void registerCustomizeWidgetOptions(); + void registerSoundFontOption(); + void registerPluginOption(qmpPluginManager *pmgr); + void registerExtraMidiOptions(); +signals: + void dialogClosing(); - private slots: - void on_buttonBox_accepted(); - void on_buttonBox_rejected(); +private slots: + void on_buttonBox_accepted(); + void on_buttonBox_rejected(); - private: - Ui::qmpSettingsWindow *ui; - std::map customOptions; - std::map customOptPages; - void saveOption(std::string key=std::string()); - void loadOption(std::string key=std::string()); - void setupWidgets(); - QGridLayout* pageForTab(std::string tab); - qmpCustomizeWindow *cwt,*cwa; - qmpDevPropDialog *dps; - qmpDevicePriorityDialog *devpriod; - qmpSettings *settings; +private: + Ui::qmpSettingsWindow *ui; + std::map customOptions; + std::map customOptPages; + void saveOption(std::string key = std::string()); + void loadOption(std::string key = std::string()); + void setupWidgets(); + QGridLayout *pageForTab(std::string tab); + qmpCustomizeWindow *cwt, *cwa; + qmpDevPropDialog *dps; + qmpDevicePriorityDialog *devpriod; + qmpSettings *settings; }; #endif // QMPSETTINGSWINDOW_H diff --git a/qmidiplayer-lite/main.cpp b/qmidiplayer-lite/main.cpp index 1a87b33..f0f9af6 100644 --- a/qmidiplayer-lite/main.cpp +++ b/qmidiplayer-lite/main.cpp @@ -5,11 +5,11 @@ int main(int argc, char *argv[]) { - QApplication app(argc, argv); - qmlRegisterType("org.chrisoft.qmpcore",1,0,"CQMPCoreWrapper"); + QApplication app(argc, argv); + qmlRegisterType("org.chrisoft.qmpcore", 1, 0, "CQMPCoreWrapper"); - QQmlApplicationEngine engine; - engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); + QQmlApplicationEngine engine; + engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); - return app.exec(); + return app.exec(); } diff --git a/qmidiplayer-lite/qmpcorewrapper.hpp b/qmidiplayer-lite/qmpcorewrapper.hpp index 090edc7..07dff65 100644 --- a/qmidiplayer-lite/qmpcorewrapper.hpp +++ b/qmidiplayer-lite/qmpcorewrapper.hpp @@ -5,56 +5,66 @@ #include #include #include "../core/qmpmidiplay.hpp" -class CQMPCoreWrapper:public QObject +class CQMPCoreWrapper: public QObject { - Q_OBJECT + Q_OBJECT private: - CMidiPlayer *mp; - std::thread *playerTh; - int curprog; + CMidiPlayer *mp; + std::thread *playerTh; + int curprog; public: - explicit CQMPCoreWrapper(QObject* parent=0):QObject(parent) - { - mp=new CMidiPlayer(); - } - ~CQMPCoreWrapper(){delete mp;} - Q_INVOKABLE void initFluidSynth(QUrl sfpath) - { - mp->fluid()->setOptStr("audio.driver","pulseaudio"); - mp->fluid()->deviceInit(); - mp->fluid()->loadSFont(sfpath.toLocalFile().toStdString().c_str()); - for(int i=0;i<16;++i) - mp->setChannelOutput(i,0); - } - Q_INVOKABLE void deinitFluidSynth() - { - mp->fluid()->deviceDeinit(); - } - Q_INVOKABLE void loadFile(QUrl file) - { - mp->playerLoadFile(file.toLocalFile().toStdString().c_str()); - mp->playerInit();curprog=0; - } - Q_INVOKABLE void playFile() - { - playerTh=new std::thread(&CMidiPlayer::playerThread,mp); - } - Q_INVOKABLE void stop() - { - mp->playerDeinit();playerTh->join();delete playerTh; - mp->playerPanic(); - } - Q_INVOKABLE int getProgress() - { - while(!mp->isFinished()&&mp->getTCeptr()>mp->getStamp(curprog) - &&curprog<=100) - ++curprog; - return curprog; - } - Q_INVOKABLE void panic(){mp->playerPanic();} - Q_INVOKABLE void setTCeptr(int perct) - { - mp->setTCeptr(mp->getStamp(perct),perct);curprog=perct; - } + explicit CQMPCoreWrapper(QObject *parent = 0): QObject(parent) + { + mp = new CMidiPlayer(); + } + ~CQMPCoreWrapper() + { + delete mp; + } + Q_INVOKABLE void initFluidSynth(QUrl sfpath) + { + mp->fluid()->setOptStr("audio.driver", "pulseaudio"); + mp->fluid()->deviceInit(); + mp->fluid()->loadSFont(sfpath.toLocalFile().toStdString().c_str()); + for (int i = 0; i < 16; ++i) + mp->setChannelOutput(i, 0); + } + Q_INVOKABLE void deinitFluidSynth() + { + mp->fluid()->deviceDeinit(); + } + Q_INVOKABLE void loadFile(QUrl file) + { + mp->playerLoadFile(file.toLocalFile().toStdString().c_str()); + mp->playerInit(); + curprog = 0; + } + Q_INVOKABLE void playFile() + { + playerTh = new std::thread(&CMidiPlayer::playerThread, mp); + } + Q_INVOKABLE void stop() + { + mp->playerDeinit(); + playerTh->join(); + delete playerTh; + mp->playerPanic(); + } + Q_INVOKABLE int getProgress() + { + while (!mp->isFinished() && mp->getTCeptr() > mp->getStamp(curprog) + && curprog <= 100) + ++curprog; + return curprog; + } + Q_INVOKABLE void panic() + { + mp->playerPanic(); + } + Q_INVOKABLE void setTCeptr(int perct) + { + mp->setTCeptr(mp->getStamp(perct), perct); + curprog = perct; + } }; #endif // QMPCOREWRAPPER_H diff --git a/qmidiplayer-lite/qmpmidiplay.cpp b/qmidiplayer-lite/qmpmidiplay.cpp index baec9a2..017de20 100644 --- a/qmidiplayer-lite/qmpmidiplay.cpp +++ b/qmidiplayer-lite/qmpmidiplay.cpp @@ -9,398 +9,531 @@ uint64_t pf; #endif void CMidiPlayer::fluidPreInitialize() { - settings=new_fluid_settings(); + settings = new_fluid_settings(); } void CMidiPlayer::fluidInitialize() { - synth=new_fluid_synth(settings); - adriver=new_fluid_audio_driver(settings,synth); - fluid_synth_set_chorus(synth,FLUID_CHORUS_DEFAULT_N,FLUID_CHORUS_DEFAULT_LEVEL, - FLUID_CHORUS_DEFAULT_SPEED,FLUID_CHORUS_DEFAULT_DEPTH, - FLUID_CHORUS_DEFAULT_TYPE); + synth = new_fluid_synth(settings); + adriver = new_fluid_audio_driver(settings, synth); + fluid_synth_set_chorus(synth, FLUID_CHORUS_DEFAULT_N, FLUID_CHORUS_DEFAULT_LEVEL, + FLUID_CHORUS_DEFAULT_SPEED, FLUID_CHORUS_DEFAULT_DEPTH, + FLUID_CHORUS_DEFAULT_TYPE); #ifndef _WIN32 - if(!singleInstance) - { - if(midiFile->getStandard()==4) - fluid_synth_set_channel_type(synth,9,CHANNEL_TYPE_MELODIC); - else if(midiFile->getStandard()==1) - fluid_synth_set_channel_type(synth,9,CHANNEL_TYPE_DRUM); - else - { - fluid_synth_set_channel_type(synth,9,CHANNEL_TYPE_DRUM); - fluid_synth_bank_select(synth,9,128); - } - } + if (!singleInstance) + { + if (midiFile->getStandard() == 4) + fluid_synth_set_channel_type(synth, 9, CHANNEL_TYPE_MELODIC); + else if (midiFile->getStandard() == 1) + fluid_synth_set_channel_type(synth, 9, CHANNEL_TYPE_DRUM); + else + { + fluid_synth_set_channel_type(synth, 9, CHANNEL_TYPE_DRUM); + fluid_synth_bank_select(synth, 9, 128); + } + } #endif } void CMidiPlayer::fluidDeinitialize() { - if(!synth||!adriver||!settings)return; - delete_fluid_settings(settings); - delete_fluid_audio_driver(adriver); - delete_fluid_synth(synth); - settings=NULL;synth=NULL;adriver=NULL; + if (!synth || !adriver || !settings)return; + delete_fluid_settings(settings); + delete_fluid_audio_driver(adriver); + delete_fluid_synth(synth); + settings = NULL; + synth = NULL; + adriver = NULL; } void CMidiPlayer::processEvent(const SEvent *e) { - switch(e->type&0xF0) - { - case 0x80://Note off - fluid_synth_noteoff(synth,e->type&0x0F,e->p1); - break; - case 0x90://Note on - if((mute>>(e->type&0x0F))&1)break;//muted - if(solo&&!((solo>>(e->type&0x0F))&1))break; - fluid_synth_noteon(synth,e->type&0x0F,e->p1,e->p2); - break; - case 0xB0://CC - if(e->p1==100)rpnid=e->p2; - if(e->p1==6)rpnval=e->p2; - if(~rpnid&&~rpnval) - { - if(rpnid==0)fluid_synth_pitch_wheel_sens(synth,e->type&0x0F,rpnval); - rpnid=rpnval=-1; - } - fluid_synth_cc(synth,e->type&0x0F,e->p1,e->p2); - break; - case 0xC0://PC - fluid_synth_program_change(synth,e->type&0x0F,e->p1); - break; - case 0xE0://PW - fluid_synth_pitch_bend(synth,e->type&0x0F,e->p1); - break; - case 0xF0://Meta/SysEx - if((e->type&0x0F)==0x0F) - { - switch(e->p1) - { - case 0x51: - ctempo=e->p2;dpt=ctempo*1000/divs; - break; - case 0x58: - ctsn=e->p2>>24; - ctsd=1<<((e->p2>>16)&0xFF); - break; - case 0x59: - cks=e->p2; - break; - case 0x01:case 0x02:case 0x03: - case 0x04:case 0x05:case 0x06: - case 0x07: - if(e->str)puts(e->str); - break; - } - } - if((e->type&0x0F)==0x00||(e->type&0x0F)==07) - { - int io=0; - if(sendSysEx)fluid_synth_sysex(synth,e->str,e->p1,NULL,&io,NULL,0); - } - break; - } + switch (e->type & 0xF0) + { + case 0x80://Note off + fluid_synth_noteoff(synth, e->type & 0x0F, e->p1); + break; + case 0x90://Note on + if ((mute >> (e->type & 0x0F)) & 1)break; //muted + if (solo && !((solo >> (e->type & 0x0F)) & 1))break; + fluid_synth_noteon(synth, e->type & 0x0F, e->p1, e->p2); + break; + case 0xB0://CC + if (e->p1 == 100)rpnid = e->p2; + if (e->p1 == 6)rpnval = e->p2; + if (~rpnid && ~rpnval) + { + if (rpnid == 0)fluid_synth_pitch_wheel_sens(synth, e->type & 0x0F, rpnval); + rpnid = rpnval = -1; + } + fluid_synth_cc(synth, e->type & 0x0F, e->p1, e->p2); + break; + case 0xC0://PC + fluid_synth_program_change(synth, e->type & 0x0F, e->p1); + break; + case 0xE0://PW + fluid_synth_pitch_bend(synth, e->type & 0x0F, e->p1); + break; + case 0xF0://Meta/SysEx + if ((e->type & 0x0F) == 0x0F) + { + switch (e->p1) + { + case 0x51: + ctempo = e->p2; + dpt = ctempo * 1000 / divs; + break; + case 0x58: + ctsn = e->p2 >> 24; + ctsd = 1 << ((e->p2 >> 16) & 0xFF); + break; + case 0x59: + cks = e->p2; + break; + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + if (e->str)puts(e->str); + break; + } + } + if ((e->type & 0x0F) == 0x00 || (e->type & 0x0F) == 07) + { + int io = 0; + if (sendSysEx)fluid_synth_sysex(synth, e->str, e->p1, NULL, &io, NULL, 0); + } + break; + } } void CMidiPlayer::processEventStub(const SEvent *e) { - switch(e->type&0xF0) - { - case 0xB0://CC - if(e->p1==100)rpnid=e->p2; - if(e->p1==6)rpnval=e->p2; - if(~rpnid&&~rpnval) - { - if(rpnid==0)ccc[e->type&0x0F][134]=rpnval; - rpnid=rpnval=-1; - } - ccc[e->type&0x0F][e->p1]=e->p2; - break; - case 0xC0://PC - ccc[e->type&0x0F][128]=e->p1; - break; - case 0xD0://CP - ccc[e->type&0x0F][129]=e->p1; - break; - case 0xE0://PW - ccc[e->type&0x0F][130]=e->p1; - break; - case 0xF0://Meta/SysEx - if((e->type&0x0F)==0x0F) - { - switch(e->p1) - { - case 0x51: - ctempo=e->p2;dpt=ctempo*1000/divs; - ccc[0][131]=dpt; - break; - case 0x58: - ccc[0][132]=e->p2; - break; - case 0x59: - ccc[0][133]=e->p2; - break; - } - } - break; - } + switch (e->type & 0xF0) + { + case 0xB0://CC + if (e->p1 == 100)rpnid = e->p2; + if (e->p1 == 6)rpnval = e->p2; + if (~rpnid && ~rpnval) + { + if (rpnid == 0)ccc[e->type & 0x0F][134] = rpnval; + rpnid = rpnval = -1; + } + ccc[e->type & 0x0F][e->p1] = e->p2; + break; + case 0xC0://PC + ccc[e->type & 0x0F][128] = e->p1; + break; + case 0xD0://CP + ccc[e->type & 0x0F][129] = e->p1; + break; + case 0xE0://PW + ccc[e->type & 0x0F][130] = e->p1; + break; + case 0xF0://Meta/SysEx + if ((e->type & 0x0F) == 0x0F) + { + switch (e->p1) + { + case 0x51: + ctempo = e->p2; + dpt = ctempo * 1000 / divs; + ccc[0][131] = dpt; + break; + case 0x58: + ccc[0][132] = e->p2; + break; + case 0x59: + ccc[0][133] = e->p2; + break; + } + } + break; + } } #ifdef _WIN32 void w32usleep(uint64_t t) { - uint64_t st=0,ct=0; - QueryPerformanceCounter((LARGE_INTEGER*)&st); - do{ - if(t>10000+(ct-st)*1000000/pf)Sleep((t-(ct-st)*1000000/pf)/2000); - else if(t>5000+(ct-st)*1000000/pf)Sleep(1); - else std::this_thread::yield(); - QueryPerformanceCounter((LARGE_INTEGER*)&ct); - }while((ct-st)*1000000 10000 + (ct - st) * 1000000 / pf)Sleep((t - (ct - st) * 1000000 / pf) / 2000); + else if (t > 5000 + (ct - st) * 1000000 / pf)Sleep(1); + else std::this_thread::yield(); + QueryPerformanceCounter((LARGE_INTEGER *)&ct); + } while ((ct - st) * 1000000 < t * pf); } #endif void CMidiPlayer::playEvents() { - for(uint32_t ct=midiFile->getEvent(0)->time;tceptrgetEventCount();) - { - while(tcpaused)std::this_thread::sleep_for(std::chrono::milliseconds(100)); - while(!tcstop&&midiFile&&tceptrgetEventCount()&&ct==midiFile->getEvent(tceptr)->time) - processEvent(midiFile->getEvent(tceptr++)); - if(tcstop||!midiFile||tceptr>=midiFile->getEventCount())break; - if(resumed)resumed=false; - else + for (uint32_t ct = midiFile->getEvent(0)->time; tceptr < midiFile->getEventCount();) + { + while (tcpaused)std::this_thread::sleep_for(std::chrono::milliseconds(100)); + while (!tcstop && midiFile && tceptr < midiFile->getEventCount() && ct == midiFile->getEvent(tceptr)->time) + processEvent(midiFile->getEvent(tceptr++)); + if (tcstop || !midiFile || tceptr >= midiFile->getEventCount())break; + if (resumed)resumed = false; + else #ifdef _WIN32 - w32usleep((midiFile->getEvent(tceptr)->time-ct)*(dpt/1000)); + w32usleep((midiFile->getEvent(tceptr)->time - ct) * (dpt / 1000)); #else - std::this_thread::sleep_for(std::chrono::nanoseconds(midiFile->getEvent(tceptr)->time-ct)*dpt); + std::this_thread::sleep_for(std::chrono::nanoseconds(midiFile->getEvent(tceptr)->time - ct)*dpt); #endif - if(tcstop||!midiFile)break; - ct=midiFile->getEvent(tceptr)->time; - } - while(!tcstop&&synth&&(waitvoice&&fluid_synth_get_active_voice_count(synth)>0))std::this_thread::sleep_for(std::chrono::milliseconds(2)); - finished=1; + if (tcstop || !midiFile)break; + ct = midiFile->getEvent(tceptr)->time; + } + while (!tcstop && synth && (waitvoice && fluid_synth_get_active_voice_count(synth) > 0))std::this_thread::sleep_for(std::chrono::milliseconds(2)); + finished = 1; } void CMidiPlayer::fileTimer1Pass() { - ftime=.0;ctempo=0x7A120;dpt=ctempo*1000/divs; - for(uint32_t eptr=0,ct=midiFile->getEvent(0)->time;eptrgetEventCount();) - { - while(eptrgetEventCount()&&ct==midiFile->getEvent(eptr)->time) - processEventStub(midiFile->getEvent(eptr++)); - if(eptr>=midiFile->getEventCount())break; - ftime+=(midiFile->getEvent(eptr)->time-ct)*dpt/1e9; - ct=midiFile->getEvent(eptr)->time; - } + ftime = .0; + ctempo = 0x7A120; + dpt = ctempo * 1000 / divs; + for (uint32_t eptr = 0, ct = midiFile->getEvent(0)->time; eptr < midiFile->getEventCount();) + { + while (eptr < midiFile->getEventCount() && ct == midiFile->getEvent(eptr)->time) + processEventStub(midiFile->getEvent(eptr++)); + if (eptr >= midiFile->getEventCount())break; + ftime += (midiFile->getEvent(eptr)->time - ct) * dpt / 1e9; + ct = midiFile->getEvent(eptr)->time; + } } void CMidiPlayer::fileTimer2Pass() { - double ctime=.0;uint32_t c=1;ctempo=0x7A120;dpt=ctempo*1000/divs; - memset(stamps,0,sizeof(stamps));memset(ccstamps,0,sizeof(ccstamps)); - memset(ccc,0,sizeof(ccc));rpnid=rpnval=-1;for(int i=0;i<16;++i) - { - ccc[i][7]=100;ccc[i][10]=64;ccc[i][11]=127; - ccc[i][11]=127;ccc[i][71]=64;ccc[i][72]=64; - ccc[i][73]=64;ccc[i][74]=64;ccc[i][75]=64; - ccc[i][76]=64;ccc[i][77]=64;ccc[i][78]=64; - ccc[0][131]=dpt;ccc[0][132]=0x04021808; - ccc[0][133]=0;ccc[0][134]=2; - }if(midiFile->getStandard()!=4)ccc[9][0]=128; - for(int i=0;i<16;++i)for(int j=0;j<135;++j) - ccstamps[0][i][j]=ccc[i][j]; - for(uint32_t eptr=0,ct=midiFile->getEvent(0)->time;eptrgetEventCount();) - { - while(eptrgetEventCount()&&ct==midiFile->getEvent(eptr)->time) - processEventStub(midiFile->getEvent(eptr++)); - if(eptr>=midiFile->getEventCount())break; - ctime+=(midiFile->getEvent(eptr)->time-ct)*dpt/1e9; - while(ctime>ftime*c/100.) - { - for(int i=0;i<16;++i)for(int j=0;j<135;++j) - ccstamps[c][i][j]=ccc[i][j]; - stamps[c++]=eptr; - if(c>100)break; - } - ct=midiFile->getEvent(eptr)->time; - } - while(c<101) - { - for(int i=0;i<16;++i)for(int j=0;j<135;++j) - ccstamps[c][i][j]=ccc[i][j]; - stamps[c++]=midiFile->getEventCount(); - } + double ctime = .0; + uint32_t c = 1; + ctempo = 0x7A120; + dpt = ctempo * 1000 / divs; + memset(stamps, 0, sizeof(stamps)); + memset(ccstamps, 0, sizeof(ccstamps)); + memset(ccc, 0, sizeof(ccc)); + rpnid = rpnval = -1; + for (int i = 0; i < 16; ++i) + { + ccc[i][7] = 100; + ccc[i][10] = 64; + ccc[i][11] = 127; + ccc[i][11] = 127; + ccc[i][71] = 64; + ccc[i][72] = 64; + ccc[i][73] = 64; + ccc[i][74] = 64; + ccc[i][75] = 64; + ccc[i][76] = 64; + ccc[i][77] = 64; + ccc[i][78] = 64; + ccc[0][131] = dpt; + ccc[0][132] = 0x04021808; + ccc[0][133] = 0; + ccc[0][134] = 2; + } + if (midiFile->getStandard() != 4)ccc[9][0] = 128; + for (int i = 0; i < 16; ++i)for (int j = 0; j < 135; ++j) + ccstamps[0][i][j] = ccc[i][j]; + for (uint32_t eptr = 0, ct = midiFile->getEvent(0)->time; eptr < midiFile->getEventCount();) + { + while (eptr < midiFile->getEventCount() && ct == midiFile->getEvent(eptr)->time) + processEventStub(midiFile->getEvent(eptr++)); + if (eptr >= midiFile->getEventCount())break; + ctime += (midiFile->getEvent(eptr)->time - ct) * dpt / 1e9; + while (ctime > ftime * c / 100.) + { + for (int i = 0; i < 16; ++i)for (int j = 0; j < 135; ++j) + ccstamps[c][i][j] = ccc[i][j]; + stamps[c++] = eptr; + if (c > 100)break; + } + ct = midiFile->getEvent(eptr)->time; + } + while (c < 101) + { + for (int i = 0; i < 16; ++i)for (int j = 0; j < 135; ++j) + ccstamps[c][i][j] = ccc[i][j]; + stamps[c++] = midiFile->getEventCount(); + } } CMidiPlayer::CMidiPlayer(bool singleInst) { - midiFile=NULL;resumed=false;singleInstance=singleInst; - settings=NULL;synth=NULL;adriver=NULL;waitvoice=true; + midiFile = NULL; + resumed = false; + singleInstance = singleInst; + settings = NULL; + synth = NULL; + adriver = NULL; + waitvoice = true; #ifdef _WIN32 - QueryPerformanceFrequency((LARGE_INTEGER*)&pf); - timeBeginPeriod(1); + QueryPerformanceFrequency((LARGE_INTEGER *)&pf); + timeBeginPeriod(1); #endif } CMidiPlayer::~CMidiPlayer() { - if(singleInstance)fluidDeinitialize(); + if (singleInstance)fluidDeinitialize(); #ifdef _WIN32 - timeEndPeriod(1); + timeEndPeriod(1); #endif } void CMidiPlayer::playerPanic(bool reset) { - if(reset)for(int i=0;i<16;++i) - { - fluid_synth_pitch_bend(synth,i,8192); - fluid_synth_cc(synth,i,7,100); - fluid_synth_cc(synth,i,10,64); - fluid_synth_cc(synth,i,11,127); - } - for(int i=0;i<16;++i)fluid_synth_all_notes_off(synth,i); + if (reset)for (int i = 0; i < 16; ++i) + { + fluid_synth_pitch_bend(synth, i, 8192); + fluid_synth_cc(synth, i, 7, 100); + fluid_synth_cc(synth, i, 10, 64); + fluid_synth_cc(synth, i, 11, 127); + } + for (int i = 0; i < 16; ++i)fluid_synth_all_notes_off(synth, i); } -bool CMidiPlayer::playerLoadFile(const char* fn) +bool CMidiPlayer::playerLoadFile(const char *fn) { - midiFile=new CMidiFile(fn); - if(!midiFile->isValid())return false; - divs=midiFile->getDivision(); - fileTimer1Pass(); - fileTimer2Pass(); - return true; + midiFile = new CMidiFile(fn); + if (!midiFile->isValid())return false; + divs = midiFile->getDivision(); + fileTimer1Pass(); + fileTimer2Pass(); + return true; } void CMidiPlayer::playerInit() { - ctempo=0x7A120;ctsn=4;ctsd=4;cks=0;dpt=ctempo*1000/divs; - tceptr=0;tcstop=0;tcpaused=0;finished=0;mute=solo=0; - sendSysEx=true;rpnid=rpnval=-1; - if(!singleInstance)fluidPreInitialize(); + ctempo = 0x7A120; + ctsn = 4; + ctsd = 4; + cks = 0; + dpt = ctempo * 1000 / divs; + tceptr = 0; + tcstop = 0; + tcpaused = 0; + finished = 0; + mute = solo = 0; + sendSysEx = true; + rpnid = rpnval = -1; + if (!singleInstance)fluidPreInitialize(); } void CMidiPlayer::playerDeinit() { - tceptr=0;tcstop=1;tcpaused=0; - delete midiFile;midiFile=NULL; - if(!singleInstance)fluidDeinitialize(); + tceptr = 0; + tcstop = 1; + tcpaused = 0; + delete midiFile; + midiFile = NULL; + if (!singleInstance)fluidDeinitialize(); } void CMidiPlayer::playerThread() { - playEvents(); + playEvents(); } -void CMidiPlayer::rendererLoadFile(const char* ofn) +void CMidiPlayer::rendererLoadFile(const char *ofn) { - settings=new_fluid_settings(); - fluid_settings_setstr(settings,"audio.file.name",ofn); + settings = new_fluid_settings(); + fluid_settings_setstr(settings, "audio.file.name", ofn); } -void CMidiPlayer::rendererInit(const char* fn) +void CMidiPlayer::rendererInit(const char *fn) { - finished=0; - synth=new_fluid_synth(settings); - player=new_fluid_player(synth); - fluid_player_add(player,fn); + finished = 0; + synth = new_fluid_synth(settings); + player = new_fluid_player(synth); + fluid_player_add(player, fn); } void CMidiPlayer::rendererThread() { - fluid_file_renderer_t* renderer=new_fluid_file_renderer(synth); - fluid_player_play(player); - while(fluid_player_get_status(player)==FLUID_PLAYER_PLAYING) - if(fluid_file_renderer_process_block(renderer)!=FLUID_OK)break; - delete_fluid_file_renderer(renderer); - finished=1; + fluid_file_renderer_t *renderer = new_fluid_file_renderer(synth); + fluid_player_play(player); + while (fluid_player_get_status(player) == FLUID_PLAYER_PLAYING) + if (fluid_file_renderer_process_block(renderer) != FLUID_OK)break; + delete_fluid_file_renderer(renderer); + finished = 1; } void CMidiPlayer::rendererDeinit() { - delete_fluid_player(player); - delete_fluid_synth(synth); - delete_fluid_settings(settings); - player=NULL;synth=NULL;settings=NULL; + delete_fluid_player(player); + delete_fluid_synth(synth); + delete_fluid_settings(settings); + player = NULL; + synth = NULL; + settings = NULL; } -void CMidiPlayer::sendSysX(bool send){sendSysEx=send;} -uint32_t CMidiPlayer::getStamp(int id){return stamps[id];} -uint32_t CMidiPlayer::getTCeptr(){return tceptr;} -void CMidiPlayer::setTCeptr(uint32_t ep,uint32_t st) -{ - resumed=true; - if(ep==midiFile->getEventCount())tcstop=1;else tceptr=ep; - for(int i=0;i<16;++i) - { - for(int j=0;j<120;++j)fluid_synth_cc(synth,i,j,ccstamps[st][i][j]); - fluid_synth_program_change(synth,i,ccstamps[st][i][128]); - //fluid_synth_pitch_bend(synth,i,ccstamps[st][i][130]); - dpt=ccstamps[st][0][131];ctempo=dpt*divs/1000; - ctsn=ccstamps[st][0][132]>>24;ctsd=1<<((ccstamps[st][0][132]>>16)&0xFF); - cks=ccstamps[st][0][133]; - } -} -double CMidiPlayer::getFtime(){return ftime;} -void CMidiPlayer::getCurrentTimeSignature(int *n,int *d){*n=ctsn;*d=ctsd;} -void CMidiPlayer::getCurrentKeySignature(int *ks){*ks=cks;} -uint32_t CMidiPlayer::getFileNoteCount(){return midiFile?midiFile->getNoteCount():0;} -uint32_t CMidiPlayer::getFileStandard(){return midiFile?midiFile->getStandard():0;} -const char* CMidiPlayer::getTitle(){return midiFile?midiFile->getTitle():"";} -const char* CMidiPlayer::getCopyright(){return midiFile?midiFile->getCopyright():"";} -double CMidiPlayer::getTempo(){return 60./(ctempo/1e6)/**ctsd/4.*/;} -uint32_t CMidiPlayer::getTCpaused(){return tcpaused;} -void CMidiPlayer::setTCpaused(uint32_t ps){tcpaused=ps;} -uint32_t CMidiPlayer::isFinished(){return finished;} -void CMidiPlayer::setResumed(){resumed=true;} -void CMidiPlayer::setWaitVoice(bool wv){waitvoice=wv;} -void CMidiPlayer::setGain(double gain){if(settings)fluid_settings_setnum(settings,"synth.gain",gain);} -int CMidiPlayer::getPolyphone(){return synth?fluid_synth_get_active_voice_count(synth):0;} -int CMidiPlayer::getMaxPolyphone(){return synth?fluid_synth_get_polyphony(synth):0;} -void CMidiPlayer::setMaxPolyphone(int p){if(synth)fluid_synth_set_polyphony(synth,p);} +void CMidiPlayer::sendSysX(bool send) +{ + sendSysEx = send; +} +uint32_t CMidiPlayer::getStamp(int id) +{ + return stamps[id]; +} +uint32_t CMidiPlayer::getTCeptr() +{ + return tceptr; +} +void CMidiPlayer::setTCeptr(uint32_t ep, uint32_t st) +{ + resumed = true; + if (ep == midiFile->getEventCount())tcstop = 1; + else tceptr = ep; + for (int i = 0; i < 16; ++i) + { + for (int j = 0; j < 120; ++j)fluid_synth_cc(synth, i, j, ccstamps[st][i][j]); + fluid_synth_program_change(synth, i, ccstamps[st][i][128]); + //fluid_synth_pitch_bend(synth,i,ccstamps[st][i][130]); + dpt = ccstamps[st][0][131]; + ctempo = dpt * divs / 1000; + ctsn = ccstamps[st][0][132] >> 24; + ctsd = 1 << ((ccstamps[st][0][132] >> 16) & 0xFF); + cks = ccstamps[st][0][133]; + } +} +double CMidiPlayer::getFtime() +{ + return ftime; +} +void CMidiPlayer::getCurrentTimeSignature(int *n, int *d) +{ + *n = ctsn; + *d = ctsd; +} +void CMidiPlayer::getCurrentKeySignature(int *ks) +{ + *ks = cks; +} +uint32_t CMidiPlayer::getFileNoteCount() +{ + return midiFile ? midiFile->getNoteCount() : 0; +} +uint32_t CMidiPlayer::getFileStandard() +{ + return midiFile ? midiFile->getStandard() : 0; +} +const char *CMidiPlayer::getTitle() +{ + return midiFile ? midiFile->getTitle() : ""; +} +const char *CMidiPlayer::getCopyright() +{ + return midiFile ? midiFile->getCopyright() : ""; +} +double CMidiPlayer::getTempo() +{ + return 60. / (ctempo / 1e6)/**ctsd/4.*/; +} +uint32_t CMidiPlayer::getTCpaused() +{ + return tcpaused; +} +void CMidiPlayer::setTCpaused(uint32_t ps) +{ + tcpaused = ps; +} +uint32_t CMidiPlayer::isFinished() +{ + return finished; +} +void CMidiPlayer::setResumed() +{ + resumed = true; +} +void CMidiPlayer::setWaitVoice(bool wv) +{ + waitvoice = wv; +} +void CMidiPlayer::setGain(double gain) +{ + if (settings)fluid_settings_setnum(settings, "synth.gain", gain); +} +int CMidiPlayer::getPolyphone() +{ + return synth ? fluid_synth_get_active_voice_count(synth) : 0; +} +int CMidiPlayer::getMaxPolyphone() +{ + return synth ? fluid_synth_get_polyphony(synth) : 0; +} +void CMidiPlayer::setMaxPolyphone(int p) +{ + if (synth)fluid_synth_set_polyphony(synth, p); +} -void CMidiPlayer::getChannelPreset(int ch,int *b,int *p,char *name) +void CMidiPlayer::getChannelPreset(int ch, int *b, int *p, char *name) { - if(!synth)return(void)(b=0,p=0,strcpy(name,"")); - fluid_synth_channel_info_t info; - fluid_synth_get_channel_info(synth,ch,&info); - *b=info.bank;*p=info.program; - strcpy(name,info.name); + if (!synth)return (void)(b = 0, p = 0, strcpy(name, "")); + fluid_synth_channel_info_t info; + fluid_synth_get_channel_info(synth, ch, &info); + *b = info.bank; + *p = info.program; + strcpy(name, info.name); } -void CMidiPlayer::setChannelPreset(int ch,int b,int p) +void CMidiPlayer::setChannelPreset(int ch, int b, int p) { - if(!synth)return; - fluid_synth_bank_select(synth,ch,b); - fluid_synth_program_change(synth,ch,p); + if (!synth)return; + fluid_synth_bank_select(synth, ch, b); + fluid_synth_program_change(synth, ch, p); } //16MSB..LSB1 void CMidiPlayer::setBit(uint16_t &n, uint16_t bn, uint16_t b) -{n^=(-b^n)&(1< struct SEvent { - uint32_t iid,time,p1,p2; - uint8_t type; - char *str; - SEvent(){time=p1=p2=0;type=0;str=NULL;} - SEvent(uint32_t _iid,uint32_t _t,char _tp,uint32_t _p1,uint32_t _p2,const char* s=NULL) - { - iid=_iid;time=_t;type=_tp; - p1=_p1;p2=_p2; - if(s){str=new char[strlen(s)+2];strcpy(str,s);}else str=NULL; - } + uint32_t iid, time, p1, p2; + uint8_t type; + char *str; + SEvent() + { + time = p1 = p2 = 0; + type = 0; + str = NULL; + } + SEvent(uint32_t _iid, uint32_t _t, char _tp, uint32_t _p1, uint32_t _p2, const char *s = NULL) + { + iid = _iid; + time = _t; + type = _tp; + p1 = _p1; + p2 = _p2; + if (s) + { + str = new char[strlen(s) + 2]; + strcpy(str, s); + } + else str = NULL; + } }; class CMidiFile { - private: - SEvent *eventList[10000000]; - char *title,*copyright; - uint32_t eventc,std;//standard 0=? 1=GM 2=GM2 3=GS 4=XG - uint32_t fmt,trk,divs; - FILE *f; - int byteread,valid; - uint32_t notes,curt,curid; +private: + SEvent *eventList[10000000]; + char *title, *copyright; + uint32_t eventc, std; //standard 0=? 1=GM 2=GM2 3=GS 4=XG + uint32_t fmt, trk, divs; + FILE *f; + int byteread, valid; + uint32_t notes, curt, curid; - void error(int fatal,const char* format,...); - uint32_t readSW(); - uint32_t readDW(); - uint32_t readVL(); - int eventReader(); - void trackChunkReader(); - void headerChunkReader(); - int chunkReader(int hdrXp); - public: - CMidiFile(const char* fn); - ~CMidiFile(); - const SEvent* getEvent(uint32_t id); - uint32_t getEventCount(); - uint32_t getDivision(); - uint32_t getNoteCount(); - uint32_t getStandard(); - const char* getTitle(); - const char* getCopyright(); - bool isValid(); + void error(int fatal, const char *format, ...); + uint32_t readSW(); + uint32_t readDW(); + uint32_t readVL(); + int eventReader(); + void trackChunkReader(); + void headerChunkReader(); + int chunkReader(int hdrXp); +public: + CMidiFile(const char *fn); + ~CMidiFile(); + const SEvent *getEvent(uint32_t id); + uint32_t getEventCount(); + uint32_t getDivision(); + uint32_t getNoteCount(); + uint32_t getStandard(); + const char *getTitle(); + const char *getCopyright(); + bool isValid(); }; class CMidiPlayer { - private: - CMidiFile *midiFile; - uint32_t stamps[101]; - 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,rpnval; - uint16_t mute,solo; - double ftime; - bool sendSysEx,singleInstance,waitvoice; - fluid_settings_t* settings; - fluid_synth_t* synth; - fluid_audio_driver_t* adriver; - fluid_player_t* player; - uint32_t ctempo,ctsn,ctsd,dpt,divs,cks; - //raw tempo, timesig num., timesig den., delay per tick, division, keysig - //thread control - uint32_t tceptr,tcpaused,tcstop; - uint32_t finished,resumed; +private: + CMidiFile *midiFile; + uint32_t stamps[101]; + 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, rpnval; + uint16_t mute, solo; + double ftime; + bool sendSysEx, singleInstance, waitvoice; + fluid_settings_t *settings; + fluid_synth_t *synth; + fluid_audio_driver_t *adriver; + fluid_player_t *player; + uint32_t ctempo, ctsn, ctsd, dpt, divs, cks; + //raw tempo, timesig num., timesig den., delay per tick, division, keysig + //thread control + uint32_t tceptr, tcpaused, tcstop; + uint32_t finished, resumed; - void setBit(uint16_t &n,uint16_t bn,uint16_t b); - void processEvent(const SEvent *e); - void processEventStub(const SEvent *e); - void playEvents(); - void fileTimer1Pass(); - void fileTimer2Pass(); - public: - CMidiPlayer(bool singleInst=false); - ~CMidiPlayer(); - bool playerLoadFile(const char* fn); - void playerInit(); - void fluidPreInitialize(); - void fluidInitialize(); - void fluidDeinitialize(); - void playerDeinit(); - void playerThread(); - void playerPanic(bool reset=false); + void setBit(uint16_t &n, uint16_t bn, uint16_t b); + void processEvent(const SEvent *e); + void processEventStub(const SEvent *e); + void playEvents(); + void fileTimer1Pass(); + void fileTimer2Pass(); +public: + CMidiPlayer(bool singleInst = false); + ~CMidiPlayer(); + bool playerLoadFile(const char *fn); + void playerInit(); + void fluidPreInitialize(); + void fluidInitialize(); + void fluidDeinitialize(); + void playerDeinit(); + void playerThread(); + void playerPanic(bool reset = false); - void rendererLoadFile(const char* ofn); - void rendererInit(const char *fn); - void rendererThread(); - void rendererDeinit(); + void rendererLoadFile(const char *ofn); + void rendererInit(const char *fn); + void rendererThread(); + void rendererDeinit(); - //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); - uint32_t isFinished(); - void setResumed(); - void setWaitVoice(bool wv); + //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); + uint32_t isFinished(); + void setResumed(); + void setWaitVoice(bool wv); - double getFtime(); - void getCurrentTimeSignature(int *n,int *d); - void getCurrentKeySignature(int *ks); - uint32_t getFileNoteCount(); - uint32_t getFileStandard(); - double getTempo(); - const char* getTitle(); - const char* getCopyright(); + double getFtime(); + void getCurrentTimeSignature(int *n, int *d); + void getCurrentKeySignature(int *ks); + uint32_t getFileNoteCount(); + uint32_t getFileStandard(); + double getTempo(); + const char *getTitle(); + const char *getCopyright(); - void setGain(double gain); - void sendSysX(bool send); - int getPolyphone(); - int getMaxPolyphone(); - void setMaxPolyphone(int p); + void setGain(double gain); + void sendSysX(bool send); + int getPolyphone(); + int getMaxPolyphone(); + void setMaxPolyphone(int p); - void setChannelPreset(int ch,int b,int p); - void getChannelPreset(int ch,int *b,int *p,char *name); - void setMute(int ch,bool m); - void setSolo(int ch,bool s); - int getCC(int ch,int id); - void setCC(int ch,int id,int val); - void getReverbPara(double *r,double *d,double *w,double *l); - void setReverbPara(int e,double r,double d,double w,double l); - void getChorusPara(int *fb,double *l,double *r,double *d,int *type); - void setChorusPara(int e,int fb,double l,double r,double d,int type); + void setChannelPreset(int ch, int b, int p); + void getChannelPreset(int ch, int *b, int *p, char *name); + void setMute(int ch, bool m); + void setSolo(int ch, bool s); + int getCC(int ch, int id); + void setCC(int ch, int id, int val); + void getReverbPara(double *r, double *d, double *w, double *l); + void setReverbPara(int e, double r, double d, double w, double l); + void getChorusPara(int *fb, double *l, double *r, double *d, int *type); + void setChorusPara(int e, int fb, double l, double r, double d, int type); - fluid_settings_t* getFluidSettings(); - void pushSoundFont(const char* sf); - int getSFCount(); - fluid_sfont_t* getSFPtr(int sfid); + fluid_settings_t *getFluidSettings(); + void pushSoundFont(const char *sf); + int getSFCount(); + fluid_sfont_t *getSFPtr(int sfid); }; #endif diff --git a/qmidiplayer-lite/qmpmidiread.cpp b/qmidiplayer-lite/qmpmidiread.cpp index 0bcf597..227aa7d 100644 --- a/qmidiplayer-lite/qmpmidiread.cpp +++ b/qmidiplayer-lite/qmpmidiread.cpp @@ -8,233 +8,348 @@ #include #include #include "qmpmidiplay.hpp" -const char* GM1SysX={"\xF0\x7E\x7F\x09\x01\xF7"}; -const char* GM2SysX={"\xF0\x7E\x7F\x09\x03\xF7"}; -const char* GSSysEx={"\xF0\x41\x10\x42\x12\x40\x00\x7F\x00\x41\xF7"}; -const char* XGSysEx={"\xF0\x43\x10\x4C\x00\x00\x7E\x00\xF7"}; -bool cmp(SEvent *a,SEvent *b){return a->time-b->time?a->timetime:a->iidiid;} -void CMidiFile::error(int fatal,const char* format,...) -{ - va_list ap; - va_start(ap,format);vfprintf(stderr,format,ap);va_end(ap); - fprintf(stderr," at %#lx\n",ftell(f)); - if(fatal)throw 2; +const char *GM1SysX = {"\xF0\x7E\x7F\x09\x01\xF7"}; +const char *GM2SysX = {"\xF0\x7E\x7F\x09\x03\xF7"}; +const char *GSSysEx = {"\xF0\x41\x10\x42\x12\x40\x00\x7F\x00\x41\xF7"}; +const char *XGSysEx = {"\xF0\x43\x10\x4C\x00\x00\x7E\x00\xF7"}; +bool cmp(SEvent *a, SEvent *b) +{ + return a->time - b->time ? a->time < b->time : a->iid < b->iid; +} +void CMidiFile::error(int fatal, const char *format, ...) +{ + va_list ap; + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + fprintf(stderr, " at %#lx\n", ftell(f)); + if (fatal)throw 2; } uint32_t CMidiFile::readSW() { - byteread+=2; - uint32_t ret=0; - for(int i=0;i<2;++i){ret<<=8;ret|=((uint32_t)fgetc(f))&0xFF;} - return ret; + byteread += 2; + uint32_t ret = 0; + for (int i = 0; i < 2; ++i) + { + ret <<= 8; + ret |= ((uint32_t)fgetc(f)) & 0xFF; + } + return ret; } uint32_t CMidiFile::readDW() { - byteread+=4; - uint32_t ret=0; - for(int i=0;i<4;++i){ret<<=8;ret|=((uint32_t)fgetc(f))&0xFF;} - return ret; + byteread += 4; + uint32_t ret = 0; + for (int i = 0; i < 4; ++i) + { + ret <<= 8; + ret |= ((uint32_t)fgetc(f)) & 0xFF; + } + return ret; } uint32_t CMidiFile::readVL() { - uint32_t ret=0,t,c=0; - do - { - t=fgetc(f); - if(++c>4)error(1,"E: Variable length type overflow."); - ret<<=7;ret|=(t&0x7F); - }while(t&0x80); - byteread+=c; - return ret; + uint32_t ret = 0, t, c = 0; + do + { + t = fgetc(f); + if (++c > 4)error(1, "E: Variable length type overflow."); + ret <<= 7; + ret |= (t & 0x7F); + } while (t & 0x80); + byteread += c; + return ret; } int CMidiFile::eventReader()//returns 0 if End of Track encountered { - uint32_t delta=readVL();curt+=delta; - char type=fgetc(f);++byteread;uint32_t p1,p2; - static char lasttype; + uint32_t delta = readVL(); + curt += delta; + char type = fgetc(f); + ++byteread; + uint32_t p1, p2; + static char lasttype; retry: - switch(type&0xF0) - { - case 0x80://Note Off - p1=fgetc(f);p2=fgetc(f);byteread+=2; - eventList[eventc++]=new SEvent(curid,curt,type,p1,p2); - break; - case 0x90://Note On - p1=fgetc(f);p2=fgetc(f);byteread+=2; - if(p2) - { - ++notes; - eventList[eventc++]=new SEvent(curid,curt,type,p1,p2); - } - else - eventList[eventc++]=new SEvent(curid,curt,(type&0x0F)|0x80,p1,p2); - break; - case 0xA0://Note Aftertouch - p1=fgetc(f);p2=fgetc(f);byteread+=2; - eventList[eventc++]=new SEvent(curid,curt,type,p1,p2); - break; - case 0xB0://Controller Change - p1=fgetc(f);p2=fgetc(f);byteread+=2; - eventList[eventc++]=new SEvent(curid,curt,type,p1,p2); - break; - case 0xC0://Patch Change - p1=fgetc(f);++byteread; - eventList[eventc++]=new SEvent(curid,curt,type,p1,0); - break; - case 0xD0://Channel Aftertouch - p1=fgetc(f);++byteread; - eventList[eventc++]=new SEvent(curid,curt,type,p1,0); - break; - case 0xE0://Pitch wheel - p1=fgetc(f);p2=fgetc(f);byteread+=2; - eventList[eventc++]=new SEvent(curid,curt,type,(p1|(p2<<7))&0x3FFF,0); - break; - case 0xF0: - if((type&0x0F)==0x0F)//Meta Event - { - char metatype=fgetc(f);++byteread; - switch(metatype) - { - case 0x00://Sequence Number - fgetc(f);fgetc(f);fgetc(f); - byteread+=3; - break; - case 0x20://Channel Prefix - fgetc(f);fgetc(f);byteread+=2; - break; - case 0x2F://End of Track - fgetc(f);++byteread; - return 0; - break; - case 0x51://Set Tempo - p1=readDW();p1&=0x00FFFFFF; - eventList[eventc++]=new SEvent(curid,curt,type,metatype,p1); - break; - case 0x54://SMTPE offset, not handled. - fgetc(f);fgetc(f);fgetc(f); - fgetc(f);fgetc(f);fgetc(f); - byteread+=6; - break; - case 0x58://Time signature - fgetc(f);++byteread; - p1=readDW(); - eventList[eventc++]=new SEvent(curid,curt,type,metatype,p1); - break; - case 0x59://Key signature - fgetc(f);++byteread; - p1=readSW(); - eventList[eventc++]=new SEvent(curid,curt,type,metatype,p1); - break; - case 0x01:case 0x02:case 0x03: - case 0x04:case 0x05:case 0x06: - case 0x07:case 0x7F:default://text-like meta - { - uint32_t len=readVL(),c;char* str=NULL; - if(len<=1024&&len>0)str=new char[len+8]; - for(c=0;c0)delete[] str; - } - } - } - else if((type&0x0F)==0x00||(type&0x0F)==0x07)//SysEx - { - uint32_t len=readVL(),c;char* str=NULL; - str=new char[len+8]; - if((type&0x0F)==0x00) - { - str[0]=0xF0;++len; - for(c=1;c 0)str = new char[len + 8]; + for (c = 0; c < len; ++c) + { + ++byteread; + if (str)str[c] = fgetc(f); + else fgetc(f); + } + if (str)str[c] = '\0'; + eventList[eventc++] = new SEvent(curid, curt, type, metatype, 0, str); + if (str && metatype == 0x03 && !title) + { + title = new char[len + 8]; + strcpy(title, str); + } + if (str && metatype == 0x02 && !copyright) + { + copyright = new char[len + 8]; + strcpy(copyright, str); + } + if (len <= 1024 && len > 0)delete[] str; + } + } + } + else if ((type & 0x0F) == 0x00 || (type & 0x0F) == 0x07) //SysEx + { + uint32_t len = readVL(), c; + char *str = NULL; + str = new char[len + 8]; + if ((type & 0x0F) == 0x00) + { + str[0] = 0xF0; + ++len; + for (c = 1; c < len; ++c) + { + ++byteread; + str[c] = fgetc(f); + } + } + else for (c = 0; c < len; ++c) + { + ++byteread; + str[c] = fgetc(f); + } + eventList[eventc++] = new SEvent(curid, curt, type, len, 0, str); + if (!strcmp(str, GM1SysX))std = 1; + if (!strcmp(str, GM2SysX))std = 2; + if (!strcmp(str, GSSysEx))std = 3; + if (!strcmp(str, XGSysEx))std = 4; + } + else error(0, "W: Unknown event type %#x", type); + break; + default: + fseek(f, -1, SEEK_CUR); + --byteread; + type = lasttype; + goto retry; + } + lasttype = type; + ++curid; + return 1; } void CMidiFile::trackChunkReader() { - int chnklen=readDW();byteread=0;curt=0;curid=0; - while(/*bytereadchnklen) - { - error(1,"E: Read past end of track."); - }*/ + int chnklen = readDW(); + byteread = 0; + curt = 0; + curid = 0; + while (/*bytereadchnklen) + { + error(1,"E: Read past end of track."); + }*/ } void CMidiFile::headerChunkReader() { - int chnklen=readDW();byteread=0; - if(chnklen<6)error(1,"E: Header chunk too short."); - if(chnklen>6)error(0,"W: Header chunk length longer than expected. Ignoring extra bytes."); - fmt=readSW();trk=readSW();divs=readSW(); - if(divs&0x8000)error(1,"E: SMTPE format is not supported."); - for(;byteread 6)error(0, "W: Header chunk length longer than expected. Ignoring extra bytes."); + fmt = readSW(); + trk = readSW(); + divs = readSW(); + if (divs & 0x8000)error(1, "E: SMTPE format is not supported."); + for (; byteread < chnklen; ++byteread) + { + fgetc(f); + } } int CMidiFile::chunkReader(int hdrXp) { - char hdr[6]; - if(!fgets(hdr,5,f))error(1,"E: Unexpected EOF."); - if(hdrXp) - if(strncmp(hdr,"MThd",4)){error(1,"E: Wrong MIDI header.");throw;} - else return headerChunkReader(),0; - else - if(strncmp(hdr,"MTrk",4)) - { - error(0,"W: Wrong track chunk header. Ignoring the whole chunk."); - for(int chnklen=readDW();chnklen>0;--chnklen)fgetc(f);return 0; - } - else return trackChunkReader(),1; -} -CMidiFile::CMidiFile(const char* fn) -{ - title=copyright=NULL;notes=eventc=0;std=0;valid=1; - try - { - if(!(f=fopen(fn,"rb")))throw (fprintf(stderr,"E: file %s doesn't exist!\n",fn),2); - chunkReader(1); - for(uint32_t i=0;i 0; --chnklen)fgetc(f); + return 0; + } + else return trackChunkReader(), 1; +} +CMidiFile::CMidiFile(const char *fn) +{ + title = copyright = NULL; + notes = eventc = 0; + std = 0; + valid = 1; + try + { + if (!(f = fopen(fn, "rb")))throw (fprintf(stderr, "E: file %s doesn't exist!\n", fn), 2); + chunkReader(1); + for (uint32_t i = 0; i < trk; i += chunkReader(0)); + printf("%d note(s)\n", notes); + fclose(f); + std::sort(eventList, eventList + eventc, cmp); + } + catch (int) + { + fprintf(stderr, "E: %s is not a supported file.\n", fn); + valid = 0; + } } CMidiFile::~CMidiFile() { - for(uint32_t i=0;i #include "sampleplugin.hpp" -qmpSamplePlugin::qmpSamplePlugin(qmpPluginAPI* _api){api=_api;} -qmpSamplePlugin::~qmpSamplePlugin(){api=nullptr;} +qmpSamplePlugin::qmpSamplePlugin(qmpPluginAPI *_api) +{ + api = _api; +} +qmpSamplePlugin::~qmpSamplePlugin() +{ + api = nullptr; +} void qmpSamplePlugin::init() -{fputs("Hello world from plugin init!\n",stderr);} +{ + fputs("Hello world from plugin init!\n", stderr); +} void qmpSamplePlugin::deinit() -{fputs("Bye!\n",stderr);} -const char* qmpSamplePlugin::pluginGetName(){return "QMidiPlayer Sample Plugin";} -const char* qmpSamplePlugin::pluginGetVersion(){return "0.0.0";} +{ + fputs("Bye!\n", stderr); +} +const char *qmpSamplePlugin::pluginGetName() +{ + return "QMidiPlayer Sample Plugin"; +} +const char *qmpSamplePlugin::pluginGetVersion() +{ + return "0.0.0"; +} diff --git a/sample-plugin/sampleplugin.hpp b/sample-plugin/sampleplugin.hpp index ffb3d77..7c981c1 100644 --- a/sample-plugin/sampleplugin.hpp +++ b/sample-plugin/sampleplugin.hpp @@ -3,24 +3,28 @@ #include "../include/qmpcorepublic.hpp" -class qmpSamplePlugin:public qmpPluginIntf +class qmpSamplePlugin: public qmpPluginIntf { - private: - qmpPluginAPI* api; - public: - qmpSamplePlugin(qmpPluginAPI* _api); - ~qmpSamplePlugin(); - void init(); - void deinit(); - const char* pluginGetName(); - const char* pluginGetVersion(); +private: + qmpPluginAPI *api; +public: + qmpSamplePlugin(qmpPluginAPI *_api); + ~qmpSamplePlugin(); + void init(); + void deinit(); + const char *pluginGetName(); + const char *pluginGetVersion(); }; -extern "C"{ - EXPORTSYM qmpPluginIntf* qmpPluginGetInterface(qmpPluginAPI* api) - {return new qmpSamplePlugin(api);} - EXPORTSYM const char* qmpPluginGetAPIRev() - {return QMP_PLUGIN_API_REV;} +extern "C" { + EXPORTSYM qmpPluginIntf *qmpPluginGetInterface(qmpPluginAPI *api) + { + return new qmpSamplePlugin(api); + } + EXPORTSYM const char *qmpPluginGetAPIRev() + { + return QMP_PLUGIN_API_REV; + } } #endif // SAMPLEPLUGIN_H diff --git a/simple-visualization/qmpkeyboardwindow.cpp b/simple-visualization/qmpkeyboardwindow.cpp index 2c5e70a..b33bb4b 100644 --- a/simple-visualization/qmpkeyboardwindow.cpp +++ b/simple-visualization/qmpkeyboardwindow.cpp @@ -6,66 +6,69 @@ #include "qmppianowidget.hpp" #include "qmpkeyboardwindow.hpp" -qmpKeyboardWindow::qmpKeyboardWindow(qmpPluginAPI *_api,QWidget *parent): - QWidget(parent,Qt::Dialog),api(_api) +qmpKeyboardWindow::qmpKeyboardWindow(qmpPluginAPI *_api, QWidget *parent): + QWidget(parent, Qt::Dialog), api(_api) { - setWindowTitle("Keyboard"); - QGridLayout *grid; - setLayout(grid=new QGridLayout()); - for(int ch=0;ch<16;++ch) - { - grid->addWidget(lb[ch]=new QLabel,ch,0); - grid->addWidget(pw[ch]=new qmpPianoWidget(this),ch,1); - lb[ch]->setFont(QFontDatabase::systemFont(QFontDatabase::SystemFont::FixedFont)); - pw[ch]->setSizePolicy(QSizePolicy::Policy::Expanding,QSizePolicy::Policy::Preferred); - QPalette p=palette(); - p.setColor(QPalette::ColorRole::Highlight,api->getOptionUint("Keyboard/acolor"+std::to_string(ch))); - p.setColor(QPalette::ColorRole::Base,api->getOptionUint("Keyboard/bcolor"+std::to_string(ch))); - pw[ch]->setPalette(p); - } - hide(); - eh=api->registerEventHandler( - [this](const void* ee,void*){ - const SEvent *e=(const SEvent*)ee; - int ch=e->type&0xF; - if((e->type&0xF0)==0x80||((e->type&0xF0)==0x90&&e->p2==0)) - emit keystateupdated(ch,e->p1,false); - if((e->type&0xF0)==0x90&&e->p2>0) - emit keystateupdated(ch,e->p1,e->p2>0); - if((e->type&0xF0)==0xB0||(e->type&0xF0)==0xC0) - lb[ch]->setText( - QString::fromStdString(api->getChannelPresetString(ch))+ - QString("\nch:%1 v:0x%2 p:0x%3 e:0x%4") - .arg(ch+1,2,10,QChar('0')) - .arg(api->getChannelCC(ch,0x7),2,16,QChar('0')) - .arg(api->getChannelCC(ch,0xa),2,16,QChar('0')) - .arg(api->getChannelCC(ch,0xb),2,16,QChar('0'))); - } - ,nullptr,true); - connect(this,&qmpKeyboardWindow::keystateupdated,this,&qmpKeyboardWindow::onkeystatesupdate); + setWindowTitle("Keyboard"); + QGridLayout *grid; + setLayout(grid = new QGridLayout()); + for (int ch = 0; ch < 16; ++ch) + { + grid->addWidget(lb[ch] = new QLabel, ch, 0); + grid->addWidget(pw[ch] = new qmpPianoWidget(this), ch, 1); + lb[ch]->setFont(QFontDatabase::systemFont(QFontDatabase::SystemFont::FixedFont)); + pw[ch]->setSizePolicy(QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Preferred); + QPalette p = palette(); + p.setColor(QPalette::ColorRole::Highlight, api->getOptionUint("Keyboard/acolor" + std::to_string(ch))); + p.setColor(QPalette::ColorRole::Base, api->getOptionUint("Keyboard/bcolor" + std::to_string(ch))); + pw[ch]->setPalette(p); + } + hide(); + eh = api->registerEventHandler( + [this](const void *ee, void *) + { + const SEvent *e = (const SEvent *)ee; + int ch = e->type & 0xF; + if ((e->type & 0xF0) == 0x80 || ((e->type & 0xF0) == 0x90 && e->p2 == 0)) + emit keystateupdated(ch, e->p1, false); + if ((e->type & 0xF0) == 0x90 && e->p2 > 0) + emit keystateupdated(ch, e->p1, e->p2 > 0); + if ((e->type & 0xF0) == 0xB0 || (e->type & 0xF0) == 0xC0) + lb[ch]->setText( + QString::fromStdString(api->getChannelPresetString(ch)) + + QString("\nch:%1 v:0x%2 p:0x%3 e:0x%4") + .arg(ch + 1, 2, 10, QChar('0')) + .arg(api->getChannelCC(ch, 0x7), 2, 16, QChar('0')) + .arg(api->getChannelCC(ch, 0xa), 2, 16, QChar('0')) + .arg(api->getChannelCC(ch, 0xb), 2, 16, QChar('0'))); + } + , nullptr, true); + connect(this, &qmpKeyboardWindow::keystateupdated, this, &qmpKeyboardWindow::onkeystatesupdate); } qmpKeyboardWindow::~qmpKeyboardWindow() { - api->unregisterEventHandler(eh); + api->unregisterEventHandler(eh); } void qmpKeyboardWindow::closeEvent(QCloseEvent *event) { - api->setFuncState("Keyboard",false); - event->accept(); + api->setFuncState("Keyboard", false); + event->accept(); +} +void qmpKeyboardWindow::onkeystatesupdate(int ch, int key, bool state) +{ + pw[ch]->setKeyState(key, state); } -void qmpKeyboardWindow::onkeystatesupdate(int ch,int key,bool state) -{pw[ch]->setKeyState(key,state);} void qmpKeyboardWindow::resetAll() { - for(int ch=0;ch<16;++ch) - { - pw[ch]->reset(); - lb[ch]->setText( - QString::fromStdString(api->getChannelPresetString(ch))+ - QString("\nch:%1 v:0x%2 p:0x%3 e:0x%4") - .arg(ch+1,2,10,QChar('0')) - .arg(api->getChannelCC(ch,0x7),2,16,QChar('0')) - .arg(api->getChannelCC(ch,0xa),2,16,QChar('0')) - .arg(api->getChannelCC(ch,0xb),2,16,QChar('0'))); - } + for (int ch = 0; ch < 16; ++ch) + { + pw[ch]->reset(); + lb[ch]->setText( + QString::fromStdString(api->getChannelPresetString(ch)) + + QString("\nch:%1 v:0x%2 p:0x%3 e:0x%4") + .arg(ch + 1, 2, 10, QChar('0')) + .arg(api->getChannelCC(ch, 0x7), 2, 16, QChar('0')) + .arg(api->getChannelCC(ch, 0xa), 2, 16, QChar('0')) + .arg(api->getChannelCC(ch, 0xb), 2, 16, QChar('0'))); + } } diff --git a/simple-visualization/qmpkeyboardwindow.hpp b/simple-visualization/qmpkeyboardwindow.hpp index 65ad266..b540cca 100644 --- a/simple-visualization/qmpkeyboardwindow.hpp +++ b/simple-visualization/qmpkeyboardwindow.hpp @@ -7,24 +7,24 @@ class QLabel; class qmpPianoWidget; -class qmpKeyboardWindow:public QWidget +class qmpKeyboardWindow: public QWidget { - Q_OBJECT - private: - qmpPianoWidget *pw[16]; - QLabel *lb[16]; - qmpPluginAPI *api; - int eh; - public: - qmpKeyboardWindow(qmpPluginAPI *_api,QWidget *parent); - ~qmpKeyboardWindow(); - void resetAll(); - protected: - void closeEvent(QCloseEvent *event); - signals: - void keystateupdated(int ch,int key,bool state); - public slots: - void onkeystatesupdate(int ch,int key,bool state); + Q_OBJECT +private: + qmpPianoWidget *pw[16]; + QLabel *lb[16]; + qmpPluginAPI *api; + int eh; +public: + qmpKeyboardWindow(qmpPluginAPI *_api, QWidget *parent); + ~qmpKeyboardWindow(); + void resetAll(); +protected: + void closeEvent(QCloseEvent *event); +signals: + void keystateupdated(int ch, int key, bool state); +public slots: + void onkeystatesupdate(int ch, int key, bool state); }; #endif diff --git a/simple-visualization/qmppianowidget.cpp b/simple-visualization/qmppianowidget.cpp index daeff25..05a84ed 100644 --- a/simple-visualization/qmppianowidget.cpp +++ b/simple-visualization/qmppianowidget.cpp @@ -4,82 +4,83 @@ qmpPianoWidget::qmpPianoWidget(QWidget *parent) : QWidget(parent) { - memset(keystates,0,sizeof(keystates)); - QPalette p=palette(); - p.setColor(QPalette::ColorRole::Highlight,0xff66cc); - p.setColor(QPalette::ColorRole::Base,0x66ccff); - setPalette(p); + memset(keystates, 0, sizeof(keystates)); + QPalette p = palette(); + p.setColor(QPalette::ColorRole::Highlight, 0xff66cc); + p.setColor(QPalette::ColorRole::Base, 0x66ccff); + setPalette(p); } -void qmpPianoWidget::setKeyState(int key,bool state) +void qmpPianoWidget::setKeyState(int key, bool state) { - keystates[key]=state; - update(); + keystates[key] = state; + update(); } void qmpPianoWidget::reset() { - memset(keystates,0,sizeof(keystates)); - update(); + memset(keystates, 0, sizeof(keystates)); + update(); } QSize qmpPianoWidget::minimumSizeHint()const { - return QSize(320,22); + return QSize(320, 22); } bool qmpPianoWidget::hasHeightForWidth()const { - return true; + return true; } int qmpPianoWidget::heightForWidth(int w)const { - return w*22/320; + return w * 22 / 320; } void qmpPianoWidget::paintEvent(QPaintEvent *event) { - Q_UNUSED(event) - for(int i=0;i<128;++i) - { - QRectF r=getKeyRect(i); - QColor activeColor=palette().color(QPalette::ColorRole::Highlight); - QColor inactiveColor=palette().color(QPalette::ColorRole::Base); - if(i/12%2) - { - if(inactiveColor.valueF()>0.5) - inactiveColor=inactiveColor.darker(112); - else - inactiveColor=inactiveColor.lighter(112); - } - paintKey(r,keystates[i]?activeColor:inactiveColor); - } + Q_UNUSED(event) + for (int i = 0; i < 128; ++i) + { + QRectF r = getKeyRect(i); + QColor activeColor = palette().color(QPalette::ColorRole::Highlight); + QColor inactiveColor = palette().color(QPalette::ColorRole::Base); + if (i / 12 % 2) + { + if (inactiveColor.valueF() > 0.5) + inactiveColor = inactiveColor.darker(112); + else + inactiveColor = inactiveColor.lighter(112); + } + paintKey(r, keystates[i] ? activeColor : inactiveColor); + } } QRectF qmpPianoWidget::getKeyRect(int key) { - int octave=key/12;key%=12; - bool is_black=(key<5&&(key&1))||(key>5&&((key&1)^1)); - double key_width=width()/75.; - QRectF ret(0,0,key_width,height()/2.); - if(!is_black) - { - ret.moveTop(height()/2.); - int shift=(key+(key>=5))>>1; - ret.moveLeft((octave*7+shift)*key_width); - } - else - ret.moveLeft((octave*7+(key+(key>=5))/2.)*key_width); - return ret; + int octave = key / 12; + key %= 12; + bool is_black = (key < 5 && (key & 1)) || (key > 5 && ((key & 1) ^ 1)); + double key_width = width() / 75.; + QRectF ret(0, 0, key_width, height() / 2.); + if (!is_black) + { + ret.moveTop(height() / 2.); + int shift = (key + (key >= 5)) >> 1; + ret.moveLeft((octave * 7 + shift)*key_width); + } + else + ret.moveLeft((octave * 7 + (key + (key >= 5)) / 2.)*key_width); + return ret; } -void qmpPianoWidget::paintKey(QRectF keyrect,QColor keycolor) +void qmpPianoWidget::paintKey(QRectF keyrect, QColor keycolor) { - QColor bordercolor(keycolor); - if(keycolor.valueF()>0.5) - bordercolor=bordercolor.darker(150); - else - bordercolor=bordercolor.lighter(150); - QPainter *p=new QPainter(this); - p->setPen(bordercolor); - p->setBrush(QBrush(keycolor)); - p->drawRect(keyrect.adjusted(1,1,-1,-1)); - delete p; + QColor bordercolor(keycolor); + if (keycolor.valueF() > 0.5) + bordercolor = bordercolor.darker(150); + else + bordercolor = bordercolor.lighter(150); + QPainter *p = new QPainter(this); + p->setPen(bordercolor); + p->setBrush(QBrush(keycolor)); + p->drawRect(keyrect.adjusted(1, 1, -1, -1)); + delete p; } diff --git a/simple-visualization/qmppianowidget.hpp b/simple-visualization/qmppianowidget.hpp index cca643c..aec034d 100644 --- a/simple-visualization/qmppianowidget.hpp +++ b/simple-visualization/qmppianowidget.hpp @@ -6,22 +6,22 @@ class qmpPianoWidget : public QWidget { - Q_OBJECT - public: - explicit qmpPianoWidget(QWidget *parent = nullptr); - void setKeyState(int key,bool state); - void reset(); - QSize minimumSizeHint()const override; - bool hasHeightForWidth()const override; - int heightForWidth(int w)const override; + Q_OBJECT +public: + explicit qmpPianoWidget(QWidget *parent = nullptr); + void setKeyState(int key, bool state); + void reset(); + QSize minimumSizeHint()const override; + bool hasHeightForWidth()const override; + int heightForWidth(int w)const override; - protected: - void paintEvent(QPaintEvent *event)override; +protected: + void paintEvent(QPaintEvent *event)override; - private: - bool keystates[128]; - QRectF getKeyRect(int key); - void paintKey(QRectF keyrect,QColor keycolor); +private: + bool keystates[128]; + QRectF getKeyRect(int key); + void paintKey(QRectF keyrect, QColor keycolor); }; #endif // QMPPIANOWIDGET_HPP diff --git a/simple-visualization/simplevisualization.cpp b/simple-visualization/simplevisualization.cpp index b93af30..0c3a5b9 100644 --- a/simple-visualization/simplevisualization.cpp +++ b/simple-visualization/simplevisualization.cpp @@ -1,33 +1,51 @@ #include "simplevisualization.hpp" #include "qmpkeyboardwindow.hpp" -qmpSimpleVisualization::qmpSimpleVisualization(qmpPluginAPI *_api){api=_api;} -void qmpSimpleVisualization::show(){p->show();} -void qmpSimpleVisualization::close(){p->close();} +qmpSimpleVisualization::qmpSimpleVisualization(qmpPluginAPI *_api) +{ + api = _api; +} +void qmpSimpleVisualization::show() +{ + p->show(); +} +void qmpSimpleVisualization::close() +{ + p->close(); +} void qmpSimpleVisualization::init() { - api->registerFunctionality(this,"Keyboard","Keyboard",api->isDarkTheme()?":/img/visualization_i.svg":":/img/visualization.svg",0,true); - for(int i=0;i<16;++i) - { - api->registerOptionUint("","","Keyboard/acolor"+std::to_string(i),0,0xffffff,0xffff66cc); - api->registerOptionUint("","","Keyboard/bcolor"+std::to_string(i),0,0xffffff,0xff66ccff); - } - p=new qmpKeyboardWindow(api,(QWidget*)api->getMainWindow()); - auto refreshfn=[this](const void*,void*){this->p->resetAll();}; - uihs=api->registerUIHook("main.stop",refreshfn,nullptr); - uihsk=api->registerUIHook("main.seek",refreshfn,nullptr); - uihsk=api->registerUIHook("preset.set",refreshfn,nullptr); - uihsk=api->registerUIHook("channel.ccchange",refreshfn,nullptr); + api->registerFunctionality(this, "Keyboard", "Keyboard", api->isDarkTheme() ? ":/img/visualization_i.svg" : ":/img/visualization.svg", 0, true); + for (int i = 0; i < 16; ++i) + { + api->registerOptionUint("", "", "Keyboard/acolor" + std::to_string(i), 0, 0xffffff, 0xffff66cc); + api->registerOptionUint("", "", "Keyboard/bcolor" + std::to_string(i), 0, 0xffffff, 0xff66ccff); + } + p = new qmpKeyboardWindow(api, (QWidget *)api->getMainWindow()); + auto refreshfn = [this](const void *, void *) + { + this->p->resetAll(); + }; + uihs = api->registerUIHook("main.stop", refreshfn, nullptr); + uihsk = api->registerUIHook("main.seek", refreshfn, nullptr); + uihsk = api->registerUIHook("preset.set", refreshfn, nullptr); + uihsk = api->registerUIHook("channel.ccchange", refreshfn, nullptr); } void qmpSimpleVisualization::deinit() { - if(!api)return;close(); - api->unregisterFunctionality("Keyboard"); - api->unregisterUIHook("main.stop",uihs); - api->unregisterUIHook("main.seek",uihsk); - delete p; + if (!api) + return; + close(); + api->unregisterFunctionality("Keyboard"); + api->unregisterUIHook("main.stop", uihs); + api->unregisterUIHook("main.seek", uihsk); + delete p; +} +const char *qmpSimpleVisualization::pluginGetName() +{ + return "QMidiPlayer Simple Visualization Plugin"; +} +const char *qmpSimpleVisualization::pluginGetVersion() +{ + return PLUGIN_VERSION; } -const char* qmpSimpleVisualization::pluginGetName() -{return "QMidiPlayer Simple Visualization Plugin";} -const char* qmpSimpleVisualization::pluginGetVersion() -{return PLUGIN_VERSION;} diff --git a/simple-visualization/simplevisualization.hpp b/simple-visualization/simplevisualization.hpp index 58b02ac..6d09cb6 100644 --- a/simple-visualization/simplevisualization.hpp +++ b/simple-visualization/simplevisualization.hpp @@ -4,28 +4,32 @@ #include "../include/qmpcorepublic.hpp" class qmpKeyboardWindow; -class qmpSimpleVisualization:public qmpPluginIntf,public qmpFuncBaseIntf +class qmpSimpleVisualization: public qmpPluginIntf, public qmpFuncBaseIntf { - private: - qmpPluginAPI* api; - qmpKeyboardWindow *p; - int uihs; - int uihsk; - public: - qmpSimpleVisualization(qmpPluginAPI* _api); - void show(); - void close(); - void init(); - void deinit(); - const char* pluginGetName(); - const char* pluginGetVersion(); +private: + qmpPluginAPI *api; + qmpKeyboardWindow *p; + int uihs; + int uihsk; +public: + qmpSimpleVisualization(qmpPluginAPI *_api); + void show(); + void close(); + void init(); + void deinit(); + const char *pluginGetName(); + const char *pluginGetVersion(); }; -extern "C"{ - EXPORTSYM qmpPluginIntf* qmpPluginGetInterface(qmpPluginAPI* api) - {return new qmpSimpleVisualization(api);} - EXPORTSYM const char* qmpPluginGetAPIRev() - {return QMP_PLUGIN_API_REV;} +extern "C" { + EXPORTSYM qmpPluginIntf *qmpPluginGetInterface(qmpPluginAPI *api) + { + return new qmpSimpleVisualization(api); + } + EXPORTSYM const char *qmpPluginGetAPIRev() + { + return QMP_PLUGIN_API_REV; + } } #endif // SIMPLEVISUALIZATION_HPP diff --git a/visualization/extrasmeltutils.cpp b/visualization/extrasmeltutils.cpp index 2d0a807..ec9f021 100644 --- a/visualization/extrasmeltutils.cpp +++ b/visualization/extrasmeltutils.cpp @@ -3,367 +3,494 @@ #include #include #include "extrasmeltutils.hpp" -SMELT* smEntity3DBuffer::sm=nullptr; -SMELT* smParticle::sm=nullptr; -SMELT* smParticleSystem::sm=nullptr; -smVertex makeVertex(float x,float y,float z,DWORD color,float tx,float ty) -{smVertex v;v.x=x;v.y=y;v.z=z;v.col=color;v.tx=tx;v.ty=ty;return v;} -void smEntity3D::addVertices(size_t n,...) -{ - va_list vl;va_start(vl,n); - for(int i=0;i0&&idx 0 && idx < vertices.size()) + return vertices[idx]; + return smVertex(); } WORD smEntity3D::index(size_t idx)const { - if(idx>0&&idx 0 && idx < indices.size()) + return indices[idx]; + return 0; } -void smEntity3D::setVertex(size_t idx,smVertex v) +void smEntity3D::setVertex(size_t idx, smVertex v) { - if(idx>0&&idx 0 && idx < vertices.size()) + vertices[idx] = v; } -void smEntity3D::setIndex(size_t idx,WORD i) +void smEntity3D::setIndex(size_t idx, WORD i) { - if(idx>0&&idx 0 && idx < indices.size()) + indices[idx] = i; } -smEntity3D smEntity3D::cube(smvec3d a,smvec3d b,DWORD color,int faces) -{ - smEntity3D ret; - ret.addVertices(8, - makeVertex(a.x,a.y,a.z,color,0,0),makeVertex(b.x,a.y,a.z,color,0,0), - makeVertex(b.x,b.y,a.z,color,0,0),makeVertex(a.x,b.y,a.z,color,0,0), - makeVertex(a.x,a.y,b.z,color,0,0),makeVertex(b.x,a.y,b.z,color,0,0), - makeVertex(b.x,b.y,b.z,color,0,0),makeVertex(a.x,b.y,b.z,color,0,0)); - if(faces&0x1)//a.z - ret.addIndices(6, 0,1,3, 1,2,3); - if(faces&0x2)//b.z - ret.addIndices(6, 4,5,7, 5,6,7); - if(faces&0x4)//a.x - ret.addIndices(6, 0,3,7, 0,4,7); - if(faces&0x8)//b.x - ret.addIndices(6, 1,2,6, 1,5,6); - if(faces&0x10)//a.y - ret.addIndices(6, 0,1,4, 1,4,5); - if(faces&0x20)//b.y - ret.addIndices(6, 2,3,7, 2,6,7); - return ret; +smEntity3D smEntity3D::cube(smvec3d a, smvec3d b, DWORD color, int faces) +{ + smEntity3D ret; + ret.addVertices(8, + makeVertex(a.x, a.y, a.z, color, 0, 0), makeVertex(b.x, a.y, a.z, color, 0, 0), + makeVertex(b.x, b.y, a.z, color, 0, 0), makeVertex(a.x, b.y, a.z, color, 0, 0), + makeVertex(a.x, a.y, b.z, color, 0, 0), makeVertex(b.x, a.y, b.z, color, 0, 0), + makeVertex(b.x, b.y, b.z, color, 0, 0), makeVertex(a.x, b.y, b.z, color, 0, 0)); + if (faces & 0x1) //a.z + ret.addIndices(6, 0, 1, 3, 1, 2, 3); + if (faces & 0x2) //b.z + ret.addIndices(6, 4, 5, 7, 5, 6, 7); + if (faces & 0x4) //a.x + ret.addIndices(6, 0, 3, 7, 0, 4, 7); + if (faces & 0x8) //b.x + ret.addIndices(6, 1, 2, 6, 1, 5, 6); + if (faces & 0x10) //a.y + ret.addIndices(6, 0, 1, 4, 1, 4, 5); + if (faces & 0x20) //b.y + ret.addIndices(6, 2, 3, 7, 2, 6, 7); + return ret; } smEntity3DBuffer::smEntity3DBuffer() { - sm=smGetInterface(SMELT_APILEVEL); - vertices.clear();indices.clear(); + sm = smGetInterface(SMELT_APILEVEL); + vertices.clear(); + indices.clear(); } -void smEntity3DBuffer::addTransformedEntity(smEntity3D *entity,smMatrix t,smvec3d p) +void smEntity3DBuffer::addTransformedEntity(smEntity3D *entity, smMatrix t, smvec3d p) { - if(entity->vertices.size()+vertices.size()>4000)drawBatch(); - for(unsigned i=0;iindices.size();++i) - indices.push_back(entity->indices[i]+vertices.size()); - for(unsigned i=0;ivertices.size();++i) - { - smvec3d tp=smvec3d(entity->vertices[i].x,entity->vertices[i].y,entity->vertices[i].z); - tp=t*tp;tp=tp+p;vertices.push_back(makeVertex(tp.x,tp.y,tp.z,entity->vertices[i].col,entity->vertices[i].tx,entity->vertices[i].ty)); - } + if (entity->vertices.size() + vertices.size() > 4000) + drawBatch(); + for (unsigned i = 0; i < entity->indices.size(); ++i) + indices.push_back(entity->indices[i] + vertices.size()); + for (unsigned i = 0; i < entity->vertices.size(); ++i) + { + smvec3d tp = smvec3d(entity->vertices[i].x, entity->vertices[i].y, entity->vertices[i].z); + tp = t * tp; + tp = tp + p; + vertices.push_back(makeVertex(tp.x, tp.y, tp.z, entity->vertices[i].col, entity->vertices[i].tx, entity->vertices[i].ty)); + } } void smEntity3DBuffer::drawBatch() { - if(!vertices.size())return; - sm->smDrawCustomIndexedVertices(&vertices[0],&indices[0],vertices.size(),indices.size(),BLEND_ALPHABLEND,0); - vertices.clear();indices.clear(); + if (!vertices.size()) + return; + sm->smDrawCustomIndexedVertices(&vertices[0], &indices[0], vertices.size(), indices.size(), BLEND_ALPHABLEND, 0); + vertices.clear(); + indices.clear(); } smParticle::smParticle() -{sm=smGetInterface(SMELT_APILEVEL);dead=false;clifespan=0;} -smParticle::~smParticle(){sm->smRelease();} +{ + sm = smGetInterface(SMELT_APILEVEL); + dead = false; + clifespan = 0; +} +smParticle::~smParticle() +{ + sm->smRelease(); +} void smParticle::render() -{sm->smRenderQuad(&q);} +{ + sm->smRenderQuad(&q); +} void smParticle::update() { - clifespan+=sm->smGetDelta();if(clifespan>lifespan){dead=true;return;} - vel=vel+accel;pos=pos+vel;rotv=rotv+rota;rot=rot+rotv; - size=clifespan/lifespan*(finalsize-initsize)+initsize; - smColorRGBA fc(finalcolor),ic(initcolor),cc; - cc.a=clifespan/lifespan*(fc.a-ic.a)+ic.a; - cc.r=clifespan/lifespan*(fc.r-ic.r)+ic.r; - cc.g=clifespan/lifespan*(fc.g-ic.g)+ic.g; - cc.b=clifespan/lifespan*(fc.b-ic.b)+ic.b; - color=cc.getHWColor(); - for(int i=0;i<4;++i)q.v[i].col=color; - smMatrix m;m.loadIdentity(); - if(lookat)m.lookat(pos,lookatpos,smvec3d(0,0,1));else - {m.rotate(rot.x,1,0,0);m.rotate(rot.y,0,1,0);m.rotate(rot.z,0,0,1);} - smvec3d v0=m*smvec3d(-size,-size,0),v1=m*smvec3d(size,-size,0); - smvec3d v2=m*smvec3d(size,size,0),v3=m*smvec3d(-size,size,0); - q.v[0].x=v0.x+pos.x;q.v[0].y=v0.y+pos.y;q.v[0].z=v0.z+pos.z; - q.v[1].x=v1.x+pos.x;q.v[1].y=v1.y+pos.y;q.v[1].z=v1.z+pos.z; - q.v[2].x=v2.x+pos.x;q.v[2].y=v2.y+pos.y;q.v[2].z=v2.z+pos.z; - q.v[3].x=v3.x+pos.x;q.v[3].y=v3.y+pos.y;q.v[3].z=v3.z+pos.z; + clifespan += sm->smGetDelta(); + if (clifespan > lifespan) + { + dead = true; + return; + } + vel = vel + accel; + pos = pos + vel; + rotv = rotv + rota; + rot = rot + rotv; + size = clifespan / lifespan * (finalsize - initsize) + initsize; + smColorRGBA fc(finalcolor), ic(initcolor), cc; + cc.a = clifespan / lifespan * (fc.a - ic.a) + ic.a; + cc.r = clifespan / lifespan * (fc.r - ic.r) + ic.r; + cc.g = clifespan / lifespan * (fc.g - ic.g) + ic.g; + cc.b = clifespan / lifespan * (fc.b - ic.b) + ic.b; + color = cc.getHWColor(); + for (int i = 0; i < 4; ++i) + q.v[i].col = color; + smMatrix m; + m.loadIdentity(); + if (lookat) + m.lookat(pos, lookatpos, smvec3d(0, 0, 1)); + else + { + m.rotate(rot.x, 1, 0, 0); + m.rotate(rot.y, 0, 1, 0); + m.rotate(rot.z, 0, 0, 1); + } + smvec3d v0 = m * smvec3d(-size, -size, 0), v1 = m * smvec3d(size, -size, 0); + smvec3d v2 = m * smvec3d(size, size, 0), v3 = m * smvec3d(-size, size, 0); + q.v[0].x = v0.x + pos.x; + q.v[0].y = v0.y + pos.y; + q.v[0].z = v0.z + pos.z; + q.v[1].x = v1.x + pos.x; + q.v[1].y = v1.y + pos.y; + q.v[1].z = v1.z + pos.z; + q.v[2].x = v2.x + pos.x; + q.v[2].y = v2.y + pos.y; + q.v[2].z = v2.z + pos.z; + q.v[3].x = v3.x + pos.x; + q.v[3].y = v3.y + pos.y; + q.v[3].z = v3.z + pos.z; } smParticleSystem::smParticleSystem() -{sm=smGetInterface(SMELT_APILEVEL);particles.clear();posGenerator=nullptr;active=false;} +{ + sm = smGetInterface(SMELT_APILEVEL); + particles.clear(); + posGenerator = nullptr; + active = false; +} smParticleSystem::~smParticleSystem() -{for(unsigned i=0;ismGetDelta(); - if(active&&cemdelay>nemdelay&&(int)particles.size()pos=pos+(posGenerator?posGenerator->genPos():smvec3d(0,0,0)); - p->vel=smvec3d( - re.nextDouble(psinfo.vel.x-psinfo.velvar.x,psinfo.vel.x+psinfo.velvar.x), - re.nextDouble(psinfo.vel.y-psinfo.velvar.y,psinfo.vel.y+psinfo.velvar.y), - re.nextDouble(psinfo.vel.z-psinfo.velvar.z,psinfo.vel.z+psinfo.velvar.z)); - p->accel=smvec3d( - re.nextDouble(psinfo.acc.x-psinfo.accvar.x,psinfo.acc.x+psinfo.accvar.x), - re.nextDouble(psinfo.acc.y-psinfo.accvar.y,psinfo.acc.y+psinfo.accvar.y), - re.nextDouble(psinfo.acc.z-psinfo.accvar.z,psinfo.acc.z+psinfo.accvar.z)); - p->rotv=smvec3d( - re.nextDouble(psinfo.rotv.x-psinfo.rotvvar.x,psinfo.rotv.x+psinfo.rotvvar.x), - re.nextDouble(psinfo.rotv.y-psinfo.rotvvar.y,psinfo.rotv.y+psinfo.rotvvar.y), - re.nextDouble(psinfo.rotv.z-psinfo.rotvvar.z,psinfo.rotv.z+psinfo.rotvvar.z)); - p->rota=smvec3d( - re.nextDouble(psinfo.rota.x-psinfo.rotavar.x,psinfo.rota.x+psinfo.rotavar.x), - re.nextDouble(psinfo.rota.y-psinfo.rotavar.y,psinfo.rota.y+psinfo.rotavar.y), - re.nextDouble(psinfo.rota.z-psinfo.rotavar.z,psinfo.rota.z+psinfo.rotavar.z)); - p->rot=smvec3d(0,0,0);if(lookat)p->lookat=true,p->lookatpos=lookatpos;else p->lookat=false; - p->lifespan=re.nextDouble(psinfo.lifespan-psinfo.lifespanvar,psinfo.lifespan+psinfo.lifespanvar); - p->initsize=re.nextDouble(psinfo.initsize-psinfo.initsizevar,psinfo.initsize+psinfo.initsizevar); - p->finalsize=re.nextDouble(psinfo.finalsize-psinfo.finalsizevar,psinfo.finalsize+psinfo.finalsizevar); - p->size=p->initsize; - p->initcolor=ARGB( - re.nextInt(GETA(psinfo.initcolor)-GETA(psinfo.initcolorvar),GETA(psinfo.initcolor)+GETA(psinfo.initcolorvar)), - re.nextInt(GETR(psinfo.initcolor)-GETR(psinfo.initcolorvar),GETR(psinfo.initcolor)+GETR(psinfo.initcolorvar)), - re.nextInt(GETG(psinfo.initcolor)-GETG(psinfo.initcolorvar),GETG(psinfo.initcolor)+GETG(psinfo.initcolorvar)), - re.nextInt(GETB(psinfo.initcolor)-GETB(psinfo.initcolorvar),GETB(psinfo.initcolor)+GETB(psinfo.initcolorvar))); - p->finalcolor=ARGB( - re.nextInt(GETA(psinfo.finalcolor)-GETA(psinfo.finalcolorvar),GETA(psinfo.finalcolor)+GETA(psinfo.finalcolorvar)), - re.nextInt(GETR(psinfo.finalcolor)-GETR(psinfo.finalcolorvar),GETR(psinfo.finalcolor)+GETR(psinfo.finalcolorvar)), - re.nextInt(GETG(psinfo.finalcolor)-GETG(psinfo.finalcolorvar),GETG(psinfo.finalcolor)+GETG(psinfo.finalcolorvar)), - re.nextInt(GETB(psinfo.finalcolor)-GETB(psinfo.finalcolorvar),GETB(psinfo.finalcolor)+GETB(psinfo.finalcolorvar))); - p->color=p->initcolor;p->q.tex=psinfo.texture;p->q.blend=psinfo.blend; - p->q.v[0].tx=p->q.v[3].tx=0;p->q.v[0].ty=p->q.v[1].ty=0; - p->q.v[1].tx=p->q.v[2].tx=1;p->q.v[2].ty=p->q.v[3].ty=1; - particles.push_back(p); - } - cemdelay=0; - nemdelay=re.nextDouble(psinfo.emissiondelay-psinfo.edvar,psinfo.emissiondelay+psinfo.edvar); - } - for(unsigned i=0,j;idead;++i) - { - particles[i]->update(); - if(particles[i]->dead) - { - for(j=particles.size()-1;j>i&&particles[j]->dead;--j); - std::swap(particles[i],particles[j]); - } - } - while(!particles.empty()&&particles.back()->dead) - {delete particles.back();particles.back()=nullptr;particles.pop_back();} + cemdelay += sm->smGetDelta(); + if (active && cemdelay > nemdelay && (int)particles.size() < psinfo.maxcount) + { + int ec = re.nextInt(psinfo.emissioncount - psinfo.ecvar, psinfo.emissioncount + psinfo.ecvar); + for (int i = 0; i < ec; ++i) + { + smParticle *p = new smParticle(); + p->pos = pos + (posGenerator ? posGenerator->genPos() : smvec3d(0, 0, 0)); + p->vel = smvec3d( + re.nextDouble(psinfo.vel.x - psinfo.velvar.x, psinfo.vel.x + psinfo.velvar.x), + re.nextDouble(psinfo.vel.y - psinfo.velvar.y, psinfo.vel.y + psinfo.velvar.y), + re.nextDouble(psinfo.vel.z - psinfo.velvar.z, psinfo.vel.z + psinfo.velvar.z)); + p->accel = smvec3d( + re.nextDouble(psinfo.acc.x - psinfo.accvar.x, psinfo.acc.x + psinfo.accvar.x), + re.nextDouble(psinfo.acc.y - psinfo.accvar.y, psinfo.acc.y + psinfo.accvar.y), + re.nextDouble(psinfo.acc.z - psinfo.accvar.z, psinfo.acc.z + psinfo.accvar.z)); + p->rotv = smvec3d( + re.nextDouble(psinfo.rotv.x - psinfo.rotvvar.x, psinfo.rotv.x + psinfo.rotvvar.x), + re.nextDouble(psinfo.rotv.y - psinfo.rotvvar.y, psinfo.rotv.y + psinfo.rotvvar.y), + re.nextDouble(psinfo.rotv.z - psinfo.rotvvar.z, psinfo.rotv.z + psinfo.rotvvar.z)); + p->rota = smvec3d( + re.nextDouble(psinfo.rota.x - psinfo.rotavar.x, psinfo.rota.x + psinfo.rotavar.x), + re.nextDouble(psinfo.rota.y - psinfo.rotavar.y, psinfo.rota.y + psinfo.rotavar.y), + re.nextDouble(psinfo.rota.z - psinfo.rotavar.z, psinfo.rota.z + psinfo.rotavar.z)); + p->rot = smvec3d(0, 0, 0); + if (lookat) + p->lookat = true, p->lookatpos = lookatpos; + else p->lookat = false; + p->lifespan = re.nextDouble(psinfo.lifespan - psinfo.lifespanvar, psinfo.lifespan + psinfo.lifespanvar); + p->initsize = re.nextDouble(psinfo.initsize - psinfo.initsizevar, psinfo.initsize + psinfo.initsizevar); + p->finalsize = re.nextDouble(psinfo.finalsize - psinfo.finalsizevar, psinfo.finalsize + psinfo.finalsizevar); + p->size = p->initsize; + p->initcolor = ARGB( + re.nextInt(GETA(psinfo.initcolor) - GETA(psinfo.initcolorvar), GETA(psinfo.initcolor) + GETA(psinfo.initcolorvar)), + re.nextInt(GETR(psinfo.initcolor) - GETR(psinfo.initcolorvar), GETR(psinfo.initcolor) + GETR(psinfo.initcolorvar)), + re.nextInt(GETG(psinfo.initcolor) - GETG(psinfo.initcolorvar), GETG(psinfo.initcolor) + GETG(psinfo.initcolorvar)), + re.nextInt(GETB(psinfo.initcolor) - GETB(psinfo.initcolorvar), GETB(psinfo.initcolor) + GETB(psinfo.initcolorvar))); + p->finalcolor = ARGB( + re.nextInt(GETA(psinfo.finalcolor) - GETA(psinfo.finalcolorvar), GETA(psinfo.finalcolor) + GETA(psinfo.finalcolorvar)), + re.nextInt(GETR(psinfo.finalcolor) - GETR(psinfo.finalcolorvar), GETR(psinfo.finalcolor) + GETR(psinfo.finalcolorvar)), + re.nextInt(GETG(psinfo.finalcolor) - GETG(psinfo.finalcolorvar), GETG(psinfo.finalcolor) + GETG(psinfo.finalcolorvar)), + re.nextInt(GETB(psinfo.finalcolor) - GETB(psinfo.finalcolorvar), GETB(psinfo.finalcolor) + GETB(psinfo.finalcolorvar))); + p->color = p->initcolor; + p->q.tex = psinfo.texture; + p->q.blend = psinfo.blend; + p->q.v[0].tx = p->q.v[3].tx = 0; + p->q.v[0].ty = p->q.v[1].ty = 0; + p->q.v[1].tx = p->q.v[2].tx = 1; + p->q.v[2].ty = p->q.v[3].ty = 1; + particles.push_back(p); + } + cemdelay = 0; + nemdelay = re.nextDouble(psinfo.emissiondelay - psinfo.edvar, psinfo.emissiondelay + psinfo.edvar); + } + for (unsigned i = 0, j; i < particles.size() && !particles[i]->dead; ++i) + { + particles[i]->update(); + if (particles[i]->dead) + { + for (j = particles.size() - 1; j > i && particles[j]->dead; --j); + std::swap(particles[i], particles[j]); + } + } + while (!particles.empty() && particles.back()->dead) + { + delete particles.back(); + particles.back() = nullptr; + particles.pop_back(); + } } void smParticleSystem::renderPS() -{for(unsigned i=0;irender();} +{ + for (unsigned i = 0; i < particles.size(); ++i) + particles[i]->render(); +} smColor::smColor() -{r=g=b=h=s=v=a=0;} +{ + r = g = b = h = s = v = a = 0; +} void smColor::update_rgb() { - auto f=[this](float n){ - float k=fmodf(n+6.0f*this->h,6.0f); - return this->v-this->v*this->s*max(0.0f,min(1.0f,min(k,4.0f-k))); - }; - r=f(5); - g=f(3); - b=f(1); + auto f = [this](float n) + { + float k = fmodf(n + 6.0f * this->h, 6.0f); + return this->v - this->v * this->s * max(0.0f, min(1.0f, min(k, 4.0f - k))); + }; + r = f(5); + g = f(3); + b = f(1); } void smColor::update_hsv() { - v=max(r,max(g,b)); - float vm=min(r,min(g,b)); - float chroma=v-vm; - if(v-vmEPSF) - { - r=red; - update_hsv(); - } + if (fabsf(r - red) > EPSF) + { + r = red; + update_hsv(); + } } void smColor::setGreen(float green) { - if(fabsf(g-green)>EPSF) - { - g=green; - update_hsv(); - } + if (fabsf(g - green) > EPSF) + { + g = green; + update_hsv(); + } } void smColor::setBlue(float blue) { - if(fabsf(b-blue)>EPSF) - { - b=blue; - update_hsv(); - } + if (fabsf(b - blue) > EPSF) + { + b = blue; + update_hsv(); + } } void smColor::setHue(float hue) { - if(fabsf(h-hue)>EPSF) - { - h=hue; - update_rgb(); - } + if (fabsf(h - hue) > EPSF) + { + h = hue; + update_rgb(); + } } void smColor::setSaturation(float saturation) { - if(fabsf(s-saturation)>EPSF) - { - s=saturation; - update_rgb(); - } + if (fabsf(s - saturation) > EPSF) + { + s = saturation; + update_rgb(); + } } void smColor::setHSLSaturation(float saturation) { - float ss=hslSaturation(); - float l=lightness(); - if(fabsf(ss-saturation)>EPSF) - { - ss=saturation; - v=l+ss*min(l,1-l); - if(v EPSF) + { + ss = saturation; + v = l + ss * min(l, 1 - l); + if (v < EPSF) + s = 0; + else s = 2 - 2 * l / v; + update_rgb(); + } } void smColor::setValue(float value) { - if(fabsf(v-value)>EPSF) - { - v=value; - update_rgb(); - } + if (fabsf(v - value) > EPSF) + { + v = value; + update_rgb(); + } } void smColor::setLightness(float lightness) { - float ss=hslSaturation(); - float l=this->lightness(); - if(fabsf(l-lightness)>EPSF) - { - l=lightness; - v=l+ss*min(l,1-l); - if(vlightness(); + if (fabsf(l - lightness) > EPSF) + { + l = lightness; + v = l + ss * min(l, 1 - l); + if (v < EPSF) + s = 0; + else s = 2 - 2 * l / v; + update_rgb(); + } } smColor smColor::lighter(int factor) { - smColor ret(*this); - ret.setValue(v*(factor/100.0f)); - ret.clamp(true); - return ret; + smColor ret(*this); + ret.setValue(v * (factor / 100.0f)); + ret.clamp(true); + return ret; } smColor smColor::darker(int factor) { - smColor ret(*this); - ret.setValue(factor?(v/(factor/100.0f)):1.); - ret.clamp(true); - return ret; + smColor ret(*this); + ret.setValue(factor ? (v / (factor / 100.0f)) : 1.); + ret.clamp(true); + return ret; } uint32_t smColor::toHWColor() { - return RGBA(r*255,g*255,b*255,a*255); + return RGBA(r * 255, g * 255, b * 255, a * 255); } smColor smColor::fromHWColor(uint32_t color) { - smColor ret; - ret.r=GETR(color)/255.0f; - ret.g=GETG(color)/255.0f; - ret.b=GETB(color)/255.0f; - ret.a=GETA(color)/255.0f; - ret.update_hsv(); - return ret; + smColor ret; + ret.r = GETR(color) / 255.0f; + ret.g = GETG(color) / 255.0f; + ret.b = GETB(color) / 255.0f; + ret.a = GETA(color) / 255.0f; + ret.update_hsv(); + return ret; } diff --git a/visualization/extrasmeltutils.hpp b/visualization/extrasmeltutils.hpp index 3cea3fc..ca36415 100644 --- a/visualization/extrasmeltutils.hpp +++ b/visualization/extrasmeltutils.hpp @@ -13,134 +13,152 @@ #define EPSF 1e-6f class smEntity3D { - friend class smEntity3DBuffer; - private: - std::vector vertices; - std::vector indices; - public: - smEntity3D(){vertices.clear();indices.clear();} - void addVertices(size_t n,...); - void addIndices(size_t n,...); - smVertex vertex(size_t idx)const; - WORD index(size_t idx)const; - void setVertex(size_t idx,smVertex v); - void setIndex(size_t idx,WORD i); - static smEntity3D cube(smvec3d tl,smvec3d br,DWORD color,int faces=63); + friend class smEntity3DBuffer; +private: + std::vector vertices; + std::vector indices; +public: + smEntity3D() + { + vertices.clear(); + indices.clear(); + } + void addVertices(size_t n, ...); + void addIndices(size_t n, ...); + smVertex vertex(size_t idx)const; + WORD index(size_t idx)const; + void setVertex(size_t idx, smVertex v); + void setIndex(size_t idx, WORD i); + static smEntity3D cube(smvec3d tl, smvec3d br, DWORD color, int faces = 63); }; class smEntity3DBuffer { - private: - std::vector vertices; - std::vector indices; - static SMELT* sm; - public: - smEntity3DBuffer(); - ~smEntity3DBuffer(){sm->smRelease();} - void addTransformedEntity(smEntity3D *entity,smMatrix t,smvec3d p); - void drawBatch(); +private: + std::vector vertices; + std::vector indices; + static SMELT *sm; +public: + smEntity3DBuffer(); + ~smEntity3DBuffer() + { + sm->smRelease(); + } + void addTransformedEntity(smEntity3D *entity, smMatrix t, smvec3d p); + void drawBatch(); }; class smColor { - private: - float r,g,b,h,s,v,a; - void update_rgb(); - void update_hsv(); - public: - smColor(); - void clamp(bool hsv); - float alpha()const; - float red()const; - float green()const; - float blue()const; - float hue()const; - float saturation()const; - float hslSaturation()const; - float value()const; - float lightness()const; - void setAlpha(float alpha); - void setRed(float red); - void setGreen(float green); - void setBlue(float blue); - void setHue(float hue); - void setSaturation(float saturation); - void setHSLSaturation(float saturation); - void setValue(float value); - void setLightness(float lightness); - smColor lighter(int factor); - smColor darker(int factor); - uint32_t toHWColor(); - static smColor fromHWColor(uint32_t color); +private: + float r, g, b, h, s, v, a; + void update_rgb(); + void update_hsv(); +public: + smColor(); + void clamp(bool hsv); + float alpha()const; + float red()const; + float green()const; + float blue()const; + float hue()const; + float saturation()const; + float hslSaturation()const; + float value()const; + float lightness()const; + void setAlpha(float alpha); + void setRed(float red); + void setGreen(float green); + void setBlue(float blue); + void setHue(float hue); + void setSaturation(float saturation); + void setHSLSaturation(float saturation); + void setValue(float value); + void setLightness(float lightness); + smColor lighter(int factor); + smColor darker(int factor); + uint32_t toHWColor(); + static smColor fromHWColor(uint32_t color); }; class smPSEmissionPositionGenerator { - public: - virtual smvec3d genPos(){return smvec3d(0,0,0);} +public: + virtual smvec3d genPos() + { + return smvec3d(0, 0, 0); + } }; -class smXLinePSGenerator:public smPSEmissionPositionGenerator +class smXLinePSGenerator: public smPSEmissionPositionGenerator { - private: - smRandomEngine re; - double var; - public: - smXLinePSGenerator(double _var){re.setSeed(time(nullptr));var=_var;} - smvec3d genPos(){return smvec3d(re.nextDouble(-var,var),0,0);} +private: + smRandomEngine re; + double var; +public: + smXLinePSGenerator(double _var) + { + re.setSeed(time(nullptr)); + var = _var; + } + smvec3d genPos() + { + return smvec3d(re.nextDouble(-var, var), 0, 0); + } }; class smParticleSystemInfo { - public: - smvec3d vel,velvar,acc,accvar; - smvec3d rotv,rotvvar,rota,rotavar; - double lifespan,lifespanvar; - int maxcount,emissioncount,ecvar; - double emissiondelay,edvar; - double initsize,initsizevar; - double finalsize,finalsizevar; - DWORD initcolor,initcolorvar; - DWORD finalcolor,finalcolorvar; - SMTEX texture;int blend; +public: + smvec3d vel, velvar, acc, accvar; + smvec3d rotv, rotvvar, rota, rotavar; + double lifespan, lifespanvar; + int maxcount, emissioncount, ecvar; + double emissiondelay, edvar; + double initsize, initsizevar; + double finalsize, finalsizevar; + DWORD initcolor, initcolorvar; + DWORD finalcolor, finalcolorvar; + SMTEX texture; + int blend; }; class smParticle { - friend class smParticleSystem; - private: - static SMELT* sm; - smvec3d pos,rot,lookatpos; - smvec3d vel,accel,rotv,rota; - double lifespan,clifespan; - double initsize,finalsize,size; - DWORD color,initcolor,finalcolor; - smQuad q; - bool dead,lookat; - public: - smParticle(); - ~smParticle(); - void render(); - void update(); + friend class smParticleSystem; +private: + static SMELT *sm; + smvec3d pos, rot, lookatpos; + smvec3d vel, accel, rotv, rota; + double lifespan, clifespan; + double initsize, finalsize, size; + DWORD color, initcolor, finalcolor; + smQuad q; + bool dead, lookat; +public: + smParticle(); + ~smParticle(); + void render(); + void update(); }; class smParticleSystem { - private: - static SMELT* sm; - std::vector particles; - smParticleSystemInfo psinfo; - smvec3d pos,lookatpos; - smRandomEngine re; - smPSEmissionPositionGenerator* posGenerator; - bool active,lookat; - double cemdelay,nemdelay; - public: - smParticleSystem(); - ~smParticleSystem(); - void setParticleSystemInfo(smParticleSystemInfo _psinfo); - void setPos(smvec3d _pos); - void setPSEmissionPosGen(smPSEmissionPositionGenerator* _gen); - void setPSLookAt(smvec3d at); - void unsetPSLookAt(); - void startPS(); - void stopPS(); - void updatePS(); - void renderPS(); +private: + static SMELT *sm; + std::vector particles; + smParticleSystemInfo psinfo; + smvec3d pos, lookatpos; + smRandomEngine re; + smPSEmissionPositionGenerator *posGenerator; + bool active, lookat; + double cemdelay, nemdelay; +public: + smParticleSystem(); + ~smParticleSystem(); + void setParticleSystemInfo(smParticleSystemInfo _psinfo); + void setPos(smvec3d _pos); + void setPSEmissionPosGen(smPSEmissionPositionGenerator *_gen); + void setPSLookAt(smvec3d at); + void unsetPSLookAt(); + void startPS(); + void stopPS(); + void updatePS(); + void renderPS(); }; -extern smVertex makeVertex(float x,float y,float z,DWORD color,float tx,float ty); +extern smVertex makeVertex(float x, float y, float z, DWORD color, float tx, float ty); #endif // EXTRASMELTUTILS_H diff --git a/visualization/qmpvirtualpiano3d.cpp b/visualization/qmpvirtualpiano3d.cpp index 0fbf75f..4ee7460 100644 --- a/visualization/qmpvirtualpiano3d.cpp +++ b/visualization/qmpvirtualpiano3d.cpp @@ -1,219 +1,249 @@ #include #include "qmpvirtualpiano3d.hpp" #define configureVertex(v,sub,_x,_y,_z) v[sub].x=_x,v[sub].y=_y,v[sub].z=_z; -const double gap[]={WK_TALWIDTH/2*0.92,WK_TALWIDTH/2*1.23,WK_TALWIDTH/2*1.2, - WK_TALWIDTH/2*0.95,WK_TALWIDTH*1.1,WK_TALWIDTH/2*0.95, - WK_TALWIDTH/2*1.2,WK_TALWIDTH/2*1.15,WK_TALWIDTH/2*1, - WK_TALWIDTH/2*1.3,WK_TALWIDTH/2*0.85,WK_TALWIDTH*1.1}; +const double gap[] = {WK_TALWIDTH / 2 * 0.92, WK_TALWIDTH / 2 * 1.23, WK_TALWIDTH / 2 * 1.2, + WK_TALWIDTH / 2 * 0.95, WK_TALWIDTH * 1.1, WK_TALWIDTH / 2 * 0.95, + WK_TALWIDTH / 2 * 1.2, WK_TALWIDTH / 2 * 1.15, WK_TALWIDTH / 2 * 1, + WK_TALWIDTH / 2 * 1.3, WK_TALWIDTH / 2 * 0.85, WK_TALWIDTH * 1.1 + }; qmpVirtualPiano3D::qmpVirtualPiano3D() { - ebuf=new smEntity3DBuffer();buildKeys();memset(traveld,0,sizeof(traveld)); + ebuf = new smEntity3DBuffer(); + buildKeys(); + memset(traveld, 0, sizeof(traveld)); } qmpVirtualPiano3D::~qmpVirtualPiano3D() { - delete wkcf;delete wkeb;delete wkd;delete wkg;delete wka;delete bk; - wkcf=wkeb=wkd=wkg=wka=bk=nullptr;delete ebuf;ebuf=nullptr; + delete wkcf; + delete wkeb; + delete wkd; + delete wkg; + delete wka; + delete bk; + wkcf = wkeb = wkd = wkg = wka = bk = nullptr; + delete ebuf; + ebuf = nullptr; } void qmpVirtualPiano3D::render(smvec3d p) { - p.x-=WK_TALWIDTH*37*1.075; - for(int i=0;i<128;++i) - { - smMatrix m;m.loadIdentity();m.rotate(-0.2*traveld[i],1,0,0); - switch(i%12) - { - case 0:case 5: - if(wkcf)ebuf->addTransformedEntity(wkcf,m,p); - break; - case 2: - if(wkd)ebuf->addTransformedEntity(wkd,m,p); - break; - case 4:case 11: - if(wkeb)ebuf->addTransformedEntity(wkeb,m,p); - break; - case 7: - if(wkg)ebuf->addTransformedEntity(wkg,m,p); - break; - case 9: - if(wka)ebuf->addTransformedEntity(wka,m,p); - break; - case 1:case 3:case 6:case 8:case 10: - if(bk)ebuf->addTransformedEntity(bk,m,p); - break; - } - p.x+=gap[i%12]; - } - ebuf->drawBatch(); + p.x -= WK_TALWIDTH * 37 * 1.075; + for (int i = 0; i < 128; ++i) + { + smMatrix m; + m.loadIdentity(); + m.rotate(-0.2 * traveld[i], 1, 0, 0); + switch (i % 12) + { + case 0: + case 5: + if (wkcf) + ebuf->addTransformedEntity(wkcf, m, p); + break; + case 2: + if (wkd) + ebuf->addTransformedEntity(wkd, m, p); + break; + case 4: + case 11: + if (wkeb) + ebuf->addTransformedEntity(wkeb, m, p); + break; + case 7: + if (wkg) + ebuf->addTransformedEntity(wkg, m, p); + break; + case 9: + if (wka) + ebuf->addTransformedEntity(wka, m, p); + break; + case 1: + case 3: + case 6: + case 8: + case 10: + if (bk) + ebuf->addTransformedEntity(bk, m, p); + break; + } + p.x += gap[i % 12]; + } + ebuf->drawBatch(); +} +void qmpVirtualPiano3D::setKeyTravelDist(int k, double td) +{ + traveld[k] = td; } -void qmpVirtualPiano3D::setKeyTravelDist(int k,double td) -{traveld[k]=td;} void qmpVirtualPiano3D::buildKeys() { - wkcf=new smEntity3D();wkeb=new smEntity3D();wkd=new smEntity3D(); - wkg=new smEntity3D();wka=new smEntity3D();bk=new smEntity3D(); - wkcf->addVertices(19, - makeVertex(-WK_TALWIDTH/2,0,WK_HEIGHT,0xFFFFFFFF,0,0), - makeVertex(-WK_TALWIDTH/2+WK_PREWIDTH,0,WK_HEIGHT,0xFFFFFFFF,0,0), - makeVertex(-WK_TALWIDTH/2+WK_PREWIDTH,WK_PRELEN,WK_HEIGHT,0xFFFFFFFF,0,0), - makeVertex(-WK_TALWIDTH/2,WK_PRELEN,WK_HEIGHT,0xFFFFFFFF,0,0), - makeVertex( WK_TALWIDTH/2,WK_PRELEN,WK_HEIGHT,0xFFFFFFFF,0,0), - makeVertex( WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN+WK_WING,WK_HEIGHT,0xFFFFFFFF,0,0), - makeVertex(-WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN+WK_WING,WK_HEIGHT,0xFFFFFFFF,0,0),//// - makeVertex(-WK_TALWIDTH/2,0,WK_HEIGHT,0xFFCCCCCC,0,0), - makeVertex(-WK_TALWIDTH/2+WK_PREWIDTH,0,WK_HEIGHT,0xFFCCCCCC,0,0), - makeVertex(-WK_TALWIDTH/2+WK_PREWIDTH,WK_PRELEN,WK_HEIGHT,0xFFCCCCCC,0,0), - makeVertex( WK_TALWIDTH/2,WK_PRELEN,WK_HEIGHT,0xFFCCCCCC,0,0), - makeVertex( WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,WK_HEIGHT,0xFFCCCCCC,0,0), - makeVertex(-WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,WK_HEIGHT,0xFFCCCCCC,0,0), - makeVertex(-WK_TALWIDTH/2,0,0,0xFFCCCCCC,0,0), - makeVertex(-WK_TALWIDTH/2+WK_PREWIDTH,0,0,0xFFCCCCCC,0,0), - makeVertex(-WK_TALWIDTH/2+WK_PREWIDTH,WK_PRELEN,0,0xFFCCCCCC,0,0), - makeVertex( WK_TALWIDTH/2,WK_PRELEN,0,0xFFCCCCCC,0,0), - makeVertex( WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,0,0xFFCCCCCC,0,0), - makeVertex(-WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,0,0xFFCCCCCC,0,0)); - wkcf->addIndices(48, - 0,1,3, 1,2,3, 3,4,6, 4,5,6, - 7,8,13, 8,13,14, 8,14,15, 8,9,15, - 9,10,15, 10,15,16, 10,11,17, 10,16,17, - 11,12,18, 11,17,18, 18,12,13, 12,13,7); + wkcf = new smEntity3D(); + wkeb = new smEntity3D(); + wkd = new smEntity3D(); + wkg = new smEntity3D(); + wka = new smEntity3D(); + bk = new smEntity3D(); + wkcf->addVertices(19, + makeVertex(-WK_TALWIDTH / 2, 0, WK_HEIGHT, 0xFFFFFFFF, 0, 0), + makeVertex(-WK_TALWIDTH / 2 + WK_PREWIDTH, 0, WK_HEIGHT, 0xFFFFFFFF, 0, 0), + makeVertex(-WK_TALWIDTH / 2 + WK_PREWIDTH, WK_PRELEN, WK_HEIGHT, 0xFFFFFFFF, 0, 0), + makeVertex(-WK_TALWIDTH / 2, WK_PRELEN, WK_HEIGHT, 0xFFFFFFFF, 0, 0), + makeVertex(WK_TALWIDTH / 2, WK_PRELEN, WK_HEIGHT, 0xFFFFFFFF, 0, 0), + makeVertex(WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN + WK_WING, WK_HEIGHT, 0xFFFFFFFF, 0, 0), + makeVertex(-WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN + WK_WING, WK_HEIGHT, 0xFFFFFFFF, 0, 0), //// + makeVertex(-WK_TALWIDTH / 2, 0, WK_HEIGHT, 0xFFCCCCCC, 0, 0), + makeVertex(-WK_TALWIDTH / 2 + WK_PREWIDTH, 0, WK_HEIGHT, 0xFFCCCCCC, 0, 0), + makeVertex(-WK_TALWIDTH / 2 + WK_PREWIDTH, WK_PRELEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0), + makeVertex(WK_TALWIDTH / 2, WK_PRELEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0), + makeVertex(WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0), + makeVertex(-WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0), + makeVertex(-WK_TALWIDTH / 2, 0, 0, 0xFFCCCCCC, 0, 0), + makeVertex(-WK_TALWIDTH / 2 + WK_PREWIDTH, 0, 0, 0xFFCCCCCC, 0, 0), + makeVertex(-WK_TALWIDTH / 2 + WK_PREWIDTH, WK_PRELEN, 0, 0xFFCCCCCC, 0, 0), + makeVertex(WK_TALWIDTH / 2, WK_PRELEN, 0, 0xFFCCCCCC, 0, 0), + makeVertex(WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, 0, 0xFFCCCCCC, 0, 0), + makeVertex(-WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, 0, 0xFFCCCCCC, 0, 0)); + wkcf->addIndices(48, + 0, 1, 3, 1, 2, 3, 3, 4, 6, 4, 5, 6, + 7, 8, 13, 8, 13, 14, 8, 14, 15, 8, 9, 15, + 9, 10, 15, 10, 15, 16, 10, 11, 17, 10, 16, 17, + 11, 12, 18, 11, 17, 18, 18, 12, 13, 12, 13, 7); - wkeb->addVertices(19, - makeVertex( WK_TALWIDTH/2,0,WK_HEIGHT,0xFFFFFFFF,0,0), - makeVertex( WK_TALWIDTH/2-WK_PREWIDTH,0,WK_HEIGHT,0xFFFFFFFF,0,0), - makeVertex( WK_TALWIDTH/2-WK_PREWIDTH,WK_PRELEN,WK_HEIGHT,0xFFFFFFFF,0,0), - makeVertex( WK_TALWIDTH/2,WK_PRELEN,WK_HEIGHT,0xFFFFFFFF,0,0), - makeVertex(-WK_TALWIDTH/2,WK_PRELEN,WK_HEIGHT,0xFFFFFFFF,0,0), - makeVertex(-WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN+WK_WING,WK_HEIGHT,0xFFFFFFFF,0,0), - makeVertex( WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN+WK_WING,WK_HEIGHT,0xFFFFFFFF,0,0),//// - makeVertex( WK_TALWIDTH/2,0,WK_HEIGHT,0xFFCCCCCC,0,0), - makeVertex( WK_TALWIDTH/2-WK_PREWIDTH,0,WK_HEIGHT,0xFFCCCCCC,0,0), - makeVertex( WK_TALWIDTH/2-WK_PREWIDTH,WK_PRELEN,WK_HEIGHT,0xFFCCCCCC,0,0), - makeVertex(-WK_TALWIDTH/2,WK_PRELEN,WK_HEIGHT,0xFFCCCCCC,0,0), - makeVertex(-WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,WK_HEIGHT,0xFFCCCCCC,0,0), - makeVertex( WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,WK_HEIGHT,0xFFCCCCCC,0,0), - makeVertex( WK_TALWIDTH/2,0,0,0xFFCCCCCC,0,0), - makeVertex( WK_TALWIDTH/2-WK_PREWIDTH,0,0,0xFFCCCCCC,0,0), - makeVertex( WK_TALWIDTH/2-WK_PREWIDTH,WK_PRELEN,0,0xFFCCCCCC,0,0), - makeVertex(-WK_TALWIDTH/2,WK_PRELEN,0,0xFFCCCCCC,0,0), - makeVertex(-WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,0,0xFFCCCCCC,0,0), - makeVertex( WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,0,0xFFCCCCCC,0,0)); - wkeb->addIndices(48, - 0,1,3, 1,2,3, 3,4,6, 4,5,6, - 7,8,13, 8,13,14, 8,14,15, 8,9,15, - 9,10,15, 10,15,16, 10,11,17, 10,16,17, - 11,12,18, 11,17,18, 18,12,13, 12,13,7); + wkeb->addVertices(19, + makeVertex(WK_TALWIDTH / 2, 0, WK_HEIGHT, 0xFFFFFFFF, 0, 0), + makeVertex(WK_TALWIDTH / 2 - WK_PREWIDTH, 0, WK_HEIGHT, 0xFFFFFFFF, 0, 0), + makeVertex(WK_TALWIDTH / 2 - WK_PREWIDTH, WK_PRELEN, WK_HEIGHT, 0xFFFFFFFF, 0, 0), + makeVertex(WK_TALWIDTH / 2, WK_PRELEN, WK_HEIGHT, 0xFFFFFFFF, 0, 0), + makeVertex(-WK_TALWIDTH / 2, WK_PRELEN, WK_HEIGHT, 0xFFFFFFFF, 0, 0), + makeVertex(-WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN + WK_WING, WK_HEIGHT, 0xFFFFFFFF, 0, 0), + makeVertex(WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN + WK_WING, WK_HEIGHT, 0xFFFFFFFF, 0, 0), //// + makeVertex(WK_TALWIDTH / 2, 0, WK_HEIGHT, 0xFFCCCCCC, 0, 0), + makeVertex(WK_TALWIDTH / 2 - WK_PREWIDTH, 0, WK_HEIGHT, 0xFFCCCCCC, 0, 0), + makeVertex(WK_TALWIDTH / 2 - WK_PREWIDTH, WK_PRELEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0), + makeVertex(-WK_TALWIDTH / 2, WK_PRELEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0), + makeVertex(-WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0), + makeVertex(WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0), + makeVertex(WK_TALWIDTH / 2, 0, 0, 0xFFCCCCCC, 0, 0), + makeVertex(WK_TALWIDTH / 2 - WK_PREWIDTH, 0, 0, 0xFFCCCCCC, 0, 0), + makeVertex(WK_TALWIDTH / 2 - WK_PREWIDTH, WK_PRELEN, 0, 0xFFCCCCCC, 0, 0), + makeVertex(-WK_TALWIDTH / 2, WK_PRELEN, 0, 0xFFCCCCCC, 0, 0), + makeVertex(-WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, 0, 0xFFCCCCCC, 0, 0), + makeVertex(WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, 0, 0xFFCCCCCC, 0, 0)); + wkeb->addIndices(48, + 0, 1, 3, 1, 2, 3, 3, 4, 6, 4, 5, 6, + 7, 8, 13, 8, 13, 14, 8, 14, 15, 8, 9, 15, + 9, 10, 15, 10, 15, 16, 10, 11, 17, 10, 16, 17, + 11, 12, 18, 11, 17, 18, 18, 12, 13, 12, 13, 7); - wkd->addVertices(24, - makeVertex(-WK_TALWIDTH/2+(WK_TALWIDTH-WK_PREWIDTH)/2,0,WK_HEIGHT,0xFFFFFFFF,0,0), - makeVertex( WK_TALWIDTH/2-(WK_TALWIDTH-WK_PREWIDTH)/2,0,WK_HEIGHT,0xFFFFFFFF,0,0), - makeVertex( WK_TALWIDTH/2-(WK_TALWIDTH-WK_PREWIDTH)/2,WK_PRELEN,WK_HEIGHT,0xFFFFFFFF,0,0), - makeVertex(-WK_TALWIDTH/2+(WK_TALWIDTH-WK_PREWIDTH)/2,WK_PRELEN,WK_HEIGHT,0xFFFFFFFF,0,0), - makeVertex( WK_TALWIDTH/2,WK_PRELEN,WK_HEIGHT,0xFFFFFFFF,0,0), - makeVertex( WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN+WK_WING,WK_HEIGHT,0xFFFFFFFF,0,0), - makeVertex(-WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN+WK_WING,WK_HEIGHT,0xFFFFFFFF,0,0), - makeVertex(-WK_TALWIDTH/2,WK_PRELEN,WK_HEIGHT,0xFFFFFFFF,0,0),//// - makeVertex(-WK_TALWIDTH/2+(WK_TALWIDTH-WK_PREWIDTH)/2,0,WK_HEIGHT,0xFFCCCCCC,0,0), - makeVertex( WK_TALWIDTH/2-(WK_TALWIDTH-WK_PREWIDTH)/2,0,WK_HEIGHT,0xFFCCCCCC,0,0), - makeVertex( WK_TALWIDTH/2-(WK_TALWIDTH-WK_PREWIDTH)/2,WK_PRELEN,WK_HEIGHT,0xFFCCCCCC,0,0), - makeVertex(-WK_TALWIDTH/2+(WK_TALWIDTH-WK_PREWIDTH)/2,WK_PRELEN,WK_HEIGHT,0xFFCCCCCC,0,0), - makeVertex( WK_TALWIDTH/2,WK_PRELEN,WK_HEIGHT,0xFFCCCCCC,0,0), - makeVertex( WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,WK_HEIGHT,0xFFCCCCCC,0,0), - makeVertex(-WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,WK_HEIGHT,0xFFCCCCCC,0,0), - makeVertex(-WK_TALWIDTH/2,WK_PRELEN,WK_HEIGHT,0xFFCCCCCC,0,0),//// - makeVertex(-WK_TALWIDTH/2+(WK_TALWIDTH-WK_PREWIDTH)/2,0,0,0xFFCCCCCC,0,0), - makeVertex( WK_TALWIDTH/2-(WK_TALWIDTH-WK_PREWIDTH)/2,0,0,0xFFCCCCCC,0,0), - makeVertex( WK_TALWIDTH/2-(WK_TALWIDTH-WK_PREWIDTH)/2,WK_PRELEN,0,0xFFCCCCCC,0,0), - makeVertex(-WK_TALWIDTH/2+(WK_TALWIDTH-WK_PREWIDTH)/2,WK_PRELEN,0,0xFFCCCCCC,0,0), - makeVertex( WK_TALWIDTH/2,WK_PRELEN,0,0xFFCCCCCC,0,0), - makeVertex( WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,0,0xFFCCCCCC,0,0), - makeVertex(-WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,0,0xFFCCCCCC,0,0), - makeVertex(-WK_TALWIDTH/2,WK_PRELEN,0,0xFFCCCCCC,0,0)); - wkd->addIndices(60, - 0,1,2, 0,2,3, 4,5,6, 4,6,7, - 8,9,16, 9,16,17, 9,10,18, 9,17,18, - 10,12,18, 12,18,19, 12,13,20, 12,19,20, - 13,14,21, 13,20,21, 14,15,21, 15,21,22, - 15,11,22, 11,22,23, 11,23,8, 23,16,8); + wkd->addVertices(24, + makeVertex(-WK_TALWIDTH / 2 + (WK_TALWIDTH - WK_PREWIDTH) / 2, 0, WK_HEIGHT, 0xFFFFFFFF, 0, 0), + makeVertex(WK_TALWIDTH / 2 - (WK_TALWIDTH - WK_PREWIDTH) / 2, 0, WK_HEIGHT, 0xFFFFFFFF, 0, 0), + makeVertex(WK_TALWIDTH / 2 - (WK_TALWIDTH - WK_PREWIDTH) / 2, WK_PRELEN, WK_HEIGHT, 0xFFFFFFFF, 0, 0), + makeVertex(-WK_TALWIDTH / 2 + (WK_TALWIDTH - WK_PREWIDTH) / 2, WK_PRELEN, WK_HEIGHT, 0xFFFFFFFF, 0, 0), + makeVertex(WK_TALWIDTH / 2, WK_PRELEN, WK_HEIGHT, 0xFFFFFFFF, 0, 0), + makeVertex(WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN + WK_WING, WK_HEIGHT, 0xFFFFFFFF, 0, 0), + makeVertex(-WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN + WK_WING, WK_HEIGHT, 0xFFFFFFFF, 0, 0), + makeVertex(-WK_TALWIDTH / 2, WK_PRELEN, WK_HEIGHT, 0xFFFFFFFF, 0, 0), //// + makeVertex(-WK_TALWIDTH / 2 + (WK_TALWIDTH - WK_PREWIDTH) / 2, 0, WK_HEIGHT, 0xFFCCCCCC, 0, 0), + makeVertex(WK_TALWIDTH / 2 - (WK_TALWIDTH - WK_PREWIDTH) / 2, 0, WK_HEIGHT, 0xFFCCCCCC, 0, 0), + makeVertex(WK_TALWIDTH / 2 - (WK_TALWIDTH - WK_PREWIDTH) / 2, WK_PRELEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0), + makeVertex(-WK_TALWIDTH / 2 + (WK_TALWIDTH - WK_PREWIDTH) / 2, WK_PRELEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0), + makeVertex(WK_TALWIDTH / 2, WK_PRELEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0), + makeVertex(WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0), + makeVertex(-WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0), + makeVertex(-WK_TALWIDTH / 2, WK_PRELEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0), //// + makeVertex(-WK_TALWIDTH / 2 + (WK_TALWIDTH - WK_PREWIDTH) / 2, 0, 0, 0xFFCCCCCC, 0, 0), + makeVertex(WK_TALWIDTH / 2 - (WK_TALWIDTH - WK_PREWIDTH) / 2, 0, 0, 0xFFCCCCCC, 0, 0), + makeVertex(WK_TALWIDTH / 2 - (WK_TALWIDTH - WK_PREWIDTH) / 2, WK_PRELEN, 0, 0xFFCCCCCC, 0, 0), + makeVertex(-WK_TALWIDTH / 2 + (WK_TALWIDTH - WK_PREWIDTH) / 2, WK_PRELEN, 0, 0xFFCCCCCC, 0, 0), + makeVertex(WK_TALWIDTH / 2, WK_PRELEN, 0, 0xFFCCCCCC, 0, 0), + makeVertex(WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, 0, 0xFFCCCCCC, 0, 0), + makeVertex(-WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, 0, 0xFFCCCCCC, 0, 0), + makeVertex(-WK_TALWIDTH / 2, WK_PRELEN, 0, 0xFFCCCCCC, 0, 0)); + wkd->addIndices(60, + 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, + 8, 9, 16, 9, 16, 17, 9, 10, 18, 9, 17, 18, + 10, 12, 18, 12, 18, 19, 12, 13, 20, 12, 19, 20, + 13, 14, 21, 13, 20, 21, 14, 15, 21, 15, 21, 22, + 15, 11, 22, 11, 22, 23, 11, 23, 8, 23, 16, 8); - wkg->addVertices(24, - makeVertex(-WK_TALWIDTH/2+WK_WING+WK_TALWIDTH/12,0,WK_HEIGHT,0xFFFFFFFF,0,0), - makeVertex(-WK_TALWIDTH/2+WK_WING+WK_TALWIDTH/12+WK_PREWIDTH,0,WK_HEIGHT,0xFFFFFFFF,0,0), - makeVertex(-WK_TALWIDTH/2+WK_WING+WK_TALWIDTH/12+WK_PREWIDTH,WK_PRELEN,WK_HEIGHT,0xFFFFFFFF,0,0), - makeVertex(-WK_TALWIDTH/2+WK_WING+WK_TALWIDTH/12,WK_PRELEN,WK_HEIGHT,0xFFFFFFFF,0,0), - makeVertex( WK_TALWIDTH/2,WK_PRELEN,WK_HEIGHT,0xFFFFFFFF,0,0), - makeVertex( WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN+WK_WING,WK_HEIGHT,0xFFFFFFFF,0,0), - makeVertex(-WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN+WK_WING,WK_HEIGHT,0xFFFFFFFF,0,0), - makeVertex(-WK_TALWIDTH/2,WK_PRELEN,WK_HEIGHT,0xFFFFFFFF,0,0),//// - makeVertex(-WK_TALWIDTH/2+WK_WING+WK_TALWIDTH/12,0,WK_HEIGHT,0xFFCCCCCC,0,0), - makeVertex(-WK_TALWIDTH/2+WK_WING+WK_TALWIDTH/12+WK_PREWIDTH,0,WK_HEIGHT,0xFFCCCCCC,0,0), - makeVertex(-WK_TALWIDTH/2+WK_WING+WK_TALWIDTH/12+WK_PREWIDTH,WK_PRELEN,WK_HEIGHT,0xFFCCCCCC,0,0), - makeVertex(-WK_TALWIDTH/2+WK_WING+WK_TALWIDTH/12,WK_PRELEN,WK_HEIGHT,0xFFCCCCCC,0,0), - makeVertex( WK_TALWIDTH/2,WK_PRELEN,WK_HEIGHT,0xFFCCCCCC,0,0), - makeVertex( WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,WK_HEIGHT,0xFFCCCCCC,0,0), - makeVertex(-WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,WK_HEIGHT,0xFFCCCCCC,0,0), - makeVertex(-WK_TALWIDTH/2,WK_PRELEN,WK_HEIGHT,0xFFCCCCCC,0,0),//// - makeVertex(-WK_TALWIDTH/2+WK_WING+WK_TALWIDTH/12,0,0,0xFFCCCCCC,0,0), - makeVertex(-WK_TALWIDTH/2+WK_WING+WK_TALWIDTH/12+WK_PREWIDTH,0,0,0xFFCCCCCC,0,0), - makeVertex(-WK_TALWIDTH/2+WK_WING+WK_TALWIDTH/12+WK_PREWIDTH,WK_PRELEN,0,0xFFCCCCCC,0,0), - makeVertex(-WK_TALWIDTH/2+WK_WING+WK_TALWIDTH/12,WK_PRELEN,0,0xFFCCCCCC,0,0), - makeVertex( WK_TALWIDTH/2,WK_PRELEN,0,0xFFCCCCCC,0,0), - makeVertex( WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,0,0xFFCCCCCC,0,0), - makeVertex(-WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,0,0xFFCCCCCC,0,0), - makeVertex(-WK_TALWIDTH/2,WK_PRELEN,0,0xFFCCCCCC,0,0)); - wkg->addIndices(60, - 0,1,2, 0,2,3, 4,5,6, 4,6,7, - 8,9,16, 9,16,17, 9,10,18, 9,17,18, - 10,12,18, 12,18,19, 12,13,20, 12,19,20, - 13,14,21, 13,20,21, 14,15,21, 15,21,22, - 15,11,22, 11,22,23, 11,23,8, 23,16,8); + wkg->addVertices(24, + makeVertex(-WK_TALWIDTH / 2 + WK_WING + WK_TALWIDTH / 12, 0, WK_HEIGHT, 0xFFFFFFFF, 0, 0), + makeVertex(-WK_TALWIDTH / 2 + WK_WING + WK_TALWIDTH / 12 + WK_PREWIDTH, 0, WK_HEIGHT, 0xFFFFFFFF, 0, 0), + makeVertex(-WK_TALWIDTH / 2 + WK_WING + WK_TALWIDTH / 12 + WK_PREWIDTH, WK_PRELEN, WK_HEIGHT, 0xFFFFFFFF, 0, 0), + makeVertex(-WK_TALWIDTH / 2 + WK_WING + WK_TALWIDTH / 12, WK_PRELEN, WK_HEIGHT, 0xFFFFFFFF, 0, 0), + makeVertex(WK_TALWIDTH / 2, WK_PRELEN, WK_HEIGHT, 0xFFFFFFFF, 0, 0), + makeVertex(WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN + WK_WING, WK_HEIGHT, 0xFFFFFFFF, 0, 0), + makeVertex(-WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN + WK_WING, WK_HEIGHT, 0xFFFFFFFF, 0, 0), + makeVertex(-WK_TALWIDTH / 2, WK_PRELEN, WK_HEIGHT, 0xFFFFFFFF, 0, 0), //// + makeVertex(-WK_TALWIDTH / 2 + WK_WING + WK_TALWIDTH / 12, 0, WK_HEIGHT, 0xFFCCCCCC, 0, 0), + makeVertex(-WK_TALWIDTH / 2 + WK_WING + WK_TALWIDTH / 12 + WK_PREWIDTH, 0, WK_HEIGHT, 0xFFCCCCCC, 0, 0), + makeVertex(-WK_TALWIDTH / 2 + WK_WING + WK_TALWIDTH / 12 + WK_PREWIDTH, WK_PRELEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0), + makeVertex(-WK_TALWIDTH / 2 + WK_WING + WK_TALWIDTH / 12, WK_PRELEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0), + makeVertex(WK_TALWIDTH / 2, WK_PRELEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0), + makeVertex(WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0), + makeVertex(-WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0), + makeVertex(-WK_TALWIDTH / 2, WK_PRELEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0), //// + makeVertex(-WK_TALWIDTH / 2 + WK_WING + WK_TALWIDTH / 12, 0, 0, 0xFFCCCCCC, 0, 0), + makeVertex(-WK_TALWIDTH / 2 + WK_WING + WK_TALWIDTH / 12 + WK_PREWIDTH, 0, 0, 0xFFCCCCCC, 0, 0), + makeVertex(-WK_TALWIDTH / 2 + WK_WING + WK_TALWIDTH / 12 + WK_PREWIDTH, WK_PRELEN, 0, 0xFFCCCCCC, 0, 0), + makeVertex(-WK_TALWIDTH / 2 + WK_WING + WK_TALWIDTH / 12, WK_PRELEN, 0, 0xFFCCCCCC, 0, 0), + makeVertex(WK_TALWIDTH / 2, WK_PRELEN, 0, 0xFFCCCCCC, 0, 0), + makeVertex(WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, 0, 0xFFCCCCCC, 0, 0), + makeVertex(-WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, 0, 0xFFCCCCCC, 0, 0), + makeVertex(-WK_TALWIDTH / 2, WK_PRELEN, 0, 0xFFCCCCCC, 0, 0)); + wkg->addIndices(60, + 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, + 8, 9, 16, 9, 16, 17, 9, 10, 18, 9, 17, 18, + 10, 12, 18, 12, 18, 19, 12, 13, 20, 12, 19, 20, + 13, 14, 21, 13, 20, 21, 14, 15, 21, 15, 21, 22, + 15, 11, 22, 11, 22, 23, 11, 23, 8, 23, 16, 8); - wka->addVertices(24, - makeVertex(WK_TALWIDTH/2-WK_WING-WK_TALWIDTH/24-WK_PREWIDTH,0,WK_HEIGHT,0xFFFFFFFF,0,0), - makeVertex(WK_TALWIDTH/2-WK_WING-WK_TALWIDTH/24,0,WK_HEIGHT,0xFFFFFFFF,0,0), - makeVertex(WK_TALWIDTH/2-WK_WING-WK_TALWIDTH/24,WK_PRELEN,WK_HEIGHT,0xFFFFFFFF,0,0), - makeVertex(WK_TALWIDTH/2-WK_WING-WK_TALWIDTH/24-WK_PREWIDTH,WK_PRELEN,WK_HEIGHT,0xFFFFFFFF,0,0), - makeVertex( WK_TALWIDTH/2,WK_PRELEN,WK_HEIGHT,0xFFFFFFFF,0,0), - makeVertex( WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN+WK_WING,WK_HEIGHT,0xFFFFFFFF,0,0), - makeVertex(-WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN+WK_WING,WK_HEIGHT,0xFFFFFFFF,0,0), - makeVertex(-WK_TALWIDTH/2,WK_PRELEN,WK_HEIGHT,0xFFFFFFFF,0,0),//// - makeVertex(WK_TALWIDTH/2-WK_WING-WK_TALWIDTH/24-WK_PREWIDTH,0,WK_HEIGHT,0xFFCCCCCC,0,0), - makeVertex(WK_TALWIDTH/2-WK_WING-WK_TALWIDTH/24,0,WK_HEIGHT,0xFFCCCCCC,0,0), - makeVertex(WK_TALWIDTH/2-WK_WING-WK_TALWIDTH/24,WK_PRELEN,WK_HEIGHT,0xFFCCCCCC,0,0), - makeVertex(WK_TALWIDTH/2-WK_WING-WK_TALWIDTH/24-WK_PREWIDTH,WK_PRELEN,WK_HEIGHT,0xFFCCCCCC,0,0), - makeVertex( WK_TALWIDTH/2,WK_PRELEN,WK_HEIGHT,0xFFCCCCCC,0,0), - makeVertex( WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,WK_HEIGHT,0xFFCCCCCC,0,0), - makeVertex(-WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,WK_HEIGHT,0xFFCCCCCC,0,0), - makeVertex(-WK_TALWIDTH/2,WK_PRELEN,WK_HEIGHT,0xFFCCCCCC,0,0),//// - makeVertex(WK_TALWIDTH/2-WK_WING-WK_TALWIDTH/24-WK_PREWIDTH,0,0,0xFFCCCCCC,0,0), - makeVertex(WK_TALWIDTH/2-WK_WING-WK_TALWIDTH/24,0,0,0xFFCCCCCC,0,0), - makeVertex(WK_TALWIDTH/2-WK_WING-WK_TALWIDTH/24,WK_PRELEN,0,0xFFCCCCCC,0,0), - makeVertex(WK_TALWIDTH/2-WK_WING-WK_TALWIDTH/24-WK_PREWIDTH,WK_PRELEN,0,0xFFCCCCCC,0,0), - makeVertex( WK_TALWIDTH/2,WK_PRELEN,0,0xFFCCCCCC,0,0), - makeVertex( WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,0,0xFFCCCCCC,0,0), - makeVertex(-WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,0,0xFFCCCCCC,0,0), - makeVertex(-WK_TALWIDTH/2,WK_PRELEN,0,0xFFCCCCCC,0,0)); - wka->addIndices(60, - 0,1,2, 0,2,3, 4,5,6, 4,6,7, - 8,9,16, 9,16,17, 9,10,18, 9,17,18, - 10,12,18, 12,18,19, 12,13,20, 12,19,20, - 13,14,21, 13,20,21, 14,15,21, 15,21,22, - 15,11,22, 11,22,23, 11,23,8, 23,16,8); + wka->addVertices(24, + makeVertex(WK_TALWIDTH / 2 - WK_WING - WK_TALWIDTH / 24 - WK_PREWIDTH, 0, WK_HEIGHT, 0xFFFFFFFF, 0, 0), + makeVertex(WK_TALWIDTH / 2 - WK_WING - WK_TALWIDTH / 24, 0, WK_HEIGHT, 0xFFFFFFFF, 0, 0), + makeVertex(WK_TALWIDTH / 2 - WK_WING - WK_TALWIDTH / 24, WK_PRELEN, WK_HEIGHT, 0xFFFFFFFF, 0, 0), + makeVertex(WK_TALWIDTH / 2 - WK_WING - WK_TALWIDTH / 24 - WK_PREWIDTH, WK_PRELEN, WK_HEIGHT, 0xFFFFFFFF, 0, 0), + makeVertex(WK_TALWIDTH / 2, WK_PRELEN, WK_HEIGHT, 0xFFFFFFFF, 0, 0), + makeVertex(WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN + WK_WING, WK_HEIGHT, 0xFFFFFFFF, 0, 0), + makeVertex(-WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN + WK_WING, WK_HEIGHT, 0xFFFFFFFF, 0, 0), + makeVertex(-WK_TALWIDTH / 2, WK_PRELEN, WK_HEIGHT, 0xFFFFFFFF, 0, 0), //// + makeVertex(WK_TALWIDTH / 2 - WK_WING - WK_TALWIDTH / 24 - WK_PREWIDTH, 0, WK_HEIGHT, 0xFFCCCCCC, 0, 0), + makeVertex(WK_TALWIDTH / 2 - WK_WING - WK_TALWIDTH / 24, 0, WK_HEIGHT, 0xFFCCCCCC, 0, 0), + makeVertex(WK_TALWIDTH / 2 - WK_WING - WK_TALWIDTH / 24, WK_PRELEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0), + makeVertex(WK_TALWIDTH / 2 - WK_WING - WK_TALWIDTH / 24 - WK_PREWIDTH, WK_PRELEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0), + makeVertex(WK_TALWIDTH / 2, WK_PRELEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0), + makeVertex(WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0), + makeVertex(-WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0), + makeVertex(-WK_TALWIDTH / 2, WK_PRELEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0), //// + makeVertex(WK_TALWIDTH / 2 - WK_WING - WK_TALWIDTH / 24 - WK_PREWIDTH, 0, 0, 0xFFCCCCCC, 0, 0), + makeVertex(WK_TALWIDTH / 2 - WK_WING - WK_TALWIDTH / 24, 0, 0, 0xFFCCCCCC, 0, 0), + makeVertex(WK_TALWIDTH / 2 - WK_WING - WK_TALWIDTH / 24, WK_PRELEN, 0, 0xFFCCCCCC, 0, 0), + makeVertex(WK_TALWIDTH / 2 - WK_WING - WK_TALWIDTH / 24 - WK_PREWIDTH, WK_PRELEN, 0, 0xFFCCCCCC, 0, 0), + makeVertex(WK_TALWIDTH / 2, WK_PRELEN, 0, 0xFFCCCCCC, 0, 0), + makeVertex(WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, 0, 0xFFCCCCCC, 0, 0), + makeVertex(-WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, 0, 0xFFCCCCCC, 0, 0), + makeVertex(-WK_TALWIDTH / 2, WK_PRELEN, 0, 0xFFCCCCCC, 0, 0)); + wka->addIndices(60, + 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, + 8, 9, 16, 9, 16, 17, 9, 10, 18, 9, 17, 18, + 10, 12, 18, 12, 18, 19, 12, 13, 20, 12, 19, 20, + 13, 14, 21, 13, 20, 21, 14, 15, 21, 15, 21, 22, + 15, 11, 22, 11, 22, 23, 11, 23, 8, 23, 16, 8); - bk->addVertices(10, - makeVertex(-BK_WIDTH/2,0,BK_HEIGHT+BK_BOTTOM,0xFF000000,0,0), - makeVertex( BK_WIDTH/2,0,BK_HEIGHT+BK_BOTTOM,0xFF000000,0,0), - makeVertex( BK_WIDTH/2,BK_PRELEN,BK_HEIGHT+BK_BOTTOM,0xFF000000,0,0), - makeVertex(-BK_WIDTH/2,BK_PRELEN,BK_HEIGHT+BK_BOTTOM,0xFF000000,0,0), - makeVertex(-BK_WIDTH/2,WK_PRELEN*0.995,BK_DBOTTOM+BK_BOTTOM,0xFF000000,0,0), - makeVertex( BK_WIDTH/2,WK_PRELEN*0.995,BK_DBOTTOM+BK_BOTTOM,0xFF000000,0,0), - makeVertex( BK_WIDTH/2,WK_PRELEN*0.995,BK_BOTTOM,0xFF000000,0,0), - makeVertex(-BK_WIDTH/2,WK_PRELEN*0.995,BK_BOTTOM,0xFF000000,0,0), - makeVertex(-BK_WIDTH/2,0,BK_BOTTOM,0xFF000000,0,0), - makeVertex( BK_WIDTH/2,0,BK_BOTTOM,0xFF000000,0,0)); - bk->addIndices(48, - 0,1,3, 1,2,3, 2,3,4, 2,4,5, - 4,5,7, 5,6,7, 6,7,8, 6,8,9, - 0,1,8, 1,8,9, 2,5,6, 2,6,9, - 2,9,1, 3,4,7, 3,7,8, 3,8,0); + bk->addVertices(10, + makeVertex(-BK_WIDTH / 2, 0, BK_HEIGHT + BK_BOTTOM, 0xFF000000, 0, 0), + makeVertex(BK_WIDTH / 2, 0, BK_HEIGHT + BK_BOTTOM, 0xFF000000, 0, 0), + makeVertex(BK_WIDTH / 2, BK_PRELEN, BK_HEIGHT + BK_BOTTOM, 0xFF000000, 0, 0), + makeVertex(-BK_WIDTH / 2, BK_PRELEN, BK_HEIGHT + BK_BOTTOM, 0xFF000000, 0, 0), + makeVertex(-BK_WIDTH / 2, WK_PRELEN * 0.995, BK_DBOTTOM + BK_BOTTOM, 0xFF000000, 0, 0), + makeVertex(BK_WIDTH / 2, WK_PRELEN * 0.995, BK_DBOTTOM + BK_BOTTOM, 0xFF000000, 0, 0), + makeVertex(BK_WIDTH / 2, WK_PRELEN * 0.995, BK_BOTTOM, 0xFF000000, 0, 0), + makeVertex(-BK_WIDTH / 2, WK_PRELEN * 0.995, BK_BOTTOM, 0xFF000000, 0, 0), + makeVertex(-BK_WIDTH / 2, 0, BK_BOTTOM, 0xFF000000, 0, 0), + makeVertex(BK_WIDTH / 2, 0, BK_BOTTOM, 0xFF000000, 0, 0)); + bk->addIndices(48, + 0, 1, 3, 1, 2, 3, 2, 3, 4, 2, 4, 5, + 4, 5, 7, 5, 6, 7, 6, 7, 8, 6, 8, 9, + 0, 1, 8, 1, 8, 9, 2, 5, 6, 2, 6, 9, + 2, 9, 1, 3, 4, 7, 3, 7, 8, 3, 8, 0); } diff --git a/visualization/qmpvirtualpiano3d.hpp b/visualization/qmpvirtualpiano3d.hpp index cecd992..d00212a 100644 --- a/visualization/qmpvirtualpiano3d.hpp +++ b/visualization/qmpvirtualpiano3d.hpp @@ -16,15 +16,15 @@ #define BK_DBOTTOM 1. class qmpVirtualPiano3D { - private: - smEntity3D *wkcf,*wkeb,*wkd,*wkg,*wka,*bk; - smEntity3DBuffer *ebuf; - void buildKeys(); - double traveld[128]; - public: - qmpVirtualPiano3D(); - ~qmpVirtualPiano3D(); - void render(smvec3d p); - void setKeyTravelDist(int k,double td); +private: + smEntity3D *wkcf, *wkeb, *wkd, *wkg, *wka, *bk; + smEntity3DBuffer *ebuf; + void buildKeys(); + double traveld[128]; +public: + qmpVirtualPiano3D(); + ~qmpVirtualPiano3D(); + void render(smvec3d p); + void setKeyTravelDist(int k, double td); }; #endif // QMPVIRTUALPIANO3D_H diff --git a/visualization/qmpvisualization.cpp b/visualization/qmpvisualization.cpp index 09f80d6..0f73b8a 100644 --- a/visualization/qmpvisualization.cpp +++ b/visualization/qmpvisualization.cpp @@ -6,1018 +6,1341 @@ #include #include "qmpvisualization.hpp" -int viewdist=100; -int notestretch=100;//length of quarter note -int minnotelength=100; -int noteappearance=1,showpiano=1,stairpiano=1,savevp=1,showlabel=1; -int wwidth=800,wheight=600,wsupersample=1,wmultisample=0,showparticle=1; -int horizontal=1,flat=0,osdpos=0,fontsize=16,showmeasure=1; -int fov=60,vsync=1,tfps=60,usespectrum=0; -DWORD chkrtint=0xFF999999; -const wchar_t* minors=L"abebbbf c g d a e b f#c#g#d#a#"; -const wchar_t* majors=L"CbGbDbAbEbBbF C G D A E B F#C#"; -double fpoffsets[]={1,18,28,50,55,82,98,109,130,137,161,164,191}; -double froffsets[]={0,18,33,50,65,82,98,113,130,145,161,176,191}; -DWORD iccolors[]={0XFFFF0000,0XFFFF8000,0XFFFFBF00,0XFFF0F000, - 0XFFB2EE00,0XFF80FF00,0XFF00FF00,0XFF00EEB2, - 0XFF00EEEE,0XFF333333,0XFF00BFFF,0XFF007FFF, - 0XFF0000FF,0XFF7F00FF,0XFFBF00FF,0XFFFF00BF}; -DWORD accolors[]={0XFFFF9999,0XFFFFCC99,0XFFFFF4D4,0XFFFFFFDD, - 0XFFF0FFC2,0XFFDDFFBB,0XFFBBFFBB,0XFFAAFFEA, - 0XFFBBFFFF,0XFF999999,0XFF99EEFF,0XFF99CCFF, - 0XFF9999FF,0XFFCC99FF,0XFFEE99FF,0XFFFF99EE}; +int viewdist = 100; +int notestretch = 100; //length of quarter note +int minnotelength = 100; +int noteappearance = 1, showpiano = 1, stairpiano = 1, savevp = 1, showlabel = 1; +int wwidth = 800, wheight = 600, wsupersample = 1, wmultisample = 0, showparticle = 1; +int horizontal = 1, flat = 0, osdpos = 0, fontsize = 16, showmeasure = 1; +int fov = 60, vsync = 1, tfps = 60, usespectrum = 0; +DWORD chkrtint = 0xFF999999; +const wchar_t *minors = L"abebbbf c g d a e b f#c#g#d#a#"; +const wchar_t *majors = L"CbGbDbAbEbBbF C G D A E B F#C#"; +double fpoffsets[] = {1, 18, 28, 50, 55, 82, 98, 109, 130, 137, 161, 164, 191}; +double froffsets[] = {0, 18, 33, 50, 65, 82, 98, 113, 130, 145, 161, 176, 191}; +DWORD iccolors[] = {0XFFFF0000, 0XFFFF8000, 0XFFFFBF00, 0XFFF0F000, + 0XFFB2EE00, 0XFF80FF00, 0XFF00FF00, 0XFF00EEB2, + 0XFF00EEEE, 0XFF333333, 0XFF00BFFF, 0XFF007FFF, + 0XFF0000FF, 0XFF7F00FF, 0XFFBF00FF, 0XFFFF00BF + }; +DWORD accolors[] = {0XFFFF9999, 0XFFFFCC99, 0XFFFFF4D4, 0XFFFFFFDD, + 0XFFF0FFC2, 0XFFDDFFBB, 0XFFBBFFBB, 0XFFAAFFEA, + 0XFFBBFFFF, 0XFF999999, 0XFF99EEFF, 0XFF99CCFF, + 0XFF9999FF, 0XFFCC99FF, 0XFFEE99FF, 0XFFFF99EE + }; -std::set sustaininst={16,17,18,19,20,21,22,23, - 40,41,42,43,44,45,48,49, - 50,51,52,53,54,56,57,58, - 59,60,61,62,63,64,65,66, - 67,68,69,70,71,72,73,74, - 75,76,77,78,79,80,81,82, - 83,84,85,86,87,89,90,91, - 92,93,94,95,97,101,109,110,111}; +std::set sustaininst = {16, 17, 18, 19, 20, 21, 22, 23, + 40, 41, 42, 43, 44, 45, 48, 49, + 50, 51, 52, 53, 54, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, + 83, 84, 85, 86, 87, 89, 90, 91, + 92, 93, 94, 95, 97, 101, 109, 110, 111 + }; -bool cmp(MidiVisualEvent* a,MidiVisualEvent* b) +bool cmp(MidiVisualEvent *a, MidiVisualEvent *b) { - if(a->tcstcs)return true;if(a->tcs>b->tcs)return false; - if(a->tcetce)return true;return false; + if (a->tcs < b->tcs) + return true; + if (a->tcs > b->tcs) + return false; + if (a->tce < b->tce) + return true; + return false; } void qmpVisualization::showThread() { - wwidth=api->getOptionInt("Visualization/wwidth"); - wheight=api->getOptionInt("Visualization/wheight"); - wsupersample=api->getOptionInt("Visualization/supersampling"); - wmultisample=api->getOptionInt("Visualization/multisampling"); - fov=api->getOptionInt("Visualization/fov"); - noteappearance=api->getOptionBool("Visualization/3dnotes"); - showpiano=api->getOptionBool("Visualization/showpiano"); - stairpiano=api->getOptionBool("Visualization/stairpiano"); - showlabel=api->getOptionBool("Visualization/showlabel"); - showparticle=api->getOptionBool("Visualization/showparticle"); - horizontal=api->getOptionBool("Visualization/horizontal"); - flat=api->getOptionBool("Visualization/flat"); - showmeasure=api->getOptionBool("Visualization/showmeasure"); - savevp=api->getOptionBool("Visualization/savevp"); - vsync=api->getOptionBool("Visualization/vsync"); - tfps=api->getOptionInt("Visualization/tfps"); - osdpos=api->getOptionEnumInt("Visualization/osdpos"); - fontsize=api->getOptionInt("Visualization/fontsize"); - viewdist=api->getOptionInt("Visualization/viewdist"); - notestretch=api->getOptionInt("Visualization/notestretch"); - minnotelength=api->getOptionInt("Visualization/minnotelen"); - chkrtint=api->getOptionUint("Visualization/chkrtint"); - usespectrum=api->getOptionBool("Visualization/usespectrum"); - for(int i=0;i<16;++i) - { - accolors[i]=api->getOptionUint("Visualization/chActiveColor"+std::to_string(i)); - iccolors[i]=api->getOptionUint("Visualization/chInactiveColor"+std::to_string(i)); - } - sm=smGetInterface(SMELT_APILEVEL); - sm->smVidMode(wwidth,wheight,true,!hidewindow); - sm->smUpdateFunc(h);sm->smQuitFunc(closeh); - sm->smWinTitle("QMidiPlayer Visualization"); - sm->smSetFPS(vsync?FPS_VSYNC:tfps); - sm->smNoSuspend(true); - sm->smInit();shouldclose=false; - sm->smTextureOpt(TPOT_POT,TFLT_LINEAR); - chequer=sm->smTextureLoad("chequerboard.png");if(!chequer) - chequer=sm->smTextureLoad("/usr/share/qmidiplayer/img/chequerboard.png"); - pianotex=sm->smTextureLoad("kb_128.png");if(!pianotex) - pianotex=sm->smTextureLoad("/usr/share/qmidiplayer/img/kb_128.png"); - particletex=sm->smTextureLoad("particle.png");if(!particletex) - particletex=sm->smTextureLoad("/usr/share/qmidiplayer/img/particle.png"); - bgtex=sm->smTextureLoad(api->getOptionString("Visualization/background").c_str()); - if(rendermode) - fbcont=new DWORD[wwidth*wheight]; - if(showparticle&&!horizontal) - { - smParticleSystemInfo psinfo; - psinfo.acc=smvec3d(0,0,-0.05);psinfo.accvar=smvec3d(0,0,0.005); - psinfo.vel=smvec3d(0,0,0.5);psinfo.velvar=smvec3d(0.1,0.1,0.2); - psinfo.rotv=psinfo.rota=psinfo.rotavar=smvec3d(0,0,0);psinfo.rotvvar=smvec3d(0.04,0.04,0.04); - psinfo.lifespan=1;psinfo.lifespanvar=0.5;psinfo.maxcount=1000;psinfo.emissioncount=5;psinfo.ecvar=2; - psinfo.emissiondelay=0.1;psinfo.edvar=0;psinfo.initsize=0.8;psinfo.initsizevar=0.1; - psinfo.finalsize=0.1;psinfo.finalsizevar=0.05;psinfo.initcolor=0xFFFFFFFF;psinfo.finalcolor=0x00FFFFFF; - psinfo.initcolorvar=psinfo.finalcolorvar=0;psinfo.texture=particletex;psinfo.blend=BLEND_ALPHAADD; - psepg=new smXLinePSGenerator(.6); - for(int i=0;i<16;++i)for(int j=0;j<128;++j) - { - pss[i][j]=new smParticleSystem(); - pss[i][j]->setPSEmissionPosGen(psepg); - psinfo.initcolor=accolors[i];psinfo.finalcolor=SETA(accolors[i],0); - pss[i][j]->setParticleSystemInfo(psinfo); - pss[i][j]->setPos(smvec3d(0.756*((double)j-64)+.48,(stairpiano?(56-i*7.):(64-i*8.)),stairpiano*i*2+0.1)); - } - }else memset(pss,0,sizeof(pss)); - if(showpiano&&!horizontal)for(int i=0;i<16;++i)p3d[i]=new qmpVirtualPiano3D(); - memset(traveld,0,sizeof(traveld)); - nebuf=new smEntity3DBuffer(); - tdscn=sm->smTargetCreate(wwidth*wsupersample,wheight*wsupersample,wmultisample); - tdparticles=sm->smTargetCreate(wwidth*wsupersample,wheight*wsupersample,wmultisample); - if(!api->getOptionString("Visualization/font2").length()||!font.loadTTF(api->getOptionString("Visualization/font2").c_str(),fontsize)) - if(!font.loadTTF("/usr/share/fonts/truetype/freefont/FreeMono.ttf",fontsize)) - if(!font.loadTTF("/usr/share/fonts/gnu-free/FreeMono.otf",fontsize)) - if(!font.loadTTF((std::string(getenv("windir")?getenv("windir"):"")+"/Fonts/cour.ttf").c_str(),fontsize)) - fprintf(stderr,"W: Font load failed.\n"); - if(!api->getOptionString("Visualization/font2").length()||!fonthdpi.loadTTF(api->getOptionString("Visualization/font2").c_str(),180)) - if(!fonthdpi.loadTTF("/usr/share/fonts/truetype/freefont/FreeMono.ttf",180)) - if(!fonthdpi.loadTTF("/usr/share/fonts/gnu-free/FreeMono.otf",180)) - if(!fonthdpi.loadTTF((std::string(getenv("windir")?getenv("windir"):"")+"/Fonts/cour.ttf").c_str(),180)) - fprintf(stderr,"W: Font load failed.\n"); - if(!api->getOptionString("Visualization/font1").length()||!font2.loadTTF(api->getOptionString("Visualization/font1").c_str(),fontsize)) - if(!font2.loadTTF("/usr/share/fonts/truetype/wqy/wqy-microhei.ttc",fontsize)) - if(!font2.loadTTF("/usr/share/fonts/wenquanyi/wqy-microhei/wqy-microhei.ttc",fontsize)) - if(!font2.loadTTF((std::string(getenv("windir")?getenv("windir"):"")+"/Fonts/msyh.ttc").c_str(),fontsize)) - if(!font2.loadTTF((std::string(getenv("windir")?getenv("windir"):"")+"/Fonts/segoeui.ttf").c_str(),fontsize)) - fprintf(stderr,"W: Font load failed.\n"); - if(pos[0]<-1e8) - { - if(horizontal) - { - pos[0]=-20;pos[1]=45;pos[2]=0; - rot[0]=0;rot[1]=90;rot[2]=90; - } - else - { - pos[0]=0;pos[1]=120;pos[2]=70; - rot[0]=0;rot[1]=75;rot[2]=90; - } - } - debug=false; - ctk=api->getCurrentTimeStamp(); - lst=std::chrono::steady_clock::now(); - sm->smMainLoop(); - sm->smFinale(); + wwidth = api->getOptionInt("Visualization/wwidth"); + wheight = api->getOptionInt("Visualization/wheight"); + wsupersample = api->getOptionInt("Visualization/supersampling"); + wmultisample = api->getOptionInt("Visualization/multisampling"); + fov = api->getOptionInt("Visualization/fov"); + noteappearance = api->getOptionBool("Visualization/3dnotes"); + showpiano = api->getOptionBool("Visualization/showpiano"); + stairpiano = api->getOptionBool("Visualization/stairpiano"); + showlabel = api->getOptionBool("Visualization/showlabel"); + showparticle = api->getOptionBool("Visualization/showparticle"); + horizontal = api->getOptionBool("Visualization/horizontal"); + flat = api->getOptionBool("Visualization/flat"); + showmeasure = api->getOptionBool("Visualization/showmeasure"); + savevp = api->getOptionBool("Visualization/savevp"); + vsync = api->getOptionBool("Visualization/vsync"); + tfps = api->getOptionInt("Visualization/tfps"); + osdpos = api->getOptionEnumInt("Visualization/osdpos"); + fontsize = api->getOptionInt("Visualization/fontsize"); + viewdist = api->getOptionInt("Visualization/viewdist"); + notestretch = api->getOptionInt("Visualization/notestretch"); + minnotelength = api->getOptionInt("Visualization/minnotelen"); + chkrtint = api->getOptionUint("Visualization/chkrtint"); + usespectrum = api->getOptionBool("Visualization/usespectrum"); + for (int i = 0; i < 16; ++i) + { + accolors[i] = api->getOptionUint("Visualization/chActiveColor" + std::to_string(i)); + iccolors[i] = api->getOptionUint("Visualization/chInactiveColor" + std::to_string(i)); + } + sm = smGetInterface(SMELT_APILEVEL); + sm->smVidMode(wwidth, wheight, true, !hidewindow); + sm->smUpdateFunc(h); + sm->smQuitFunc(closeh); + sm->smWinTitle("QMidiPlayer Visualization"); + sm->smSetFPS(vsync ? FPS_VSYNC : tfps); + sm->smNoSuspend(true); + sm->smInit(); + shouldclose = false; + sm->smTextureOpt(TPOT_POT, TFLT_LINEAR); + chequer = sm->smTextureLoad("chequerboard.png"); + if (!chequer) + chequer = sm->smTextureLoad("/usr/share/qmidiplayer/img/chequerboard.png"); + pianotex = sm->smTextureLoad("kb_128.png"); + if (!pianotex) + pianotex = sm->smTextureLoad("/usr/share/qmidiplayer/img/kb_128.png"); + particletex = sm->smTextureLoad("particle.png"); + if (!particletex) + particletex = sm->smTextureLoad("/usr/share/qmidiplayer/img/particle.png"); + bgtex = sm->smTextureLoad(api->getOptionString("Visualization/background").c_str()); + if (rendermode) + fbcont = new DWORD[wwidth * wheight]; + if (showparticle && !horizontal) + { + smParticleSystemInfo psinfo; + psinfo.acc = smvec3d(0, 0, -0.05); + psinfo.accvar = smvec3d(0, 0, 0.005); + psinfo.vel = smvec3d(0, 0, 0.5); + psinfo.velvar = smvec3d(0.1, 0.1, 0.2); + psinfo.rotv = psinfo.rota = psinfo.rotavar = smvec3d(0, 0, 0); + psinfo.rotvvar = smvec3d(0.04, 0.04, 0.04); + psinfo.lifespan = 1; + psinfo.lifespanvar = 0.5; + psinfo.maxcount = 1000; + psinfo.emissioncount = 5; + psinfo.ecvar = 2; + psinfo.emissiondelay = 0.1; + psinfo.edvar = 0; + psinfo.initsize = 0.8; + psinfo.initsizevar = 0.1; + psinfo.finalsize = 0.1; + psinfo.finalsizevar = 0.05; + psinfo.initcolor = 0xFFFFFFFF; + psinfo.finalcolor = 0x00FFFFFF; + psinfo.initcolorvar = psinfo.finalcolorvar = 0; + psinfo.texture = particletex; + psinfo.blend = BLEND_ALPHAADD; + psepg = new smXLinePSGenerator(.6); + for (int i = 0; i < 16; ++i) + for (int j = 0; j < 128; ++j) + { + pss[i][j] = new smParticleSystem(); + pss[i][j]->setPSEmissionPosGen(psepg); + psinfo.initcolor = accolors[i]; + psinfo.finalcolor = SETA(accolors[i], 0); + pss[i][j]->setParticleSystemInfo(psinfo); + pss[i][j]->setPos(smvec3d(0.756 * ((double)j - 64) + .48, (stairpiano ? (56 - i * 7.) : (64 - i * 8.)), stairpiano * i * 2 + 0.1)); + } + } + else memset(pss, 0, sizeof(pss)); + if (showpiano && !horizontal) + for (int i = 0; i < 16; ++i) + p3d[i] = new qmpVirtualPiano3D(); + memset(traveld, 0, sizeof(traveld)); + nebuf = new smEntity3DBuffer(); + tdscn = sm->smTargetCreate(wwidth * wsupersample, wheight * wsupersample, wmultisample); + tdparticles = sm->smTargetCreate(wwidth * wsupersample, wheight * wsupersample, wmultisample); + if (!api->getOptionString("Visualization/font2").length() || !font.loadTTF(api->getOptionString("Visualization/font2").c_str(), fontsize)) + if (!font.loadTTF("/usr/share/fonts/truetype/freefont/FreeMono.ttf", fontsize)) + if (!font.loadTTF("/usr/share/fonts/gnu-free/FreeMono.otf", fontsize)) + if (!font.loadTTF((std::string(getenv("windir") ? getenv("windir") : "") + "/Fonts/cour.ttf").c_str(), fontsize)) + fprintf(stderr, "W: Font load failed.\n"); + if (!api->getOptionString("Visualization/font2").length() || !fonthdpi.loadTTF(api->getOptionString("Visualization/font2").c_str(), 180)) + if (!fonthdpi.loadTTF("/usr/share/fonts/truetype/freefont/FreeMono.ttf", 180)) + if (!fonthdpi.loadTTF("/usr/share/fonts/gnu-free/FreeMono.otf", 180)) + if (!fonthdpi.loadTTF((std::string(getenv("windir") ? getenv("windir") : "") + "/Fonts/cour.ttf").c_str(), 180)) + fprintf(stderr, "W: Font load failed.\n"); + if (!api->getOptionString("Visualization/font1").length() || !font2.loadTTF(api->getOptionString("Visualization/font1").c_str(), fontsize)) + if (!font2.loadTTF("/usr/share/fonts/truetype/wqy/wqy-microhei.ttc", fontsize)) + if (!font2.loadTTF("/usr/share/fonts/wenquanyi/wqy-microhei/wqy-microhei.ttc", fontsize)) + if (!font2.loadTTF((std::string(getenv("windir") ? getenv("windir") : "") + "/Fonts/msyh.ttc").c_str(), fontsize)) + if (!font2.loadTTF((std::string(getenv("windir") ? getenv("windir") : "") + "/Fonts/segoeui.ttf").c_str(), fontsize)) + fprintf(stderr, "W: Font load failed.\n"); + if (pos[0] < -1e8) + { + if (horizontal) + { + pos[0] = -20; + pos[1] = 45; + pos[2] = 0; + rot[0] = 0; + rot[1] = 90; + rot[2] = 90; + } + else + { + pos[0] = 0; + pos[1] = 120; + pos[2] = 70; + rot[0] = 0; + rot[1] = 75; + rot[2] = 90; + } + } + debug = false; + ctk = api->getCurrentTimeStamp(); + lst = std::chrono::steady_clock::now(); + sm->smMainLoop(); + sm->smFinale(); } void qmpVisualization::show() { - rendererTh=new std::thread(&qmpVisualization::showThread,this); + rendererTh = new std::thread(&qmpVisualization::showThread, this); } void qmpVisualization::close() { - shouldclose=true; - if(rendererTh) - { - rendererTh->join(); - delete rendererTh; - rendererTh=nullptr; - }else return; + shouldclose = true; + if (rendererTh) + { + rendererTh->join(); + delete rendererTh; + rendererTh = nullptr; + } + else return; - if(showpiano&&!horizontal)for(int i=0;i<16;++i)delete p3d[i]; - if(showparticle&&!horizontal)for(int i=0;i>16;++i)for(int j=0;j<128;++j){delete pss[i][j];pss[i][j]=0;} - delete nebuf; - if(savevp) - { - api->setOptionDouble("Visualization/px",pos[0]); - api->setOptionDouble("Visualization/py",pos[1]); - api->setOptionDouble("Visualization/pz",pos[2]); - api->setOptionDouble("Visualization/rx",rot[0]); - api->setOptionDouble("Visualization/ry",rot[1]); - api->setOptionDouble("Visualization/rz",rot[2]); - } - if(rendermode) - delete[] fbcont; - font.releaseTTF(); - font2.releaseTTF(); - fonthdpi.releaseTTF(); - sm->smTextureFree(chequer); - sm->smTextureFree(pianotex); - sm->smTextureFree(particletex); - if(bgtex)sm->smTextureFree(bgtex); - sm->smTargetFree(tdscn); - sm->smTargetFree(tdparticles); - sm->smRelease(); + if (showpiano && !horizontal) + for (int i = 0; i < 16; ++i) + delete p3d[i]; + if (showparticle && !horizontal) + for (int i = 0; i > 16; ++i) + for (int j = 0; j < 128; ++j) + { + delete pss[i][j]; + pss[i][j] = 0; + } + delete nebuf; + if (savevp) + { + api->setOptionDouble("Visualization/px", pos[0]); + api->setOptionDouble("Visualization/py", pos[1]); + api->setOptionDouble("Visualization/pz", pos[2]); + api->setOptionDouble("Visualization/rx", rot[0]); + api->setOptionDouble("Visualization/ry", rot[1]); + api->setOptionDouble("Visualization/rz", rot[2]); + } + if (rendermode) + delete[] fbcont; + font.releaseTTF(); + font2.releaseTTF(); + fonthdpi.releaseTTF(); + sm->smTextureFree(chequer); + sm->smTextureFree(pianotex); + sm->smTextureFree(particletex); + if (bgtex) + sm->smTextureFree(bgtex); + sm->smTargetFree(tdscn); + sm->smTargetFree(tdparticles); + sm->smRelease(); } void qmpVisualization::reset() { - for(unsigned i=0;istopPS(); - while(!pendingt[i][j].empty())pendingt[i][j].pop(); - while(!pendingv[i][j].empty())pendingv[i][j].pop(); - } + for (unsigned i = 0; i < pool.size(); ++i) + delete pool[i]; + pool.clear(); + elb = ctk = lstk = cfr = 0; + tspool.clear(); + cts = 0x0402; + cks = 0; + ctp = 500000; + for (int i = 0; i < 16; ++i) + { + cpbr[i] = 2; + cpw[i] = 8192; + } + for (int i = 0; i < 16; ++i) + for (int j = 0; j < 128; ++j) + { + if (showparticle && !horizontal && pss[i][j]) + pss[i][j]->stopPS(); + while (!pendingt[i][j].empty()) + pendingt[i][j].pop(); + while (!pendingv[i][j].empty()) + pendingv[i][j].pop(); + } } -void qmpVisualization::switchToRenderMode(void(*frameCallback)(void*,size_t,uint32_t,uint32_t),bool _hidewindow) +void qmpVisualization::switchToRenderMode(void(*frameCallback)(void *, size_t, uint32_t, uint32_t), bool _hidewindow) { - rendermode=true; - framecb=frameCallback; - hidewindow=_hidewindow; + rendermode = true; + framecb = frameCallback; + hidewindow = _hidewindow; +} +void qmpVisualization::start() +{ + playing = true; +} +void qmpVisualization::stop() +{ + playing = false; +} +void qmpVisualization::pause() +{ + playing = !playing; } -void qmpVisualization::start(){playing=true;} -void qmpVisualization::stop(){playing=false;} -void qmpVisualization::pause(){playing=!playing;} void qmpVisualization::updateVisualization3D() { - smQuad q; - if(!rendermode) - { - if(sm->smGetKeyState(SMK_D))pos[0]+=cos(smMath::deg2rad(rot[2]-90)),pos[1]+=sin(smMath::deg2rad(rot[2]-90)); - if(sm->smGetKeyState(SMK_A))pos[0]-=cos(smMath::deg2rad(rot[2]-90)),pos[1]-=sin(smMath::deg2rad(rot[2]-90)); - if(sm->smGetKeyState(SMK_S))pos[0]+=cos(smMath::deg2rad(rot[2])),pos[1]+=sin(smMath::deg2rad(rot[2])); - if(sm->smGetKeyState(SMK_W))pos[0]-=cos(smMath::deg2rad(rot[2])),pos[1]-=sin(smMath::deg2rad(rot[2])); - if(sm->smGetKeyState(SMK_Q))pos[2]+=1; - if(sm->smGetKeyState(SMK_E))pos[2]-=1; - if(sm->smGetKeyState(SMK_R)) - { - if(horizontal) - { - pos[0]=-20;pos[1]=45;pos[2]=0; - rot[0]=0;rot[1]=90;rot[2]=90; - } - else - { - pos[0]=0;pos[1]=120;pos[2]=70; - rot[0]=0;rot[1]=75;rot[2]=90; - } - } - if(sm->smGetKeyState(SMK_LBUTTON)==SMKST_HIT) - sm->smSetMouseGrab(true),sm->smGetMouse2f(&lastx,&lasty); - if(sm->smGetKeyState(SMK_LBUTTON)==SMKST_KEEP) - { - float x,y; - sm->smGetMouse2f(&x,&y); - rot[1]-=(y-lasty)*0.01; - rot[2]+=(x-lastx)*0.01; - while(rot[1]>360)rot[1]-=360; - while(rot[1]<0)rot[1]+=360; - while(rot[2]>360)rot[2]-=360; - while(rot[2]<0)rot[2]+=360; - } - if(sm->smGetKeyState(SMK_LBUTTON)==SMKST_RELEASE) - { - sm->smSetMouseGrab(false); - sm->smSetMouse2f(wwidth/2,wheight/2); - } - if(sm->smGetKeyState(SMK_I))rot[1]+=1; - if(sm->smGetKeyState(SMK_K))rot[1]-=1; - if(sm->smGetKeyState(SMK_L))rot[0]+=1; - if(sm->smGetKeyState(SMK_J))rot[0]-=1; - if(sm->smGetKeyState(SMK_U))rot[2]+=1; - if(sm->smGetKeyState(SMK_O))rot[2]-=1; - } - for(int i=0;i<4;++i) - {q.v[i].col=chkrtint;q.v[i].z=(showpiano&&!horizontal)?-5:0;} - q.tex=chequer;q.blend=BLEND_ALPHABLEND; - q.v[0].x=q.v[3].x=-120;q.v[1].x=q.v[2].x=120; - q.v[0].y=q.v[1].y=-120;q.v[2].y=q.v[3].y=120; - if(horizontal) - { - for(int i=0;i<4;++i)q.v[i].x=-20; - q.v[0].y=q.v[3].y=-120;q.v[1].y=q.v[2].y=120; - q.v[0].z=q.v[1].z=-120;q.v[2].z=q.v[3].z=120; - } - q.v[0].tx=q.v[3].tx=0;q.v[1].tx=q.v[2].tx=30; - q.v[0].ty=q.v[1].ty=0;q.v[2].ty=q.v[3].ty=30; - sm->smRenderBegin3D(fov,true,tdscn); - sm->sm3DCamera6f2v(pos,rot); - sm->smClrscr(0,1,1); - sm->smRenderQuad(&q); - double lpt=(double)notestretch/api->getDivision()/10.*(horizontal?0.25:1); - memcpy(lastnotestatus,notestatus,sizeof(notestatus)); - memset(notestatus,0,sizeof(notestatus)); - for(uint32_t i=elb;itcs-ctk)*lpt>viewdist*2)break; - if(fabs((double)pool[i]->tcs-ctk)*lpttce-ctk)*lptch==999){ - smvec3d a(0.63*(-64)+.1-10,(stairpiano?(56-0*7.):(64-0*8.))+10,((double)pool[i]->tcs-ctk)*lpt-minnotelength*.005); - smvec3d b(0.63*64+.7+10,(stairpiano?(56-15*7.):(64-15*8.))+.4-10,((double)pool[i]->tcs-ctk)*lpt+minnotelength*.005); - if(horizontal){ - a=smvec3d(((double)pool[i]->tcs-ctk)*lpt-20-minnotelength*.001,(16- 0*2.)+2.4,0.63*(-64)+.1); - b=smvec3d(((double)pool[i]->tcs-ctk)*lpt-20+minnotelength*.001,(16-15*2.)+0.4,0.63*64+.7); - } - smMatrix I;I.loadIdentity(); - smEntity3D c=smEntity3D::cube(a,b,0xFF000000,horizontal?51:60); - if(stairpiano&&showpiano&&!horizontal) - { - std::vector il={2,3,6,7}; - for(size_t ti:il) - { - smVertex t=c.vertex(ti); - t.z+=30; - c.setVertex(ti,t); - } - } - if(showmeasure) - nebuf->addTransformedEntity(&c,I,smvec3d(0,0,0)); - continue; - } - if(pool[i]->ch>=990)continue; - if(api->getChannelMask(pool[i]->ch))continue; - smvec3d a(0.63*((double)pool[i]->key-64)+.1,(stairpiano?(56-pool[i]->ch*7.):(64-pool[i]->ch*8.)),((double)pool[i]->tce-ctk)*lpt+(stairpiano&&showpiano&&!horizontal)*pool[i]->ch*2.); - smvec3d b(0.63*((double)pool[i]->key-64)+.7,(stairpiano?(56-pool[i]->ch*7.):(64-pool[i]->ch*8.))+.4,((double)pool[i]->tcs-ctk)*lpt+(stairpiano&&showpiano&&!horizontal)*pool[i]->ch*2.); - bool isnoteon=pool[i]->tcs<=ctk&&pool[i]->tce>=ctk; - double pb=((int)cpw[pool[i]->ch]-8192)/8192.*cpbr[pool[i]->ch]; - if(isnoteon) - { - a.x=0.63*((double)pool[i]->key-64+pb)+.1; - b.x=0.63*((double)pool[i]->key-64+pb)+.7; - } - notestatus[pool[i]->ch][pool[i]->key]|=isnoteon;a.x*=1.2;b.x*=1.2; - if(horizontal) - { - a=smvec3d(((double)pool[i]->tcs-ctk)*lpt-20,(16-pool[i]->ch*2.),0.63*((double)pool[i]->key-64)+.1); - b=smvec3d(((double)pool[i]->tce-ctk)*lpt-20,(16-pool[i]->ch*2.)+.4,0.63*((double)pool[i]->key-64)+.7); - if(isnoteon) - { - a.z=0.63*((double)pool[i]->key-64+pb)+.1; - b.z=0.63*((double)pool[i]->key-64+pb)+.7; - } - } - if(showparticle&&!horizontal) - { - if(notestatus[pool[i]->ch][pool[i]->key]&&!lastnotestatus[pool[i]->ch][pool[i]->key]) - { - pss[pool[i]->ch][pool[i]->key]->startPS(); - pss[pool[i]->ch][pool[i]->key]->setPos(smvec3d(0.756*((double)pool[i]->key-64)+.48,(stairpiano?(56-pool[i]->ch*7.):(64-pool[i]->ch*8.)),stairpiano*pool[i]->ch*2+0.1)); - } - else pss[pool[i]->ch][pool[i]->key]->stopPS(); - } - if(((double)pool[i]->tce-pool[i]->tcs)*lpttcs-ctk)*lpt-minnotelength/400.-20; - else - a.z=((double)pool[i]->tcs-ctk)*lpt-minnotelength/100.+stairpiano*pool[i]->ch*2; - } - if(usespectrum) - { - if(notestatus[pool[i]->ch][pool[i]->key]&&!lastnotestatus[pool[i]->ch][pool[i]->key]) - spectra[pool[i]->ch][pool[i]->key]=pool[i]->vel*(api->getChannelCC(pool[i]->ch,7)/127.); - } - else - { - smColor col=smColor::fromHWColor(isnoteon?accolors[pool[i]->ch]:iccolors[pool[i]->ch]); - drawCube(a,b,col.lighter(37+pool[i]->vel/2).toHWColor(),0); - } - } - } - if(usespectrum&&playing) - for(int i=0;i<16;++i)for(int j=0;j<128;++j) - { - if(sustaininst.find(api->getChannelPreset(i))!=sustaininst.end()) - { - if(!notestatus[i][j]&&spectra[i][j]) - spectra[i][j]=.95*spectra[i][j]; - }else if(spectra[i][j])spectra[i][j]=.95*spectra[i][j]; - if(spectrar[i][j]smGetTime()*32))+(stairpiano&&showpiano&&!horizontal)*i*2.); - smvec3d b(0.756*((double)j-64+pb)+.84, - (stairpiano?(56-i*7.):(64-i*8.))+.4, - (stairpiano&&showpiano&&!horizontal)*i*2.); - drawCube(a,b,SETA(iccolors[i],204),0); - } - } - nebuf->drawBatch(); - if(showpiano&&!horizontal) - for(int i=0;i<16;++i) - { - for(int j=0;j<128;++j) - { - if(notestatus[i][j]) - if(traveld[i][j]<10)traveld[i][j]+=2;else traveld[i][j]=10; - else - if(traveld[i][j]>0)traveld[i][j]-=2;else traveld[i][j]=0; - p3d[i]->setKeyTravelDist(j,traveld[i][j]/10.); - } - double pb=((int)cpw[i]-8192)/8192.*cpbr[i]; - p3d[i]->render(smvec3d(0.756*pb,stairpiano?55-i*7:62-i*8,stairpiano*i*2)); - } - for(int i=0;i<16;++i) - if(showlabel) - { - std::string s=api->getChannelPresetString(i); - wchar_t ws[1024];mbstowcs(ws,s.c_str(),1024); - fonthdpi.updateString(ws); - fonthdpi.render(-49,stairpiano?56-i*7:63-i*8,stairpiano*i*2+0.1,0xFFFFFFFF,ALIGN_RIGHT,.008,0.01); - fonthdpi.render(-49.05,stairpiano?56.05-i*7:63.05-i*8,stairpiano*i*2+0.2,0xFF000000,ALIGN_RIGHT,.008,0.01); - } - while(pool.size()&&elbtce)*lpt>viewdist*2)++elb; - sm->smRenderEnd(); - if(showparticle&&!horizontal) - { - sm->smRenderBegin3D(fov,false,tdparticles); - sm->sm3DCamera6f2v(pos,rot); - sm->smClrscr(0,1,1); - for(int i=0;i<16;++i)for(int j=0;j<128;++j) - { - pss[i][j]->setPSLookAt(smvec3d(pos[0],pos[1],pos[2])); - pss[i][j]->updatePS();pss[i][j]->renderPS(); - } - sm->smRenderEnd(); - } + smQuad q; + if (!rendermode) + { + if (sm->smGetKeyState(SMK_D)) + pos[0] += cos(smMath::deg2rad(rot[2] - 90)), pos[1] += sin(smMath::deg2rad(rot[2] - 90)); + if (sm->smGetKeyState(SMK_A)) + pos[0] -= cos(smMath::deg2rad(rot[2] - 90)), pos[1] -= sin(smMath::deg2rad(rot[2] - 90)); + if (sm->smGetKeyState(SMK_S)) + pos[0] += cos(smMath::deg2rad(rot[2])), pos[1] += sin(smMath::deg2rad(rot[2])); + if (sm->smGetKeyState(SMK_W)) + pos[0] -= cos(smMath::deg2rad(rot[2])), pos[1] -= sin(smMath::deg2rad(rot[2])); + if (sm->smGetKeyState(SMK_Q)) + pos[2] += 1; + if (sm->smGetKeyState(SMK_E)) + pos[2] -= 1; + if (sm->smGetKeyState(SMK_R)) + { + if (horizontal) + { + pos[0] = -20; + pos[1] = 45; + pos[2] = 0; + rot[0] = 0; + rot[1] = 90; + rot[2] = 90; + } + else + { + pos[0] = 0; + pos[1] = 120; + pos[2] = 70; + rot[0] = 0; + rot[1] = 75; + rot[2] = 90; + } + } + if (sm->smGetKeyState(SMK_LBUTTON) == SMKST_HIT) + sm->smSetMouseGrab(true), sm->smGetMouse2f(&lastx, &lasty); + if (sm->smGetKeyState(SMK_LBUTTON) == SMKST_KEEP) + { + float x, y; + sm->smGetMouse2f(&x, &y); + rot[1] -= (y - lasty) * 0.01; + rot[2] += (x - lastx) * 0.01; + while (rot[1] > 360) + rot[1] -= 360; + while (rot[1] < 0) + rot[1] += 360; + while (rot[2] > 360) + rot[2] -= 360; + while (rot[2] < 0) + rot[2] += 360; + } + if (sm->smGetKeyState(SMK_LBUTTON) == SMKST_RELEASE) + { + sm->smSetMouseGrab(false); + sm->smSetMouse2f(wwidth / 2, wheight / 2); + } + if (sm->smGetKeyState(SMK_I)) + rot[1] += 1; + if (sm->smGetKeyState(SMK_K)) + rot[1] -= 1; + if (sm->smGetKeyState(SMK_L)) + rot[0] += 1; + if (sm->smGetKeyState(SMK_J)) + rot[0] -= 1; + if (sm->smGetKeyState(SMK_U)) + rot[2] += 1; + if (sm->smGetKeyState(SMK_O)) + rot[2] -= 1; + } + for (int i = 0; i < 4; ++i) + { + q.v[i].col = chkrtint; + q.v[i].z = (showpiano && !horizontal) ? -5 : 0; + } + q.tex = chequer; + q.blend = BLEND_ALPHABLEND; + q.v[0].x = q.v[3].x = -120; + q.v[1].x = q.v[2].x = 120; + q.v[0].y = q.v[1].y = -120; + q.v[2].y = q.v[3].y = 120; + if (horizontal) + { + for (int i = 0; i < 4; ++i) + q.v[i].x = -20; + q.v[0].y = q.v[3].y = -120; + q.v[1].y = q.v[2].y = 120; + q.v[0].z = q.v[1].z = -120; + q.v[2].z = q.v[3].z = 120; + } + q.v[0].tx = q.v[3].tx = 0; + q.v[1].tx = q.v[2].tx = 30; + q.v[0].ty = q.v[1].ty = 0; + q.v[2].ty = q.v[3].ty = 30; + sm->smRenderBegin3D(fov, true, tdscn); + sm->sm3DCamera6f2v(pos, rot); + sm->smClrscr(0, 1, 1); + sm->smRenderQuad(&q); + double lpt = (double)notestretch / api->getDivision() / 10.*(horizontal ? 0.25 : 1); + memcpy(lastnotestatus, notestatus, sizeof(notestatus)); + memset(notestatus, 0, sizeof(notestatus)); + for (uint32_t i = elb; i < pool.size(); ++i) + { + if (((double)pool[i]->tcs - ctk)*lpt > viewdist * 2) + break; + if (fabs((double)pool[i]->tcs - ctk)*lpt < viewdist * 2 || fabs((double)pool[i]->tce - ctk)*lpt < viewdist * 2) + { + if (pool[i]->ch == 999) + { + smvec3d a(0.63 * (-64) + .1 - 10, (stairpiano ? (56 - 0 * 7.) : (64 - 0 * 8.)) + 10, ((double)pool[i]->tcs - ctk)*lpt - minnotelength * .005); + smvec3d b(0.63 * 64 + .7 + 10, (stairpiano ? (56 - 15 * 7.) : (64 - 15 * 8.)) + .4 - 10, ((double)pool[i]->tcs - ctk)*lpt + minnotelength * .005); + if (horizontal) + { + a = smvec3d(((double)pool[i]->tcs - ctk) * lpt - 20 - minnotelength * .001, (16 - 0 * 2.) + 2.4, 0.63 * (-64) + .1); + b = smvec3d(((double)pool[i]->tcs - ctk) * lpt - 20 + minnotelength * .001, (16 - 15 * 2.) + 0.4, 0.63 * 64 + .7); + } + smMatrix I; + I.loadIdentity(); + smEntity3D c = smEntity3D::cube(a, b, 0xFF000000, horizontal ? 51 : 60); + if (stairpiano && showpiano && !horizontal) + { + std::vector il = {2, 3, 6, 7}; + for (size_t ti : il) + { + smVertex t = c.vertex(ti); + t.z += 30; + c.setVertex(ti, t); + } + } + if (showmeasure) + nebuf->addTransformedEntity(&c, I, smvec3d(0, 0, 0)); + continue; + } + if (pool[i]->ch >= 990) + continue; + if (api->getChannelMask(pool[i]->ch)) + continue; + smvec3d a(0.63 * ((double)pool[i]->key - 64) + .1, (stairpiano ? (56 - pool[i]->ch * 7.) : (64 - pool[i]->ch * 8.)), ((double)pool[i]->tce - ctk)*lpt + (stairpiano && showpiano && !horizontal)*pool[i]->ch * 2.); + smvec3d b(0.63 * ((double)pool[i]->key - 64) + .7, (stairpiano ? (56 - pool[i]->ch * 7.) : (64 - pool[i]->ch * 8.)) + .4, ((double)pool[i]->tcs - ctk)*lpt + (stairpiano && showpiano && !horizontal)*pool[i]->ch * 2.); + bool isnoteon = pool[i]->tcs <= ctk && pool[i]->tce >= ctk; + double pb = ((int)cpw[pool[i]->ch] - 8192) / 8192.*cpbr[pool[i]->ch]; + if (isnoteon) + { + a.x = 0.63 * ((double)pool[i]->key - 64 + pb) + .1; + b.x = 0.63 * ((double)pool[i]->key - 64 + pb) + .7; + } + notestatus[pool[i]->ch][pool[i]->key] |= isnoteon; + a.x *= 1.2; + b.x *= 1.2; + if (horizontal) + { + a = smvec3d(((double)pool[i]->tcs - ctk) * lpt - 20, (16 - pool[i]->ch * 2.), 0.63 * ((double)pool[i]->key - 64) + .1); + b = smvec3d(((double)pool[i]->tce - ctk) * lpt - 20, (16 - pool[i]->ch * 2.) + .4, 0.63 * ((double)pool[i]->key - 64) + .7); + if (isnoteon) + { + a.z = 0.63 * ((double)pool[i]->key - 64 + pb) + .1; + b.z = 0.63 * ((double)pool[i]->key - 64 + pb) + .7; + } + } + if (showparticle && !horizontal) + { + if (notestatus[pool[i]->ch][pool[i]->key] && !lastnotestatus[pool[i]->ch][pool[i]->key]) + { + pss[pool[i]->ch][pool[i]->key]->startPS(); + pss[pool[i]->ch][pool[i]->key]->setPos(smvec3d(0.756 * ((double)pool[i]->key - 64) + .48, (stairpiano ? (56 - pool[i]->ch * 7.) : (64 - pool[i]->ch * 8.)), stairpiano * pool[i]->ch * 2 + 0.1)); + } + else pss[pool[i]->ch][pool[i]->key]->stopPS(); + } + if (((double)pool[i]->tce - pool[i]->tcs)*lpt < minnotelength * (horizontal ? 0.0025 : 0.01)) + { + if (horizontal) + a.x = ((double)pool[i]->tcs - ctk) * lpt - minnotelength / 400. - 20; + else + a.z = ((double)pool[i]->tcs - ctk) * lpt - minnotelength / 100. + stairpiano * pool[i]->ch * 2; + } + if (usespectrum) + { + if (notestatus[pool[i]->ch][pool[i]->key] && !lastnotestatus[pool[i]->ch][pool[i]->key]) + spectra[pool[i]->ch][pool[i]->key] = pool[i]->vel * (api->getChannelCC(pool[i]->ch, 7) / 127.); + } + else + { + smColor col = smColor::fromHWColor(isnoteon ? accolors[pool[i]->ch] : iccolors[pool[i]->ch]); + drawCube(a, b, col.lighter(37 + pool[i]->vel / 2).toHWColor(), 0); + } + } + } + if (usespectrum && playing) + for (int i = 0; i < 16; ++i) + for (int j = 0; j < 128; ++j) + { + if (sustaininst.find(api->getChannelPreset(i)) != sustaininst.end()) + { + if (!notestatus[i][j] && spectra[i][j]) + spectra[i][j] = .95 * spectra[i][j]; + } + else if (spectra[i][j]) + spectra[i][j] = .95 * spectra[i][j]; + if (spectrar[i][j] < spectra[i][j] * 0.9) + spectrar[i][j] += spectra[i][j] * 0.2; + else spectrar[i][j] = spectra[i][j]; + if (spectrar[i][j]) + { + double pb = ((int)cpw[i] - 8192) / 8192.*cpbr[i]; + smvec3d a(0.756 * ((double)j - 64 + pb) + .12, + (stairpiano ? (56 - i * 7.) : (64 - i * 8.)), + spectrar[i][j] * 1.2 * (1 + 0.02 * sin(sm->smGetTime() * 32)) + (stairpiano && showpiano && !horizontal)*i * 2.); + smvec3d b(0.756 * ((double)j - 64 + pb) + .84, + (stairpiano ? (56 - i * 7.) : (64 - i * 8.)) + .4, + (stairpiano && showpiano && !horizontal)*i * 2.); + drawCube(a, b, SETA(iccolors[i], 204), 0); + } + } + nebuf->drawBatch(); + if (showpiano && !horizontal) + for (int i = 0; i < 16; ++i) + { + for (int j = 0; j < 128; ++j) + { + if (notestatus[i][j]) + if (traveld[i][j] < 10) + traveld[i][j] += 2; + else traveld[i][j] = 10; + else if (traveld[i][j] > 0) + traveld[i][j] -= 2; + else traveld[i][j] = 0; + p3d[i]->setKeyTravelDist(j, traveld[i][j] / 10.); + } + double pb = ((int)cpw[i] - 8192) / 8192.*cpbr[i]; + p3d[i]->render(smvec3d(0.756 * pb, stairpiano ? 55 - i * 7 : 62 - i * 8, stairpiano * i * 2)); + } + for (int i = 0; i < 16; ++i) + if (showlabel) + { + std::string s = api->getChannelPresetString(i); + wchar_t ws[1024]; + mbstowcs(ws, s.c_str(), 1024); + fonthdpi.updateString(ws); + fonthdpi.render(-49, stairpiano ? 56 - i * 7 : 63 - i * 8, stairpiano * i * 2 + 0.1, 0xFFFFFFFF, ALIGN_RIGHT, .008, 0.01); + fonthdpi.render(-49.05, stairpiano ? 56.05 - i * 7 : 63.05 - i * 8, stairpiano * i * 2 + 0.2, 0xFF000000, ALIGN_RIGHT, .008, 0.01); + } + while (pool.size() && elb < pool.size() && ((double)ctk - pool[elb]->tce)*lpt > viewdist * 2)++elb; + sm->smRenderEnd(); + if (showparticle && !horizontal) + { + sm->smRenderBegin3D(fov, false, tdparticles); + sm->sm3DCamera6f2v(pos, rot); + sm->smClrscr(0, 1, 1); + for (int i = 0; i < 16; ++i) + for (int j = 0; j < 128; ++j) + { + pss[i][j]->setPSLookAt(smvec3d(pos[0], pos[1], pos[2])); + pss[i][j]->updatePS(); + pss[i][j]->renderPS(); + } + sm->smRenderEnd(); + } } void qmpVisualization::updateVisualization2D() { - double lpt=-(double)notestretch/api->getDivision()/2.; - memset(notestatus,0,sizeof(notestatus)); - double notew=wwidth/128,nh=showpiano?wwidth/2048.*172.:0; - if(horizontal){notew=wheight/128;nh=showpiano?wheight/2048.*172.:0;lpt=-lpt;} - smQuad nq;nq.blend=BLEND_ALPHABLEND;nq.tex=0; - for(int i=0;i<4;++i)nq.v[i].z=0,nq.v[i].tx=nq.v[i].ty=0; - for(uint32_t i=elb;itcs-ctk)*lpt+wheight-nh<0; - bool lowerbound=fabs((double)pool[i]->tce-ctk)*lpt+wheight-nhtcs-ctk)*lpt+nh>wwidth; - lowerbound=fabs((double)pool[i]->tce-ctk)*lpt+nh>0; - } - if(upperbound)break; - if(!upperbound||lowerbound) - { - if(pool[i]->ch==999){ - smvec2d a(0,((double)pool[i]->tcs-ctk)*lpt+wheight-nh-minnotelength*0.02); - smvec2d b(wwidth,((double)pool[i]->tcs-ctk)*lpt+wheight-nh); - if(horizontal) - { - a=smvec2d(((double)pool[i]->tcs-ctk)*lpt+nh-minnotelength*0.02,0); - b=smvec2d(((double)pool[i]->tcs-ctk)*lpt+nh,wheight); - } - nq.v[0].x=nq.v[3].x=a.x;nq.v[0].y=nq.v[1].y=a.y; - nq.v[1].x=nq.v[2].x=b.x;nq.v[2].y=nq.v[3].y=b.y; - for(int j=0;j<4;++j)nq.v[j].col=0xC0000000; - if(showmeasure)sm->smRenderQuad(&nq); - continue; - } - if(pool[i]->ch>=990)continue; - if(api->getChannelMask(pool[i]->ch))continue; - smvec2d a((froffsets[12]*(pool[i]->key/12)+froffsets[pool[i]->key%12])*wwidth/2048.,((double)pool[i]->tce-ctk)*lpt+wheight-nh); - smvec2d b(a.x+notew*0.9,((double)pool[i]->tcs-ctk)*lpt+wheight-nh); - if(horizontal) - { - a=smvec2d(((double)pool[i]->tce-ctk)*lpt+nh,(froffsets[12]*(pool[i]->key/12)+froffsets[pool[i]->key%12])*wheight/2048.); - b=smvec2d(((double)pool[i]->tcs-ctk)*lpt+nh,a.y+notew*0.9); - } - bool isnoteon=pool[i]->tcs<=ctk&&pool[i]->tce>=ctk; - if(isnoteon) - { - double pb=((int)cpw[pool[i]->ch]-8192)/8192.*cpbr[pool[i]->ch]; - uint32_t newkey=pool[i]->key+(int)floor(pb); - double fpb=pb-floor(pb); - if(horizontal) - { - a.y=(froffsets[12]*(newkey/12)+froffsets[newkey%12])*wheight/2048.+notew*fpb; - b.y=a.y+notew*0.9; - } - else - { - a.x=(froffsets[12]*(newkey/12)+froffsets[newkey%12])*wwidth/2048.+notew*fpb; - b.x=a.x+notew*0.9; - } - } - if(horizontal)a.y=wheight-a.y,b.y=wheight-b.y; - notestatus[pool[i]->ch][pool[i]->key]|=isnoteon; - if(horizontal) - { - if(((double)pool[i]->tce-pool[i]->tcs)*lpttcs-ctk)*lpt+nh-minnotelength*0.04; - } - else - { - if(((double)pool[i]->tcs-pool[i]->tce)*lpttcs-ctk)*lpt+wheight-nh-minnotelength*0.04; - } - nq.v[0].x=nq.v[3].x=a.x;nq.v[0].y=nq.v[1].y=a.y; - nq.v[1].x=nq.v[2].x=b.x;nq.v[2].y=nq.v[3].y=b.y; - for(int j=0;j<4;++j) - nq.v[j].col=SETA(isnoteon?accolors[pool[i]->ch]:iccolors[pool[i]->ch],int(pool[i]->vel*1.6+(isnoteon?52:32))); - if(usespectrum) - { - if(notestatus[pool[i]->ch][pool[i]->key]&&!lastnotestatus[pool[i]->ch][pool[i]->key]) - spectra[pool[i]->ch][pool[i]->key]=pool[i]->vel*(api->getChannelCC(pool[i]->ch,7)/127.); - }else sm->smRenderQuad(&nq); - } - } - if(horizontal) - while(pool.size()&&elbtce-ctk)*lpt+nh<0)++elb; - else - while(pool.size()&&elbtce-ctk)*lpt+wheight-nh>wheight)++elb; - smQuad q; - q.tex=pianotex;q.blend=BLEND_ALPHABLEND; - for(int i=0;i<4;++i)q.v[i].col=0xFFFFFFFF,q.v[i].z=0; - q.v[0].ty=q.v[3].ty=0;q.v[1].ty=q.v[2].ty=172./256.; - q.v[0].tx=q.v[1].tx=0;q.v[2].tx=q.v[3].tx=1.; - q.v[0].x=q.v[1].x=0;q.v[2].x=q.v[3].x=wwidth; - q.v[0].y=q.v[3].y=wheight-nh;q.v[1].y=q.v[2].y=wheight; - if(horizontal) - { - q.v[0].tx=q.v[3].tx=0;q.v[1].tx=q.v[2].tx=1; - q.v[0].ty=q.v[1].ty=0;q.v[2].ty=q.v[3].ty=172./256.; - q.v[0].x=q.v[1].x=nh;q.v[2].x=q.v[3].x=0; - q.v[0].y=q.v[3].y=wheight;q.v[1].y=q.v[2].y=0; - } - sm->smRenderQuad(&q); - for(int i=0,j;i<128;++i) - { - DWORD c=0;for(j=0;j<16;++j)if(notestatus[j][i]){c=SETA(iccolors[j],0xFF);break;} - if(horizontal) - { - q.v[0].y=q.v[1].y=(fpoffsets[12]*(i/12)+fpoffsets[i%12])*wheight/2048.; - q.v[2].y=q.v[3].y=q.v[0].y; - q.v[0].x=q.v[3].x=nh;q.v[1].x=q.v[2].x=0; - } - else - { - q.v[0].x=q.v[1].x=(fpoffsets[12]*(i/12)+fpoffsets[i%12])*wwidth/2048.; - q.v[2].x=q.v[3].x=q.v[0].x; - q.v[0].y=q.v[3].y=wheight-nh;q.v[1].y=q.v[2].y=wheight; - } - if(!c)continue;for(int j=0;j<4;++j)q.v[j].col=c; - switch(i%12) - { - case 1:case 3:case 6:case 8:case 10: - if(horizontal) - { - q.v[1].x=q.v[2].x=nh-115*wheight/2048.; - q.v[2].y+=15.*wheight/2048;q.v[3].y+=15.*wheight/2048; - } - else - { - q.v[1].y=q.v[2].y=wheight-nh+115*wwidth/2048.; - q.v[2].x+=15.*wwidth/2048;q.v[3].x+=15.*wwidth/2048; - } - q.v[0].ty=q.v[1].ty=1.;q.v[2].ty=q.v[3].ty=1.-15/256.; - q.v[0].tx=q.v[3].tx=1344/2048.;q.v[1].tx=q.v[2].tx=1459/2048.; - break; - case 0: - if(horizontal) - {q.v[2].y+=27.*wheight/2048;q.v[3].y+=27.*wheight/2048;} - else - {q.v[2].x+=27.*wwidth/2048;q.v[3].x+=27.*wwidth/2048;} - q.v[0].ty=q.v[1].ty=1.;q.v[2].ty=q.v[3].ty=1.-27/256.; - q.v[0].tx=q.v[3].tx=0/2048.;q.v[1].tx=q.v[2].tx=172/2048.; - break; - case 2: - if(horizontal) - {q.v[2].y+=29.*wheight/2048;q.v[3].y+=29.*wheight/2048;} - else - {q.v[2].x+=29.*wwidth/2048;q.v[3].x+=29.*wwidth/2048;} - q.v[0].ty=q.v[1].ty=1.;q.v[2].ty=q.v[3].ty=1.-29/256.; - q.v[0].tx=q.v[3].tx=192/2048.;q.v[1].tx=q.v[2].tx=364/2048.; - break; - case 4: - if(horizontal) - {q.v[2].y+=28.*wheight/2048;q.v[3].y+=28.*wheight/2048;} - else - {q.v[2].x+=28.*wwidth/2048;q.v[3].x+=28.*wwidth/2048;} - q.v[0].ty=q.v[1].ty=1.;q.v[2].ty=q.v[3].ty=1.-28/256.; - q.v[0].tx=q.v[3].tx=384/2048.;q.v[1].tx=q.v[2].tx=556/2048.; - break; - case 5: - if(horizontal) - {q.v[2].y+=28.*wheight/2048;q.v[3].y+=28.*wheight/2048;} - else - {q.v[2].x+=28.*wwidth/2048;q.v[3].x+=28.*wwidth/2048;} - q.v[0].ty=q.v[1].ty=1.;q.v[2].ty=q.v[3].ty=1.-28/256.; - q.v[0].tx=q.v[3].tx=576/2048.;q.v[1].tx=q.v[2].tx=748/2048.; - break; - case 7: - if(horizontal) - {q.v[2].y+=29.*wheight/2048;q.v[3].y+=29.*wheight/2048;} - else - {q.v[2].x+=29.*wwidth/2048;q.v[3].x+=29.*wwidth/2048;} - q.v[0].ty=q.v[1].ty=1.;q.v[2].ty=q.v[3].ty=1.-29/256.; - q.v[0].tx=q.v[3].tx=768/2048.;q.v[1].tx=q.v[2].tx=940/2048.; - break; - case 9: - if(horizontal) - {q.v[2].y+=28.*wheight/2048;q.v[3].y+=28.*wheight/2048;} - else - {q.v[2].x+=28.*wwidth/2048;q.v[3].x+=28.*wwidth/2048;} - q.v[0].ty=q.v[1].ty=1.;q.v[2].ty=q.v[3].ty=1.-28/256.; - q.v[0].tx=q.v[3].tx=960/2048.;q.v[1].tx=q.v[2].tx=1132/2048.; - break; - case 11: - if(horizontal) - {q.v[2].y+=28.*wheight/2048;q.v[3].y+=28.*wheight/2048;} - else - {q.v[2].x+=28.*wwidth/2048;q.v[3].x+=28.*wwidth/2048;} - q.v[0].ty=q.v[1].ty=1.;q.v[2].ty=q.v[3].ty=1.-28/256.; - q.v[0].tx=q.v[3].tx=1152/2048.;q.v[1].tx=q.v[2].tx=1324/2048.; - break; - } - if(horizontal)for(int j=0;j<4;++j)q.v[j].y=wheight-q.v[j].y; - sm->smRenderQuad(&q); - } - if(usespectrum&&playing) - for(int i=0;i<16;++i)for(int j=0;j<128;++j) - { - if(sustaininst.find(api->getChannelPreset(i))!=sustaininst.end()) - { - if(!notestatus[i][j]&&spectra[i][j]) - spectra[i][j]=.95*spectra[i][j]; - }else if(spectra[i][j])spectra[i][j]=.95*spectra[i][j]; - if(spectrar[i][j]smGetTime()*32))+wheight-nh); - smvec2d b(a.x+notew*0.9,lpt+wheight-nh); - double pb=((int)cpw[i]-8192)/8192.*cpbr[i]; - uint32_t newkey=j+(int)floor(pb); - double fpb=pb-floor(pb); - if(horizontal) - { - a=smvec2d(spectrar[i][j]/128.*(wwidth-nh)*(1+0.02*sin(sm->smGetTime()*32))+nh,(froffsets[12]*(j/12)+froffsets[j%12])*wheight/2048.); - b=smvec2d(nh,a.y+notew*0.9); - a.y=(froffsets[12]*(newkey/12)+froffsets[newkey%12])*wheight/2048.+notew*fpb; - b.y=a.y+notew*0.9; - a.y=wheight-a.y;b.y=wheight-b.y; - } - else - { - a.x=(froffsets[12]*(newkey/12)+froffsets[newkey%12])*wwidth/2048.+notew*fpb; - b.x=a.x+notew*0.9; - } - nq.v[0].x=nq.v[3].x=a.x;nq.v[0].y=nq.v[1].y=a.y; - nq.v[1].x=nq.v[2].x=b.x;nq.v[2].y=nq.v[3].y=b.y;for(int j=0;j<4;++j) - nq.v[j].col=SETA(iccolors[i],204); - sm->smRenderQuad(&nq); - } - } + double lpt = -(double)notestretch / api->getDivision() / 2.; + memset(notestatus, 0, sizeof(notestatus)); + double notew = wwidth / 128, nh = showpiano ? wwidth / 2048.*172. : 0; + if (horizontal) + { + notew = wheight / 128; + nh = showpiano ? wheight / 2048.*172. : 0; + lpt = -lpt; + } + smQuad nq; + nq.blend = BLEND_ALPHABLEND; + nq.tex = 0; + for (int i = 0; i < 4; ++i) + nq.v[i].z = 0, nq.v[i].tx = nq.v[i].ty = 0; + for (uint32_t i = elb; i < pool.size(); ++i) + { + bool upperbound = ((double)pool[i]->tcs - ctk) * lpt + wheight - nh < 0; + bool lowerbound = fabs((double)pool[i]->tce - ctk) * lpt + wheight - nh < wheight; + if (horizontal) + { + upperbound = ((double)pool[i]->tcs - ctk) * lpt + nh > wwidth; + lowerbound = fabs((double)pool[i]->tce - ctk) * lpt + nh > 0; + } + if (upperbound) + break; + if (!upperbound || lowerbound) + { + if (pool[i]->ch == 999) + { + smvec2d a(0, ((double)pool[i]->tcs - ctk)*lpt + wheight - nh - minnotelength * 0.02); + smvec2d b(wwidth, ((double)pool[i]->tcs - ctk)*lpt + wheight - nh); + if (horizontal) + { + a = smvec2d(((double)pool[i]->tcs - ctk) * lpt + nh - minnotelength * 0.02, 0); + b = smvec2d(((double)pool[i]->tcs - ctk) * lpt + nh, wheight); + } + nq.v[0].x = nq.v[3].x = a.x; + nq.v[0].y = nq.v[1].y = a.y; + nq.v[1].x = nq.v[2].x = b.x; + nq.v[2].y = nq.v[3].y = b.y; + for (int j = 0; j < 4; ++j) + nq.v[j].col = 0xC0000000; + if (showmeasure) + sm->smRenderQuad(&nq); + continue; + } + if (pool[i]->ch >= 990) + continue; + if (api->getChannelMask(pool[i]->ch)) + continue; + smvec2d a((froffsets[12] * (pool[i]->key / 12) + froffsets[pool[i]->key % 12])*wwidth / 2048., ((double)pool[i]->tce - ctk)*lpt + wheight - nh); + smvec2d b(a.x + notew * 0.9, ((double)pool[i]->tcs - ctk)*lpt + wheight - nh); + if (horizontal) + { + a = smvec2d(((double)pool[i]->tce - ctk) * lpt + nh, (froffsets[12] * (pool[i]->key / 12) + froffsets[pool[i]->key % 12]) * wheight / 2048.); + b = smvec2d(((double)pool[i]->tcs - ctk) * lpt + nh, a.y + notew * 0.9); + } + bool isnoteon = pool[i]->tcs <= ctk && pool[i]->tce >= ctk; + if (isnoteon) + { + double pb = ((int)cpw[pool[i]->ch] - 8192) / 8192.*cpbr[pool[i]->ch]; + uint32_t newkey = pool[i]->key + (int)floor(pb); + double fpb = pb - floor(pb); + if (horizontal) + { + a.y = (froffsets[12] * (newkey / 12) + froffsets[newkey % 12]) * wheight / 2048. + notew * fpb; + b.y = a.y + notew * 0.9; + } + else + { + a.x = (froffsets[12] * (newkey / 12) + froffsets[newkey % 12]) * wwidth / 2048. + notew * fpb; + b.x = a.x + notew * 0.9; + } + } + if (horizontal) + a.y = wheight - a.y, b.y = wheight - b.y; + notestatus[pool[i]->ch][pool[i]->key] |= isnoteon; + if (horizontal) + { + if (((double)pool[i]->tce - pool[i]->tcs)*lpt < minnotelength * 0.04) + a.x = ((double)pool[i]->tcs - ctk) * lpt + nh - minnotelength * 0.04; + } + else + { + if (((double)pool[i]->tcs - pool[i]->tce)*lpt < minnotelength * 0.04) + a.y = ((double)pool[i]->tcs - ctk) * lpt + wheight - nh - minnotelength * 0.04; + } + nq.v[0].x = nq.v[3].x = a.x; + nq.v[0].y = nq.v[1].y = a.y; + nq.v[1].x = nq.v[2].x = b.x; + nq.v[2].y = nq.v[3].y = b.y; + for (int j = 0; j < 4; ++j) + nq.v[j].col = SETA(isnoteon ? accolors[pool[i]->ch] : iccolors[pool[i]->ch], int(pool[i]->vel * 1.6 + (isnoteon ? 52 : 32))); + if (usespectrum) + { + if (notestatus[pool[i]->ch][pool[i]->key] && !lastnotestatus[pool[i]->ch][pool[i]->key]) + spectra[pool[i]->ch][pool[i]->key] = pool[i]->vel * (api->getChannelCC(pool[i]->ch, 7) / 127.); + } + else sm->smRenderQuad(&nq); + } + } + if (horizontal) + while (pool.size() && elb < pool.size() && fabs((double)pool[elb]->tce - ctk)*lpt + nh < 0)++elb; + else + while (pool.size() && elb < pool.size() && fabs((double)pool[elb]->tce - ctk)*lpt + wheight - nh > wheight)++elb; + smQuad q; + q.tex = pianotex; + q.blend = BLEND_ALPHABLEND; + for (int i = 0; i < 4; ++i) + q.v[i].col = 0xFFFFFFFF, q.v[i].z = 0; + q.v[0].ty = q.v[3].ty = 0; + q.v[1].ty = q.v[2].ty = 172. / 256.; + q.v[0].tx = q.v[1].tx = 0; + q.v[2].tx = q.v[3].tx = 1.; + q.v[0].x = q.v[1].x = 0; + q.v[2].x = q.v[3].x = wwidth; + q.v[0].y = q.v[3].y = wheight - nh; + q.v[1].y = q.v[2].y = wheight; + if (horizontal) + { + q.v[0].tx = q.v[3].tx = 0; + q.v[1].tx = q.v[2].tx = 1; + q.v[0].ty = q.v[1].ty = 0; + q.v[2].ty = q.v[3].ty = 172. / 256.; + q.v[0].x = q.v[1].x = nh; + q.v[2].x = q.v[3].x = 0; + q.v[0].y = q.v[3].y = wheight; + q.v[1].y = q.v[2].y = 0; + } + sm->smRenderQuad(&q); + for (int i = 0, j; i < 128; ++i) + { + DWORD c = 0; + for (j = 0; j < 16; ++j) + if (notestatus[j][i]) + { + c = SETA(iccolors[j], 0xFF); + break; + } + if (horizontal) + { + q.v[0].y = q.v[1].y = (fpoffsets[12] * (i / 12) + fpoffsets[i % 12]) * wheight / 2048.; + q.v[2].y = q.v[3].y = q.v[0].y; + q.v[0].x = q.v[3].x = nh; + q.v[1].x = q.v[2].x = 0; + } + else + { + q.v[0].x = q.v[1].x = (fpoffsets[12] * (i / 12) + fpoffsets[i % 12]) * wwidth / 2048.; + q.v[2].x = q.v[3].x = q.v[0].x; + q.v[0].y = q.v[3].y = wheight - nh; + q.v[1].y = q.v[2].y = wheight; + } + if (!c) + continue; + for (int j = 0; j < 4; ++j) + q.v[j].col = c; + switch (i % 12) + { + case 1: + case 3: + case 6: + case 8: + case 10: + if (horizontal) + { + q.v[1].x = q.v[2].x = nh - 115 * wheight / 2048.; + q.v[2].y += 15.*wheight / 2048; + q.v[3].y += 15.*wheight / 2048; + } + else + { + q.v[1].y = q.v[2].y = wheight - nh + 115 * wwidth / 2048.; + q.v[2].x += 15.*wwidth / 2048; + q.v[3].x += 15.*wwidth / 2048; + } + q.v[0].ty = q.v[1].ty = 1.; + q.v[2].ty = q.v[3].ty = 1. - 15 / 256.; + q.v[0].tx = q.v[3].tx = 1344 / 2048.; + q.v[1].tx = q.v[2].tx = 1459 / 2048.; + break; + case 0: + if (horizontal) + { + q.v[2].y += 27.*wheight / 2048; + q.v[3].y += 27.*wheight / 2048; + } + else + { + q.v[2].x += 27.*wwidth / 2048; + q.v[3].x += 27.*wwidth / 2048; + } + q.v[0].ty = q.v[1].ty = 1.; + q.v[2].ty = q.v[3].ty = 1. - 27 / 256.; + q.v[0].tx = q.v[3].tx = 0 / 2048.; + q.v[1].tx = q.v[2].tx = 172 / 2048.; + break; + case 2: + if (horizontal) + { + q.v[2].y += 29.*wheight / 2048; + q.v[3].y += 29.*wheight / 2048; + } + else + { + q.v[2].x += 29.*wwidth / 2048; + q.v[3].x += 29.*wwidth / 2048; + } + q.v[0].ty = q.v[1].ty = 1.; + q.v[2].ty = q.v[3].ty = 1. - 29 / 256.; + q.v[0].tx = q.v[3].tx = 192 / 2048.; + q.v[1].tx = q.v[2].tx = 364 / 2048.; + break; + case 4: + if (horizontal) + { + q.v[2].y += 28.*wheight / 2048; + q.v[3].y += 28.*wheight / 2048; + } + else + { + q.v[2].x += 28.*wwidth / 2048; + q.v[3].x += 28.*wwidth / 2048; + } + q.v[0].ty = q.v[1].ty = 1.; + q.v[2].ty = q.v[3].ty = 1. - 28 / 256.; + q.v[0].tx = q.v[3].tx = 384 / 2048.; + q.v[1].tx = q.v[2].tx = 556 / 2048.; + break; + case 5: + if (horizontal) + { + q.v[2].y += 28.*wheight / 2048; + q.v[3].y += 28.*wheight / 2048; + } + else + { + q.v[2].x += 28.*wwidth / 2048; + q.v[3].x += 28.*wwidth / 2048; + } + q.v[0].ty = q.v[1].ty = 1.; + q.v[2].ty = q.v[3].ty = 1. - 28 / 256.; + q.v[0].tx = q.v[3].tx = 576 / 2048.; + q.v[1].tx = q.v[2].tx = 748 / 2048.; + break; + case 7: + if (horizontal) + { + q.v[2].y += 29.*wheight / 2048; + q.v[3].y += 29.*wheight / 2048; + } + else + { + q.v[2].x += 29.*wwidth / 2048; + q.v[3].x += 29.*wwidth / 2048; + } + q.v[0].ty = q.v[1].ty = 1.; + q.v[2].ty = q.v[3].ty = 1. - 29 / 256.; + q.v[0].tx = q.v[3].tx = 768 / 2048.; + q.v[1].tx = q.v[2].tx = 940 / 2048.; + break; + case 9: + if (horizontal) + { + q.v[2].y += 28.*wheight / 2048; + q.v[3].y += 28.*wheight / 2048; + } + else + { + q.v[2].x += 28.*wwidth / 2048; + q.v[3].x += 28.*wwidth / 2048; + } + q.v[0].ty = q.v[1].ty = 1.; + q.v[2].ty = q.v[3].ty = 1. - 28 / 256.; + q.v[0].tx = q.v[3].tx = 960 / 2048.; + q.v[1].tx = q.v[2].tx = 1132 / 2048.; + break; + case 11: + if (horizontal) + { + q.v[2].y += 28.*wheight / 2048; + q.v[3].y += 28.*wheight / 2048; + } + else + { + q.v[2].x += 28.*wwidth / 2048; + q.v[3].x += 28.*wwidth / 2048; + } + q.v[0].ty = q.v[1].ty = 1.; + q.v[2].ty = q.v[3].ty = 1. - 28 / 256.; + q.v[0].tx = q.v[3].tx = 1152 / 2048.; + q.v[1].tx = q.v[2].tx = 1324 / 2048.; + break; + } + if (horizontal) + for (int j = 0; j < 4; ++j) + q.v[j].y = wheight - q.v[j].y; + sm->smRenderQuad(&q); + } + if (usespectrum && playing) + for (int i = 0; i < 16; ++i) + for (int j = 0; j < 128; ++j) + { + if (sustaininst.find(api->getChannelPreset(i)) != sustaininst.end()) + { + if (!notestatus[i][j] && spectra[i][j]) + spectra[i][j] = .95 * spectra[i][j]; + } + else if (spectra[i][j]) + spectra[i][j] = .95 * spectra[i][j]; + if (spectrar[i][j] < spectra[i][j] * 0.9) + spectrar[i][j] += spectra[i][j] * 0.2; + else spectrar[i][j] = spectra[i][j]; + if (spectrar[i][j]) + { + smvec2d a((froffsets[12] * (j / 12) + froffsets[j % 12])*wwidth / 2048., spectrar[i][j] / -128.*(wheight - nh) * (1 + 0.02 * sin(sm->smGetTime() * 32)) + wheight - nh); + smvec2d b(a.x + notew * 0.9, lpt + wheight - nh); + double pb = ((int)cpw[i] - 8192) / 8192.*cpbr[i]; + uint32_t newkey = j + (int)floor(pb); + double fpb = pb - floor(pb); + if (horizontal) + { + a = smvec2d(spectrar[i][j] / 128.*(wwidth - nh) * (1 + 0.02 * sin(sm->smGetTime() * 32)) + nh, (froffsets[12] * (j / 12) + froffsets[j % 12]) * wheight / 2048.); + b = smvec2d(nh, a.y + notew * 0.9); + a.y = (froffsets[12] * (newkey / 12) + froffsets[newkey % 12]) * wheight / 2048. + notew * fpb; + b.y = a.y + notew * 0.9; + a.y = wheight - a.y; + b.y = wheight - b.y; + } + else + { + a.x = (froffsets[12] * (newkey / 12) + froffsets[newkey % 12]) * wwidth / 2048. + notew * fpb; + b.x = a.x + notew * 0.9; + } + nq.v[0].x = nq.v[3].x = a.x; + nq.v[0].y = nq.v[1].y = a.y; + nq.v[1].x = nq.v[2].x = b.x; + nq.v[2].y = nq.v[3].y = b.y; + for (int j = 0; j < 4; ++j) + nq.v[j].col = SETA(iccolors[i], 204); + sm->smRenderQuad(&nq); + } + } } bool qmpVisualization::update() { - smQuad q; - if(!rendermode) - { - if(sm->smGetKeyState(SMK_RIGHT)==SMKST_HIT) - api->playerSeek(api->getCurrentPlaybackPercentage()+(sm->smGetKeyState(SMK_SHIFT)?5:1)); - if(sm->smGetKeyState(SMK_LEFT)==SMKST_HIT) - api->playerSeek(api->getCurrentPlaybackPercentage()-(sm->smGetKeyState(SMK_SHIFT)?5:1)); - if(sm->smGetKeyState(SMK_B)==SMKST_HIT) - debug^=1; - } - if(playing) - { - if(rendermode) - { - ctk=1e6*(cfr)/tfps/ctp*api->getDivision()+lstk; - ++cfr; - } - else - ctk=lstk+std::chrono::duration_cast>(std::chrono::steady_clock::now()-lst).count()/api->getRawTempo()*api->getDivision(); - } - if(!flat) - updateVisualization3D(); - sm->smRenderBegin2D(); - sm->smClrscr(0xFF666666);q.blend=BLEND_ALPHABLEND; - for(int i=0;i<4;++i){q.v[i].col=0xFFFFFFFF;q.v[i].z=0;} - if(bgtex) - { - q.tex=bgtex; - q.v[0].x=q.v[3].x=0;q.v[1].x=q.v[2].x=wwidth; - q.v[0].y=q.v[1].y=0;q.v[2].y=q.v[3].y=wheight; - q.v[0].tx=q.v[3].tx=0;q.v[1].tx=q.v[2].tx=1; - q.v[0].ty=q.v[1].ty=0;q.v[2].ty=q.v[3].ty=1; - sm->smRenderQuad(&q); - } - if(flat) - updateVisualization2D(); - else - { - q.tex=sm->smTargetTexture(tdscn); - q.v[0].tx=q.v[3].tx=0;q.v[1].tx=q.v[2].tx=1; - q.v[0].ty=q.v[1].ty=0;q.v[2].ty=q.v[3].ty=1; - q.v[0].x=q.v[1].x=0;q.v[2].x=q.v[3].x=wwidth; - q.v[0].y=q.v[3].y=0;q.v[1].y=q.v[2].y=wheight; - sm->smRenderQuad(&q); - if(showparticle&&!horizontal) - { - q.tex=sm->smTargetTexture(tdparticles); - sm->smRenderQuad(&q); - } - } - if(osdpos==4){sm->smRenderEnd();return shouldclose;} - uint32_t ltpc=~0u; - for(uint32_t i=elb;itcs>ctk)break; - if(pool[i]->ch==998)cts=pool[i]->key; - if(pool[i]->ch==997)cks=pool[i]->key; - if(pool[i]->ch==996) - ltpc=i; - if(pool[i]->ch==995)cpbr[pool[i]->vel]=pool[i]->key; - if(pool[i]->ch==994)cpw[pool[i]->vel]=pool[i]->key; - } - if(~ltpc&&ctp!=pool[ltpc]->key) - { - ctp=pool[ltpc]->key; - if(rendermode) - { - lstk=pool[ltpc]->tcs; - cfr=1; - } - } - int t,r;t=cks;r=(int8_t)((t>>8)&0xFF)+7;t&=0xFF; - std::wstring ts(t?minors:majors,2*r,2); - int step=int(1.33*fontsize); - int xp=(osdpos&1)?wwidth-step-1:1; - int yp=osdpos<2?wheight-step*5-4:step+4; - int align=osdpos&1?ALIGN_RIGHT:ALIGN_LEFT; - font2.updateString(L"Title: %ls",api->getWTitle().c_str()); - font2.render(xp,yp,0.5,0xFFFFFFFF,align); - font2.render(xp-1,yp-1,0.5,0xFF000000,align); - font.updateString(L"Time Sig: %d/%d",cts>>8,1<<(cts&0xFF)); - font.render(xp,yp+=step,0.5,0xFFFFFFFF,align); - font.render(xp-1,yp-1,0.5,0xFF000000,align); - font.updateString(L"Key Sig: %ls",ts.c_str()); - font.render(xp,yp+=step,0.5,0xFFFFFFFF,align); - font.render(xp-1,yp-1,0.5,0xFF000000,align); - font.updateString(L"Tempo: %.2f",60./(ctp/1e6)); - font.render(xp,yp+=step,0.5,0xFFFFFFFF,align); - font.render(xp-1,yp-1,0.5,0xFF000000,align); - font.updateString(L"Current tick: %d",ctk); - font.render(xp,yp+=step,0.5,0xFFFFFFFF,align); - font.render(xp-1,yp-1,0.5,0xFF000000,align); - if(!rendermode) - { - font.updateString(L"FPS: %.2f",sm->smGetFPS()); - font.render(xp,yp+=step,0.5,0xFFFFFFFF,align); - font.render(xp-1,yp-1,0.5,0xFF000000,align); - } - if(debug) - { - int dosdpos=(osdpos+1)%4; - xp=(dosdpos&1)?wwidth-step-1:1; - yp=dosdpos<2?wheight-step*5-4:step+4; - align=dosdpos&1?ALIGN_RIGHT:ALIGN_LEFT; - std::string tstr; - tstr=std::string(sm->smGetOSInfo()); - font.updateString(L"OS: %ls",std::wstring({std::begin(tstr),std::end(tstr)}).c_str()); - font.render(xp,yp,0.5,0xFFFFFFFF,align); - font.render(xp-1,yp-1,0.5,0xFF000000,align); - tstr=std::string(sm->smGetCPUModel()); - font.updateString(L"CPU: %ls",std::wstring({std::begin(tstr),std::end(tstr)}).c_str()); - font.render(xp,yp+=step,0.5,0xFFFFFFFF,align); - font.render(xp-1,yp-1,0.5,0xFF000000,align); - tstr=std::string(sm->smGetDispDriver()); - font.updateString(L"Display %ls",std::wstring({std::begin(tstr),std::end(tstr)}).c_str()); - font.render(xp,yp+=3*step,0.5,0xFFFFFFFF,align); - font.render(xp-1,yp-1,0.5,0xFF000000,align); - } - sm->smRenderEnd(); - if(rendermode) - { - if(ctk>api->getMaxTick()) - framecb(nullptr,0,ctk,api->getMaxTick()); - else - { - sm->smPixelCopy(0,0,wwidth,wheight,4*wwidth*wheight,fbcont); - framecb(fbcont,4*wwidth*wheight,ctk,api->getMaxTick()); - } - } - return shouldclose; + smQuad q; + if (!rendermode) + { + if (sm->smGetKeyState(SMK_RIGHT) == SMKST_HIT) + api->playerSeek(api->getCurrentPlaybackPercentage() + (sm->smGetKeyState(SMK_SHIFT) ? 5 : 1)); + if (sm->smGetKeyState(SMK_LEFT) == SMKST_HIT) + api->playerSeek(api->getCurrentPlaybackPercentage() - (sm->smGetKeyState(SMK_SHIFT) ? 5 : 1)); + if (sm->smGetKeyState(SMK_B) == SMKST_HIT) + debug ^= 1; + } + if (playing) + { + if (rendermode) + { + ctk = 1e6 * (cfr) / tfps / ctp * api->getDivision() + lstk; + ++cfr; + } + else + ctk = lstk + std::chrono::duration_cast>(std::chrono::steady_clock::now() - lst).count() / api->getRawTempo() * api->getDivision(); + } + if (!flat) + updateVisualization3D(); + sm->smRenderBegin2D(); + sm->smClrscr(0xFF666666); + q.blend = BLEND_ALPHABLEND; + for (int i = 0; i < 4; ++i) + { + q.v[i].col = 0xFFFFFFFF; + q.v[i].z = 0; + } + if (bgtex) + { + q.tex = bgtex; + q.v[0].x = q.v[3].x = 0; + q.v[1].x = q.v[2].x = wwidth; + q.v[0].y = q.v[1].y = 0; + q.v[2].y = q.v[3].y = wheight; + q.v[0].tx = q.v[3].tx = 0; + q.v[1].tx = q.v[2].tx = 1; + q.v[0].ty = q.v[1].ty = 0; + q.v[2].ty = q.v[3].ty = 1; + sm->smRenderQuad(&q); + } + if (flat) + updateVisualization2D(); + else + { + q.tex = sm->smTargetTexture(tdscn); + q.v[0].tx = q.v[3].tx = 0; + q.v[1].tx = q.v[2].tx = 1; + q.v[0].ty = q.v[1].ty = 0; + q.v[2].ty = q.v[3].ty = 1; + q.v[0].x = q.v[1].x = 0; + q.v[2].x = q.v[3].x = wwidth; + q.v[0].y = q.v[3].y = 0; + q.v[1].y = q.v[2].y = wheight; + sm->smRenderQuad(&q); + if (showparticle && !horizontal) + { + q.tex = sm->smTargetTexture(tdparticles); + sm->smRenderQuad(&q); + } + } + if (osdpos == 4) + { + sm->smRenderEnd(); + return shouldclose; + } + uint32_t ltpc = ~0u; + for (uint32_t i = elb; i < pool.size(); ++i) + { + if (pool[i]->tcs > ctk) + break; + if (pool[i]->ch == 998) + cts = pool[i]->key; + if (pool[i]->ch == 997) + cks = pool[i]->key; + if (pool[i]->ch == 996) + ltpc = i; + if (pool[i]->ch == 995) + cpbr[pool[i]->vel] = pool[i]->key; + if (pool[i]->ch == 994) + cpw[pool[i]->vel] = pool[i]->key; + } + if (~ltpc && ctp != pool[ltpc]->key) + { + ctp = pool[ltpc]->key; + if (rendermode) + { + lstk = pool[ltpc]->tcs; + cfr = 1; + } + } + int t, r; + t = cks; + r = (int8_t)((t >> 8) & 0xFF) + 7; + t &= 0xFF; + std::wstring ts(t ? minors : majors, 2 * r, 2); + int step = int(1.33 * fontsize); + int xp = (osdpos & 1) ? wwidth - step - 1 : 1; + int yp = osdpos < 2 ? wheight - step * 5 - 4 : step + 4; + int align = osdpos & 1 ? ALIGN_RIGHT : ALIGN_LEFT; + font2.updateString(L"Title: %ls", api->getWTitle().c_str()); + font2.render(xp, yp, 0.5, 0xFFFFFFFF, align); + font2.render(xp - 1, yp - 1, 0.5, 0xFF000000, align); + font.updateString(L"Time Sig: %d/%d", cts >> 8, 1 << (cts & 0xFF)); + font.render(xp, yp += step, 0.5, 0xFFFFFFFF, align); + font.render(xp - 1, yp - 1, 0.5, 0xFF000000, align); + font.updateString(L"Key Sig: %ls", ts.c_str()); + font.render(xp, yp += step, 0.5, 0xFFFFFFFF, align); + font.render(xp - 1, yp - 1, 0.5, 0xFF000000, align); + font.updateString(L"Tempo: %.2f", 60. / (ctp / 1e6)); + font.render(xp, yp += step, 0.5, 0xFFFFFFFF, align); + font.render(xp - 1, yp - 1, 0.5, 0xFF000000, align); + font.updateString(L"Current tick: %d", ctk); + font.render(xp, yp += step, 0.5, 0xFFFFFFFF, align); + font.render(xp - 1, yp - 1, 0.5, 0xFF000000, align); + if (!rendermode) + { + font.updateString(L"FPS: %.2f", sm->smGetFPS()); + font.render(xp, yp += step, 0.5, 0xFFFFFFFF, align); + font.render(xp - 1, yp - 1, 0.5, 0xFF000000, align); + } + if (debug) + { + int dosdpos = (osdpos + 1) % 4; + xp = (dosdpos & 1) ? wwidth - step - 1 : 1; + yp = dosdpos < 2 ? wheight - step * 5 - 4 : step + 4; + align = dosdpos & 1 ? ALIGN_RIGHT : ALIGN_LEFT; + std::string tstr; + tstr = std::string(sm->smGetOSInfo()); + font.updateString(L"OS: %ls", std::wstring({std::begin(tstr), std::end(tstr)}).c_str()); + font.render(xp, yp, 0.5, 0xFFFFFFFF, align); + font.render(xp - 1, yp - 1, 0.5, 0xFF000000, align); + tstr = std::string(sm->smGetCPUModel()); + font.updateString(L"CPU: %ls", std::wstring({std::begin(tstr), std::end(tstr)}).c_str()); + font.render(xp, yp += step, 0.5, 0xFFFFFFFF, align); + font.render(xp - 1, yp - 1, 0.5, 0xFF000000, align); + tstr = std::string(sm->smGetDispDriver()); + font.updateString(L"Display %ls", std::wstring({std::begin(tstr), std::end(tstr)}).c_str()); + font.render(xp, yp += 3 * step, 0.5, 0xFFFFFFFF, align); + font.render(xp - 1, yp - 1, 0.5, 0xFF000000, align); + } + sm->smRenderEnd(); + if (rendermode) + { + if (ctk > api->getMaxTick()) + framecb(nullptr, 0, ctk, api->getMaxTick()); + else + { + sm->smPixelCopy(0, 0, wwidth, wheight, 4 * wwidth * wheight, fbcont); + framecb(fbcont, 4 * wwidth * wheight, ctk, api->getMaxTick()); + } + } + return shouldclose; } -void qmpVisualization::drawCube(smvec3d a,smvec3d b,DWORD col,SMTEX tex,int faces) +void qmpVisualization::drawCube(smvec3d a, smvec3d b, DWORD col, SMTEX tex, int faces) { - smQuad q;q.blend=BLEND_ALPHABLEND; - q.tex=tex;for(int i=0;i<4;++i)q.v[i].col=col; - if(noteappearance==1) - { - smMatrix I;I.loadIdentity();smEntity3D c=smEntity3D::cube(a,b,col,faces); - nebuf->addTransformedEntity(&c,I,smvec3d(0,0,0)); - } - else - { - q.v[0].x=a.x;q.v[0].y=b.y;q.v[0].z=a.z; - q.v[1].x=b.x;q.v[1].y=b.y;q.v[1].z=a.z; - q.v[2].x=b.x;q.v[2].y=b.y;q.v[2].z=b.z; - q.v[3].x=a.x;q.v[3].y=b.y;q.v[3].z=b.z; - sm->smRenderQuad(&q); - } + smQuad q; + q.blend = BLEND_ALPHABLEND; + q.tex = tex; + for (int i = 0; i < 4; ++i) + q.v[i].col = col; + if (noteappearance == 1) + { + smMatrix I; + I.loadIdentity(); + smEntity3D c = smEntity3D::cube(a, b, col, faces); + nebuf->addTransformedEntity(&c, I, smvec3d(0, 0, 0)); + } + else + { + q.v[0].x = a.x; + q.v[0].y = b.y; + q.v[0].z = a.z; + q.v[1].x = b.x; + q.v[1].y = b.y; + q.v[1].z = a.z; + q.v[2].x = b.x; + q.v[2].y = b.y; + q.v[2].z = b.z; + q.v[3].x = a.x; + q.v[3].y = b.y; + q.v[3].z = b.z; + sm->smRenderQuad(&q); + } } -qmpVisualization* qmpVisualization::inst=nullptr; +qmpVisualization *qmpVisualization::inst = nullptr; -qmpVisualization::qmpVisualization(qmpPluginAPI* _api) +qmpVisualization::qmpVisualization(qmpPluginAPI *_api) { - api=_api; - inst=this; - rendermode=false; - hidewindow=false; + api = _api; + inst = this; + rendermode = false; + hidewindow = false; } qmpVisualization::~qmpVisualization() { - api=nullptr; - inst=nullptr; + api = nullptr; + inst = nullptr; } void qmpVisualization::init() { - h=new CMidiVisualHandler(this); - closeh=new CloseHandler(this); - rendererTh=nullptr;playing=false; - memset(rpnid,0xFF,sizeof(rpnid)); - memset(rpnval,0xFF,sizeof(rpnval)); - memset(spectra,0,sizeof(spectra)); - memset(spectrar,0,sizeof(spectrar)); - api->registerFunctionality(this,"Visualization","Visualization",api->isDarkTheme()?":/img/visualization_i.svg":":/img/visualization.svg",0,true); - uihb=api->registerUIHook("main.start",[this](const void*,void*){this->start();},nullptr); - uihs=api->registerUIHook("main.stop",[this](const void*,void*){this->stop();},nullptr); - uihp=api->registerUIHook("main.pause",[this](const void*,void*){this->pause();},nullptr); - uihr=api->registerUIHook("main.reset",[this](const void*,void*){this->reset();},nullptr); - uihk=api->registerUIHook("main.seek",[this](const void*,void*){ - cts=api->getTimeSig(); - cks=api->getKeySig(); - ctp=api->getRawTempo(); - for(int i=0;i<16;++i) - api->getPitchBendRaw(i,&cpw[i],&cpbr[i]); - },nullptr); - herh=api->registerEventReadHandler( - [this](const void *ee,void*){ - const SEvent* e=(const SEvent*)ee; - switch(e->type&0xF0) - { - case 0x80: - this->pushNoteOff(e->time,e->type&0x0F,e->p1); - break; - case 0x90: - if(e->p2) - this->pushNoteOn(e->time,e->type&0x0F,e->p1,e->p2); - else - this->pushNoteOff(e->time,e->type&0x0F,e->p1); - break; - case 0xB0: - if(e->p1==100)rpnid[e->type&0x0F]=e->p2; - if(e->p1==6)rpnval[e->type&0x0F]=e->p2; - if(~rpnid[e->type&0x0F]&&~rpnval[e->type&0x0F]) - { - if(rpnid[e->type&0x0F]==0) - this->pool.push_back(new MidiVisualEvent{e->time,e->time,rpnval[e->type&0x0F],e->type&0x0Fu,995}); - rpnval[e->type&0x0F]=~0u; - } - break; - case 0xE0: - this->pool.push_back(new MidiVisualEvent{e->time,e->time,(e->p1|(e->p2<<7))&0x3FFFu,e->type&0x0Fu,994}); - break; - case 0xF0: - if(e->type==0xFF&&e->p1==0x58) - { - this->tspool.push_back(std::make_pair(e->time,(e->str[0]<<24)|(e->str[1]<<16))); - this->pool.push_back(new MidiVisualEvent{e->time,e->time,(e->str[0]&0xffu)<<8|(e->str[1]&0xffu),0,998}); - } - else if(e->type==0xFF&&e->p1==0x59) - this->pool.push_back(new MidiVisualEvent{e->time,e->time,(e->str[0]&0xffu)<<8|(e->str[1]&0xffu),0,997}); - else if(e->type==0xFF&&e->p1==0x51) - this->pool.push_back(new MidiVisualEvent{e->time,e->time,(e->str[0]&0xffu)<<16|(e->str[1]&0xffu)<<8|(e->str[2]&0xffu),0,996}); - break; - } - } - ,nullptr); - heh=api->registerEventHandler( - [this](const void*,void*){ - if(this->ctk>this->api->getCurrentTimeStamp()+this->api->getDivision()/3) - this->elb=0; - /*if(abs((int)this->ctk-(int)this->api->getCurrentTimeStamp())>this->api->getDivision()/4) - fprintf(stderr,"Visualization: out of sync! %u vs %u ad: %u\n",this->ctk,this->api->getCurrentTimeStamp());*/ - this->ctk=this->api->getCurrentTimeStamp(); - this->lstk=this->ctk; - this->lst=std::chrono::steady_clock::now(); - } - ,nullptr); - hfrf=api->registerFileReadFinishHook( - [this](const void*,void*){ - memset(rpnval,0xFF,sizeof(rpnval)); - memset(rpnid,0xFF,sizeof(rpnid)); - std::sort(this->tspool.begin(),this->tspool.end()); - for(uint32_t tk=0,n=4,s=0;tk<=this->api->getMaxTick();){ - while(tk<(s>=this->tspool.size()?this->api->getMaxTick():this->tspool[s].first)){ - this->pool.push_back(new MidiVisualEvent{tk,tk,0,0,999}); - tk+=n*this->api->getDivision(); - } - tk=(s>=this->tspool.size()?this->api->getMaxTick():this->tspool[s].first); - if(tk==this->api->getMaxTick()){ - this->pool.push_back(new MidiVisualEvent{tk,tk,0,0,999}); - ++tk;break; - } - else n=this->tspool[s++].second>>24; - } - std::sort(this->pool.begin(),this->pool.end(),cmp); - } - ,nullptr); - api->registerOptionBool("Visualization-Appearance","Show Piano","Visualization/showpiano",true); - api->registerOptionBool("Visualization-Appearance","3D Notes","Visualization/3dnotes",true); - api->registerOptionBool("Visualization-Appearance","Arrange channels on a stair","Visualization/stairpiano",true); - api->registerOptionBool("Visualization-Appearance","Show channel labels","Visualization/showlabel",true); - api->registerOptionBool("Visualization-Appearance","Show Particles","Visualization/showparticle",false); - api->registerOptionBool("Visualization-Appearance","Horizontal Visualization","Visualization/horizontal",false); - api->registerOptionBool("Visualization-Appearance","2D Visualization","Visualization/flat",false); - api->registerOptionBool("Visualization-Appearance","Show Measure Indicator","Visualization/showmeasure",true); - api->registerOptionBool("Visualization-Appearance","Use spectrum instead of piano roll","Visualization/usespectrum",false); - api->registerOptionBool("Visualization-Video","Enable VSync","Visualization/vsync",true); - api->registerOptionBool("Visualization-Video","Save Viewport","Visualization/savevp",true); - api->registerOptionInt("Visualization-Video","Window Width","Visualization/wwidth",320,3200,800); - api->registerOptionInt("Visualization-Video","Window Height","Visualization/wheight",320,3200,600); - api->registerOptionInt("Visualization-Video","Target FPS","Visualization/tfps",5,1000,60); - api->registerOptionInt("Visualization-Video","Supersampling","Visualization/supersampling",1,16,0); - api->registerOptionInt("Visualization-Video","Multisampling","Visualization/multisampling",0,16,0); - api->registerOptionInt("Visualization-Video","FOV","Visualization/fov",30,180,60); - std::vector tv;tv.push_back("Bottom left");tv.push_back("Bottom right");tv.push_back("Top left");tv.push_back("Top right");tv.push_back("Hidden"); - api->registerOptionEnumInt("Visualization-Video","OSD Position","Visualization/osdpos",tv,0); - api->registerOptionInt("Visualization-Video","Font Size","Visualization/fontsize",6,180,16); - api->registerOptionString("Visualization-Video","Custom Sans Font","Visualization/font1","",true); - api->registerOptionString("Visualization-Video","Custom Monospace Font","Visualization/font2","",true); - api->registerOptionInt("Visualization-Appearance","View distance","Visualization/viewdist",20,1000,100); - api->registerOptionInt("Visualization-Appearance","Note stretch","Visualization/notestretch",20,500,100); - api->registerOptionInt("Visualization-Appearance","Minimum note length","Visualization/minnotelen",20,500,100); - api->registerOptionUint("Visualization-Appearance","Chequer board tint (AARRGGBB)","Visualization/chkrtint",0,0xFFFFFFFF,0xFF999999); - api->registerOptionString("Visualization-Appearance","Background Image","Visualization/background","",true); - api->registerOptionDouble("","","Visualization/px",-999999999,999999999,-1e9); - api->registerOptionDouble("","","Visualization/py",-999999999,999999999,-1e9); - api->registerOptionDouble("","","Visualization/pz",-999999999,999999999,-1e9); - api->registerOptionDouble("","","Visualization/rx",-999999999,999999999,-1e9); - api->registerOptionDouble("","","Visualization/ry",-999999999,999999999,-1e9); - api->registerOptionDouble("","","Visualization/rz",-999999999,999999999,-1e9); - for(int i=0;i<16;++i) - { - api->registerOptionUint("","","Visualization/chActiveColor"+std::to_string(i),0,0xFFFFFFFF,accolors[i]); - api->registerOptionUint("","","Visualization/chInactiveColor"+std::to_string(i),0,0xFFFFFFFF,iccolors[i]); - } - wwidth=api->getOptionInt("Visualization/wwidth"); - wheight=api->getOptionInt("Visualization/wheight"); - wsupersample=api->getOptionInt("Visualization/supersampling"); - wmultisample=api->getOptionInt("Visualization/multisampling"); - fov=api->getOptionInt("Visualization/fov"); - noteappearance=api->getOptionBool("Visualization/3dnotes"); - showpiano=api->getOptionBool("Visualization/showpiano"); - stairpiano=api->getOptionBool("Visualization/stairpiano"); - showlabel=api->getOptionBool("Visualization/showlabel"); - showparticle=api->getOptionBool("Visualization/showparticle"); - horizontal=api->getOptionBool("Visualization/horizontal"); - flat=api->getOptionBool("Visualization/flat"); - savevp=api->getOptionBool("Visualization/savevp"); - vsync=api->getOptionBool("Visualization/vsync"); - tfps=api->getOptionInt("Visualization/tfps"); - osdpos=api->getOptionEnumInt("Visualization/osdpos"); - fontsize=api->getOptionInt("Visualization/fontsize"); - viewdist=api->getOptionInt("Visualization/viewdist"); - notestretch=api->getOptionInt("Visualization/notestretch"); - minnotelength=api->getOptionInt("Visualization/minnotelen"); - chkrtint=api->getOptionUint("Visualization/chkrtint"); - for(int i=0;i<16;++i) - { - accolors[i]=api->getOptionUint("Visualization/chActiveColor"+std::to_string(i)); - iccolors[i]=api->getOptionUint("Visualization/chInactiveColor"+std::to_string(i)); - } - if(savevp) - { - pos[0]=api->getOptionDouble("Visualization/px"); - pos[1]=api->getOptionDouble("Visualization/py"); - pos[2]=api->getOptionDouble("Visualization/pz"); - rot[0]=api->getOptionDouble("Visualization/rx"); - rot[1]=api->getOptionDouble("Visualization/ry"); - rot[2]=api->getOptionDouble("Visualization/rz"); - } - memset(pss,0,sizeof(pss)); + h = new CMidiVisualHandler(this); + closeh = new CloseHandler(this); + rendererTh = nullptr; + playing = false; + memset(rpnid, 0xFF, sizeof(rpnid)); + memset(rpnval, 0xFF, sizeof(rpnval)); + memset(spectra, 0, sizeof(spectra)); + memset(spectrar, 0, sizeof(spectrar)); + api->registerFunctionality(this, "Visualization", "Visualization", api->isDarkTheme() ? ":/img/visualization_i.svg" : ":/img/visualization.svg", 0, true); + uihb = api->registerUIHook("main.start", [this](const void *, void *) + { + this->start(); + }, nullptr); + uihs = api->registerUIHook("main.stop", [this](const void *, void *) + { + this->stop(); + }, nullptr); + uihp = api->registerUIHook("main.pause", [this](const void *, void *) + { + this->pause(); + }, nullptr); + uihr = api->registerUIHook("main.reset", [this](const void *, void *) + { + this->reset(); + }, nullptr); + uihk = api->registerUIHook("main.seek", [this](const void *, void *) + { + cts = api->getTimeSig(); + cks = api->getKeySig(); + ctp = api->getRawTempo(); + for (int i = 0; i < 16; ++i) + api->getPitchBendRaw(i, &cpw[i], &cpbr[i]); + }, nullptr); + herh = api->registerEventReadHandler( + [this](const void *ee, void *) + { + const SEvent *e = (const SEvent *)ee; + switch (e->type & 0xF0) + { + case 0x80: + this->pushNoteOff(e->time, e->type & 0x0F, e->p1); + break; + case 0x90: + if (e->p2) + this->pushNoteOn(e->time, e->type & 0x0F, e->p1, e->p2); + else + this->pushNoteOff(e->time, e->type & 0x0F, e->p1); + break; + case 0xB0: + if (e->p1 == 100) + rpnid[e->type & 0x0F] = e->p2; + if (e->p1 == 6) + rpnval[e->type & 0x0F] = e->p2; + if (~rpnid[e->type & 0x0F] && ~rpnval[e->type & 0x0F]) + { + if (rpnid[e->type & 0x0F] == 0) + this->pool.push_back(new MidiVisualEvent{e->time, e->time, rpnval[e->type & 0x0F], e->type & 0x0Fu, 995}); + rpnval[e->type & 0x0F] = ~0u; + } + break; + case 0xE0: + this->pool.push_back(new MidiVisualEvent{e->time, e->time, (e->p1 | (e->p2 << 7)) & 0x3FFFu, e->type & 0x0Fu, 994}); + break; + case 0xF0: + if (e->type == 0xFF && e->p1 == 0x58) + { + this->tspool.push_back(std::make_pair(e->time, (e->str[0] << 24) | (e->str[1] << 16))); + this->pool.push_back(new MidiVisualEvent{e->time, e->time, (e->str[0] & 0xffu) << 8 | (e->str[1] & 0xffu), 0, 998}); + } + else if (e->type == 0xFF && e->p1 == 0x59) + this->pool.push_back(new MidiVisualEvent{e->time, e->time, (e->str[0] & 0xffu) << 8 | (e->str[1] & 0xffu), 0, 997}); + else if (e->type == 0xFF && e->p1 == 0x51) + this->pool.push_back(new MidiVisualEvent{e->time, e->time, (e->str[0] & 0xffu) << 16 | (e->str[1] & 0xffu) << 8 | (e->str[2] & 0xffu), 0, 996}); + break; + } + } + , nullptr); + heh = api->registerEventHandler( + [this](const void *, void *) + { + if (this->ctk > this->api->getCurrentTimeStamp() + this->api->getDivision() / 3) + this->elb = 0; + /*if(abs((int)this->ctk-(int)this->api->getCurrentTimeStamp())>this->api->getDivision()/4) + fprintf(stderr,"Visualization: out of sync! %u vs %u ad: %u\n",this->ctk,this->api->getCurrentTimeStamp());*/ + this->ctk = this->api->getCurrentTimeStamp(); + this->lstk = this->ctk; + this->lst = std::chrono::steady_clock::now(); + } + , nullptr); + hfrf = api->registerFileReadFinishHook( + [this](const void *, void *) + { + memset(rpnval, 0xFF, sizeof(rpnval)); + memset(rpnid, 0xFF, sizeof(rpnid)); + std::sort(this->tspool.begin(), this->tspool.end()); + for (uint32_t tk = 0, n = 4, s = 0; tk <= this->api->getMaxTick();) + { + while (tk < (s >= this->tspool.size() ? this->api->getMaxTick() : this->tspool[s].first)) + { + this->pool.push_back(new MidiVisualEvent{tk, tk, 0, 0, 999}); + tk += n * this->api->getDivision(); + } + tk = (s >= this->tspool.size() ? this->api->getMaxTick() : this->tspool[s].first); + if (tk == this->api->getMaxTick()) + { + this->pool.push_back(new MidiVisualEvent{tk, tk, 0, 0, 999}); + ++tk; + break; + } + else n = this->tspool[s++].second >> 24; + } + std::sort(this->pool.begin(), this->pool.end(), cmp); + } + , nullptr); + api->registerOptionBool("Visualization-Appearance", "Show Piano", "Visualization/showpiano", true); + api->registerOptionBool("Visualization-Appearance", "3D Notes", "Visualization/3dnotes", true); + api->registerOptionBool("Visualization-Appearance", "Arrange channels on a stair", "Visualization/stairpiano", true); + api->registerOptionBool("Visualization-Appearance", "Show channel labels", "Visualization/showlabel", true); + api->registerOptionBool("Visualization-Appearance", "Show Particles", "Visualization/showparticle", false); + api->registerOptionBool("Visualization-Appearance", "Horizontal Visualization", "Visualization/horizontal", false); + api->registerOptionBool("Visualization-Appearance", "2D Visualization", "Visualization/flat", false); + api->registerOptionBool("Visualization-Appearance", "Show Measure Indicator", "Visualization/showmeasure", true); + api->registerOptionBool("Visualization-Appearance", "Use spectrum instead of piano roll", "Visualization/usespectrum", false); + api->registerOptionBool("Visualization-Video", "Enable VSync", "Visualization/vsync", true); + api->registerOptionBool("Visualization-Video", "Save Viewport", "Visualization/savevp", true); + api->registerOptionInt("Visualization-Video", "Window Width", "Visualization/wwidth", 320, 3200, 800); + api->registerOptionInt("Visualization-Video", "Window Height", "Visualization/wheight", 320, 3200, 600); + api->registerOptionInt("Visualization-Video", "Target FPS", "Visualization/tfps", 5, 1000, 60); + api->registerOptionInt("Visualization-Video", "Supersampling", "Visualization/supersampling", 1, 16, 0); + api->registerOptionInt("Visualization-Video", "Multisampling", "Visualization/multisampling", 0, 16, 0); + api->registerOptionInt("Visualization-Video", "FOV", "Visualization/fov", 30, 180, 60); + std::vector tv; + tv.push_back("Bottom left"); + tv.push_back("Bottom right"); + tv.push_back("Top left"); + tv.push_back("Top right"); + tv.push_back("Hidden"); + api->registerOptionEnumInt("Visualization-Video", "OSD Position", "Visualization/osdpos", tv, 0); + api->registerOptionInt("Visualization-Video", "Font Size", "Visualization/fontsize", 6, 180, 16); + api->registerOptionString("Visualization-Video", "Custom Sans Font", "Visualization/font1", "", true); + api->registerOptionString("Visualization-Video", "Custom Monospace Font", "Visualization/font2", "", true); + api->registerOptionInt("Visualization-Appearance", "View distance", "Visualization/viewdist", 20, 1000, 100); + api->registerOptionInt("Visualization-Appearance", "Note stretch", "Visualization/notestretch", 20, 500, 100); + api->registerOptionInt("Visualization-Appearance", "Minimum note length", "Visualization/minnotelen", 20, 500, 100); + api->registerOptionUint("Visualization-Appearance", "Chequer board tint (AARRGGBB)", "Visualization/chkrtint", 0, 0xFFFFFFFF, 0xFF999999); + api->registerOptionString("Visualization-Appearance", "Background Image", "Visualization/background", "", true); + api->registerOptionDouble("", "", "Visualization/px", -999999999, 999999999, -1e9); + api->registerOptionDouble("", "", "Visualization/py", -999999999, 999999999, -1e9); + api->registerOptionDouble("", "", "Visualization/pz", -999999999, 999999999, -1e9); + api->registerOptionDouble("", "", "Visualization/rx", -999999999, 999999999, -1e9); + api->registerOptionDouble("", "", "Visualization/ry", -999999999, 999999999, -1e9); + api->registerOptionDouble("", "", "Visualization/rz", -999999999, 999999999, -1e9); + for (int i = 0; i < 16; ++i) + { + api->registerOptionUint("", "", "Visualization/chActiveColor" + std::to_string(i), 0, 0xFFFFFFFF, accolors[i]); + api->registerOptionUint("", "", "Visualization/chInactiveColor" + std::to_string(i), 0, 0xFFFFFFFF, iccolors[i]); + } + wwidth = api->getOptionInt("Visualization/wwidth"); + wheight = api->getOptionInt("Visualization/wheight"); + wsupersample = api->getOptionInt("Visualization/supersampling"); + wmultisample = api->getOptionInt("Visualization/multisampling"); + fov = api->getOptionInt("Visualization/fov"); + noteappearance = api->getOptionBool("Visualization/3dnotes"); + showpiano = api->getOptionBool("Visualization/showpiano"); + stairpiano = api->getOptionBool("Visualization/stairpiano"); + showlabel = api->getOptionBool("Visualization/showlabel"); + showparticle = api->getOptionBool("Visualization/showparticle"); + horizontal = api->getOptionBool("Visualization/horizontal"); + flat = api->getOptionBool("Visualization/flat"); + savevp = api->getOptionBool("Visualization/savevp"); + vsync = api->getOptionBool("Visualization/vsync"); + tfps = api->getOptionInt("Visualization/tfps"); + osdpos = api->getOptionEnumInt("Visualization/osdpos"); + fontsize = api->getOptionInt("Visualization/fontsize"); + viewdist = api->getOptionInt("Visualization/viewdist"); + notestretch = api->getOptionInt("Visualization/notestretch"); + minnotelength = api->getOptionInt("Visualization/minnotelen"); + chkrtint = api->getOptionUint("Visualization/chkrtint"); + for (int i = 0; i < 16; ++i) + { + accolors[i] = api->getOptionUint("Visualization/chActiveColor" + std::to_string(i)); + iccolors[i] = api->getOptionUint("Visualization/chInactiveColor" + std::to_string(i)); + } + if (savevp) + { + pos[0] = api->getOptionDouble("Visualization/px"); + pos[1] = api->getOptionDouble("Visualization/py"); + pos[2] = api->getOptionDouble("Visualization/pz"); + rot[0] = api->getOptionDouble("Visualization/rx"); + rot[1] = api->getOptionDouble("Visualization/ry"); + rot[2] = api->getOptionDouble("Visualization/rz"); + } + memset(pss, 0, sizeof(pss)); } void qmpVisualization::deinit() { - if(!api)return;close();tspool.clear(); - for(unsigned i=0;iunregisterUIHook("main.start",uihb); - api->unregisterUIHook("main.stop",uihs); - api->unregisterUIHook("main.pause",uihp); - api->unregisterUIHook("main.reset",uihr); - api->unregisterFunctionality("Visualization"); - api->unregisterEventReadHandler(herh); - api->unregisterEventHandler(heh); - api->unregisterFileReadFinishHook(hfrf); - delete h;delete closeh; + if (!api) + return; + close(); + tspool.clear(); + for (unsigned i = 0; i < pool.size(); ++i) + delete pool[i]; + pool.clear(); + api->unregisterUIHook("main.start", uihb); + api->unregisterUIHook("main.stop", uihs); + api->unregisterUIHook("main.pause", uihp); + api->unregisterUIHook("main.reset", uihr); + api->unregisterFunctionality("Visualization"); + api->unregisterEventReadHandler(herh); + api->unregisterEventHandler(heh); + api->unregisterFileReadFinishHook(hfrf); + delete h; + delete closeh; +} +const char *qmpVisualization::pluginGetName() +{ + return "QMidiPlayer Default Visualization Plugin"; +} +const char *qmpVisualization::pluginGetVersion() +{ + return PLUGIN_VERSION; } -const char* qmpVisualization::pluginGetName() -{return "QMidiPlayer Default Visualization Plugin";} -const char* qmpVisualization::pluginGetVersion() -{return PLUGIN_VERSION;} qmpVisualization *qmpVisualization::instance() -{return inst;} +{ + return inst; +} -void qmpVisualization::pushNoteOn(uint32_t tc,uint32_t ch,uint32_t key,uint32_t vel) +void qmpVisualization::pushNoteOn(uint32_t tc, uint32_t ch, uint32_t key, uint32_t vel) { - pendingt[ch][key].push(tc); - pendingv[ch][key].push(vel); + pendingt[ch][key].push(tc); + pendingv[ch][key].push(vel); } -void qmpVisualization::pushNoteOff(uint32_t tc,uint32_t ch,uint32_t key) +void qmpVisualization::pushNoteOff(uint32_t tc, uint32_t ch, uint32_t key) { - if(pendingt[ch][key].size()<1)return; - MidiVisualEvent *ne=new MidiVisualEvent(); - ne->tcs=pendingt[ch][key].top();pendingt[ch][key].pop(); - ne->tce=tc;ne->ch=ch;ne->key=key; - ne->vel=pendingv[ch][key].top();pendingv[ch][key].pop(); - pool.push_back(ne); + if (pendingt[ch][key].size() < 1) + return; + MidiVisualEvent *ne = new MidiVisualEvent(); + ne->tcs = pendingt[ch][key].top(); + pendingt[ch][key].pop(); + ne->tce = tc; + ne->ch = ch; + ne->key = key; + ne->vel = pendingv[ch][key].top(); + pendingv[ch][key].pop(); + pool.push_back(ne); } diff --git a/visualization/qmpvisualization.hpp b/visualization/qmpvisualization.hpp index 8a8d832..c0bc067 100644 --- a/visualization/qmpvisualization.hpp +++ b/visualization/qmpvisualization.hpp @@ -15,105 +15,121 @@ class qmpVisualization; struct MidiVisualEvent { - uint32_t tcs,tce; - uint32_t key,vel; - uint32_t ch; + uint32_t tcs, tce; + uint32_t key, vel; + uint32_t ch; }; -class qmpVisualization:public qmpPluginIntf,public qmpFuncBaseIntf +class qmpVisualization: public qmpPluginIntf, public qmpFuncBaseIntf { - friend class CloseHandler; - private: - qmpPluginAPI* api; - std::thread* rendererTh; - std::vectorpool; - smHandler *h,*closeh; - std::stack pendingt[16][128],pendingv[16][128]; - SMELT *sm; - SMTRG tdscn,tdparticles; - SMTEX chequer,bgtex,particletex,pianotex; - smTTFont font,font2,fonthdpi; - qmpVirtualPiano3D* p3d[16]; - smEntity3DBuffer* nebuf; - smParticleSystem* pss[16][128]; - smPSEmissionPositionGenerator* psepg; - float pos[3],rot[3],lastx,lasty; - uint32_t ctc,ctk,elb,lstk,cfr; - uint32_t cts,cks,ctp,cpbr[16],cpw[16]; - uint32_t rpnid[16],rpnval[16]; - std::chrono::steady_clock::time_point lst; - double etps; - bool shouldclose,playing,debug; - bool rendermode,hidewindow; - int herh,heh,hfrf; - int uihb,uihs,uihp,uihr,uihk; - void(*framecb)(void*,size_t,uint32_t,uint32_t); - DWORD* fbcont; - std::vector>tspool; - int traveld[16][128];bool notestatus[16][128],lastnotestatus[16][128]; - int spectra[16][128],spectrar[16][128]; - void drawCube(smvec3d a,smvec3d b,DWORD col,SMTEX tex,int faces=63); - void showThread(); - void pushNoteOn(uint32_t tc,uint32_t ch,uint32_t key,uint32_t vel); - void pushNoteOff(uint32_t tc,uint32_t ch,uint32_t key); - void updateVisualization3D(); - void updateVisualization2D(); + friend class CloseHandler; +private: + qmpPluginAPI *api; + std::thread *rendererTh; + std::vectorpool; + smHandler *h, *closeh; + std::stack pendingt[16][128], pendingv[16][128]; + SMELT *sm; + SMTRG tdscn, tdparticles; + SMTEX chequer, bgtex, particletex, pianotex; + smTTFont font, font2, fonthdpi; + qmpVirtualPiano3D *p3d[16]; + smEntity3DBuffer *nebuf; + smParticleSystem *pss[16][128]; + smPSEmissionPositionGenerator *psepg; + float pos[3], rot[3], lastx, lasty; + uint32_t ctc, ctk, elb, lstk, cfr; + uint32_t cts, cks, ctp, cpbr[16], cpw[16]; + uint32_t rpnid[16], rpnval[16]; + std::chrono::steady_clock::time_point lst; + double etps; + bool shouldclose, playing, debug; + bool rendermode, hidewindow; + int herh, heh, hfrf; + int uihb, uihs, uihp, uihr, uihk; + void(*framecb)(void *, size_t, uint32_t, uint32_t); + DWORD *fbcont; + std::vector>tspool; + int traveld[16][128]; + bool notestatus[16][128], lastnotestatus[16][128]; + int spectra[16][128], spectrar[16][128]; + void drawCube(smvec3d a, smvec3d b, DWORD col, SMTEX tex, int faces = 63); + void showThread(); + void pushNoteOn(uint32_t tc, uint32_t ch, uint32_t key, uint32_t vel); + void pushNoteOff(uint32_t tc, uint32_t ch, uint32_t key); + void updateVisualization3D(); + void updateVisualization2D(); - static qmpVisualization* inst; - public: - qmpVisualization(qmpPluginAPI* _api); - ~qmpVisualization(); - void show(); - void close(); - bool update(); - void start(); - void stop(); - void pause(); - void reset(); - void switchToRenderMode(void(*frameCallback)(void*,size_t,uint32_t,uint32_t),bool _hidewindow); + static qmpVisualization *inst; +public: + qmpVisualization(qmpPluginAPI *_api); + ~qmpVisualization(); + void show(); + void close(); + bool update(); + void start(); + void stop(); + void pause(); + void reset(); + void switchToRenderMode(void(*frameCallback)(void *, size_t, uint32_t, uint32_t), bool _hidewindow); - void init(); - void deinit(); - const char* pluginGetName(); - const char* pluginGetVersion(); + void init(); + void deinit(); + const char *pluginGetName(); + const char *pluginGetVersion(); - static qmpVisualization* instance(); + static qmpVisualization *instance(); }; -class CMidiVisualHandler:public smHandler +class CMidiVisualHandler: public smHandler { - private: - qmpVisualization *p; - public: - CMidiVisualHandler(qmpVisualization* par){p=par;} - bool handlerFunc(){return p->update();} +private: + qmpVisualization *p; +public: + CMidiVisualHandler(qmpVisualization *par) + { + p = par; + } + bool handlerFunc() + { + return p->update(); + } }; -class CloseHandler:public smHandler +class CloseHandler: public smHandler { - private: - qmpVisualization *p; - public: - CloseHandler(qmpVisualization* par){p=par;} - public: - bool handlerFunc() - { - std::thread ([this]{ - p->api->setFuncState("Visualization",false); - p->close();}).detach(); - return false; - } +private: + qmpVisualization *p; +public: + CloseHandler(qmpVisualization *par) + { + p = par; + } +public: + bool handlerFunc() + { + std::thread([this] + { + p->api->setFuncState("Visualization", false); + p->close(); + }).detach(); + return false; + } }; -extern "C"{ - EXPORTSYM qmpPluginIntf* qmpPluginGetInterface(qmpPluginAPI* api) - {return new qmpVisualization(api);} - EXPORTSYM const char* qmpPluginGetAPIRev() - {return QMP_PLUGIN_API_REV;} - EXPORTSYM void switchToRenderMode(void(*frameCallback)(void*,size_t,uint32_t,uint32_t),bool hidewindow) - { - if(qmpVisualization::instance()) - qmpVisualization::instance()->switchToRenderMode(frameCallback,hidewindow); - } +extern "C" { + EXPORTSYM qmpPluginIntf *qmpPluginGetInterface(qmpPluginAPI *api) + { + return new qmpVisualization(api); + } + EXPORTSYM const char *qmpPluginGetAPIRev() + { + return QMP_PLUGIN_API_REV; + } + EXPORTSYM void switchToRenderMode(void(*frameCallback)(void *, size_t, uint32_t, uint32_t), bool hidewindow) + { + if (qmpVisualization::instance()) + qmpVisualization::instance()->switchToRenderMode(frameCallback, hidewindow); + } } #endif // QMPVISUALIZATION_H diff --git a/visualization/renderer/main.cpp b/visualization/renderer/main.cpp index c651c54..7f25578 100644 --- a/visualization/renderer/main.cpp +++ b/visualization/renderer/main.cpp @@ -4,44 +4,46 @@ #include "qmpvisrendercore.hpp" #include "qmpsettingsro.hpp" -int main(int argc,char **argv) +int main(int argc, char **argv) { - QCoreApplication::setApplicationName("qmpvisrender"); - QCoreApplication::setApplicationVersion("0.0.0"); - QCoreApplication a(argc,argv); - QCommandLineParser clp; - clp.setApplicationDescription("Renderer a visualization of a midi file."); - clp.addHelpOption(); - clp.addVersionOption(); - clp.addOption({{"f","output-file"},"File name of the output file.","filename","output.mp4"}); - clp.addOption({ - "receiver", - "Specify a program and its arguments to process the rendered frames. Supports parameter substitution. See documentation for details.", - "command", - "ffmpeg %i -vf vflip -pix_fmt yuv420p -c:v libx264 -preset slow -crf 22 %o" - }); - clp.addOption({ - {"e","receiver-execution"}, - "Execution mode of the receiver command. Valid options are 'one-shot' and 'per-frame'", - "mode", - "one-shot" - }); - clp.addOption({{"s","show-window"},"Do not hide the visualization window."}); - clp.addOption({{"c","config"},"Load options from the configuration file.","qmprc file"}); - clp.addOption({{"o","option"},"Set option for the visualization module.","key-value pair"}); - clp.addOption({"list-options","Show a list of recognized options and quit."}); - clp.addPositionalArgument("file","MIDI file to render"); - clp.process(a.arguments()); - qmpVisRenderCore core(&clp); - if(clp.positionalArguments().empty()&&!clp.isSet("list-options")) - clp.showHelp(1); - core.loadSettings(); - if(!core.loadVisualizationLibrary()) - return 1; - if(clp.positionalArguments().size()) - core.setMIDIFile(clp.positionalArguments().front().toStdString().c_str()); - core.startRender(); - int retval=a.exec(); - core.unloadVisualizationLibrary(); - return retval; + QCoreApplication::setApplicationName("qmpvisrender"); + QCoreApplication::setApplicationVersion("0.0.0"); + QCoreApplication a(argc, argv); + QCommandLineParser clp; + clp.setApplicationDescription("Renderer a visualization of a midi file."); + clp.addHelpOption(); + clp.addVersionOption(); + clp.addOption({{"f", "output-file"}, "File name of the output file.", "filename", "output.mp4"}); + clp.addOption( + { + "receiver", + "Specify a program and its arguments to process the rendered frames. Supports parameter substitution. See documentation for details.", + "command", + "ffmpeg %i -vf vflip -pix_fmt yuv420p -c:v libx264 -preset slow -crf 22 %o" + }); + clp.addOption( + { + {"e", "receiver-execution"}, + "Execution mode of the receiver command. Valid options are 'one-shot' and 'per-frame'", + "mode", + "one-shot" + }); + clp.addOption({{"s", "show-window"}, "Do not hide the visualization window."}); + clp.addOption({{"c", "config"}, "Load options from the configuration file.", "qmprc file"}); + clp.addOption({{"o", "option"}, "Set option for the visualization module.", "key-value pair"}); + clp.addOption({"list-options", "Show a list of recognized options and quit."}); + clp.addPositionalArgument("file", "MIDI file to render"); + clp.process(a.arguments()); + qmpVisRenderCore core(&clp); + if (clp.positionalArguments().empty() && !clp.isSet("list-options")) + clp.showHelp(1); + core.loadSettings(); + if (!core.loadVisualizationLibrary()) + return 1; + 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 index 1be4880..b84a2b6 100644 --- a/visualization/renderer/qmppluginapistub.cpp +++ b/visualization/renderer/qmppluginapistub.cpp @@ -6,197 +6,245 @@ #include qmpPluginAPIStub::qmpPluginAPIStub(qmpVisRenderCore *_core): - core(_core) + core(_core) { } qmpPluginAPIStub::~qmpPluginAPIStub() { - core=nullptr; + core = nullptr; } uint32_t qmpPluginAPIStub::getDivision() { - return core->player->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::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;} + 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(); + 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){} + 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; + if (name == "Visualization") + core->vf = i; } void qmpPluginAPIStub::unregisterFunctionality(std::string name) { - if(name=="Visualization") - core->vf=nullptr; + if (name == "Visualization") + core->vf = nullptr; } -int qmpPluginAPIStub::registerUIHook(std::string e, ICallBack *cb, void *userdat){} +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; - if(e=="main.reset") - core->resetcb=cb; - return 0; + if (e == "main.start") + core->startcb = cb; + if (e == "main.reset") + core->resetcb = cb; + return 0; } void qmpPluginAPIStub::unregisterUIHook(std::string e, int hook) { - if(e=="main.start") - core->startcb=nullptr; - if(e=="main.reset") - core->resetcb=nullptr; + if (e == "main.start") + core->startcb = nullptr; + if (e == "main.reset") + core->resetcb = nullptr; } -void qmpPluginAPIStub::registerMidiOutDevice(qmpMidiOutDevice *dev, std::string name){} -void qmpPluginAPIStub::unregisterMidiOutDevice(std::string name){} +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::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::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); + return core->player->registerEventReadHandler(cb, userdata); } void qmpPluginAPIStub::unregisterEventReadHandler(int id) { - core->player->unregisterEventReadHandler(id); + core->player->unregisterEventReadHandler(id); } int qmpPluginAPIStub::registerFileReadFinishHook(callback_t cb, void *userdata) { - return core->player->registerFileReadFinishHook(cb,userdata); + return core->player->registerFileReadFinishHook(cb, userdata); } void qmpPluginAPIStub::unregisterFileReadFinishHook(int id) { - core->player->unregisterFileReadFinishHook(id); + core->player->unregisterFileReadFinishHook(id); } -void qmpPluginAPIStub::registerFileReader(qmpFileReader *reader, std::string name){} -void qmpPluginAPIStub::unregisterFileReader(std::string name){} +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); + core->settings()->registerOptionInt(tab, desc, key, min, max, defaultval); } int qmpPluginAPIStub::getOptionInt(std::string key) { - return core->settings()->getOptionInt(key); + return core->settings()->getOptionInt(key); } void qmpPluginAPIStub::setOptionInt(std::string key, int val) { - core->settings()->setOptionInt(key,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); + core->settings()->registerOptionUint(tab, desc, key, min, max, defaultval); } unsigned qmpPluginAPIStub::getOptionUint(std::string key) { - return core->settings()->getOptionUint(key); + return core->settings()->getOptionUint(key); } void qmpPluginAPIStub::setOptionUint(std::string key, unsigned val) { - return core->settings()->setOptionUint(key,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); + core->settings()->registerOptionBool(tab, desc, key, defaultval); } bool qmpPluginAPIStub::getOptionBool(std::string key) { - return core->settings()->getOptionBool(key); + return core->settings()->getOptionBool(key); } void qmpPluginAPIStub::setOptionBool(std::string key, bool val) { - core->settings()->setOptionBool(key,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); + core->settings()->registerOptionDouble(tab, desc, key, min, max, defaultval); } double qmpPluginAPIStub::getOptionDouble(std::string key) { - return core->settings()->getOptionDouble(key); + return core->settings()->getOptionDouble(key); } void qmpPluginAPIStub::setOptionDouble(std::string key, double val) { - core->settings()->setOptionDouble(key,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); + core->settings()->registerOptionString(tab, desc, key, defaultval, ispath); } std::string qmpPluginAPIStub::getOptionString(std::string key) { - return core->settings()->getOptionString(key); + return core->settings()->getOptionString(key); } void qmpPluginAPIStub::setOptionString(std::string key, std::string val) { - core->settings()->setOptionString(key,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); + core->settings()->registerOptionEnumInt(tab, desc, key, options, defaultval); } int qmpPluginAPIStub::getOptionEnumInt(std::string key) { - return core->settings()->getOptionEnumInt(key); + return core->settings()->getOptionEnumInt(key); } void qmpPluginAPIStub::setOptionEnumInt(std::string key, int val) { - core->settings()->setOptionEnumInt(key,val); + core->settings()->setOptionEnumInt(key, val); } diff --git a/visualization/renderer/qmppluginapistub.hpp b/visualization/renderer/qmppluginapistub.hpp index d96cfca..4a9024d 100644 --- a/visualization/renderer/qmppluginapistub.hpp +++ b/visualization/renderer/qmppluginapistub.hpp @@ -4,82 +4,82 @@ #include "qmpcorepublic.hpp" class qmpVisRenderCore; -class qmpPluginAPIStub:public qmpPluginAPI +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(); + 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 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 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); + 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; + qmpVisRenderCore *core; }; #endif // QMPPLUGINAPISTUB_HPP diff --git a/visualization/renderer/qmpsettingsro.cpp b/visualization/renderer/qmpsettingsro.cpp index 034f073..67dc257 100644 --- a/visualization/renderer/qmpsettingsro.cpp +++ b/visualization/renderer/qmpsettingsro.cpp @@ -9,218 +9,218 @@ qmpSettingsRO::qmpSettingsRO() { } -void qmpSettingsRO::registerOptionInt(std::string tab,std::string desc,std::string key,int min,int max,int defaultval) +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); + 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(); + 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) +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); + 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) +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); + 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(); + 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) +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); + 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) +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); + 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(); + 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) +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); + 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) +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); + 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(); + 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) +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); + 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) +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())); + 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(); + 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) +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())); + 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) +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; + 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(); + 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())); - } + 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) < options[key].enumlist.size()) + settings.insert(QString(key.c_str()), QString(options[key].enumlist[static_cast(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)); - } + QScopedPointer qsettings(new QSettings(path, QSettings::Format::IniFormat)); + settings.clear(); + for (QString &k : qsettings->allKeys()) + { + settings.insert(k, qsettings->value(k)); + } } void qmpSettingsRO::setopt(std::string key, std::string val) { - settings.insert(QString(key.c_str()),QString(val.c_str())); - if(key.find("Visualization/")!=0) - settings.insert("Visualization/"+QString(key.c_str()),QString(val.c_str())); + settings.insert(QString(key.c_str()), QString(val.c_str())); + if (key.find("Visualization/") != 0) + settings.insert("Visualization/" + QString(key.c_str()), QString(val.c_str())); } void qmpSettingsRO::listopt() { - for(auto&k:optionlist) - { - printf("Option key: %s\n",k.c_str()); - if(options[k].desc.length()) - printf("Description: %s\n",options[k].desc.c_str()); - switch(options[k].type) - { - case qmpOptionR::ParameterType::parameter_int: - printf("Type: int\n"); - printf("Range: [%d,%d]\n",options[k].minv.toInt(),options[k].maxv.toInt()); - printf("Default value: %d\n",options[k].defaultval.toInt()); - break; - case qmpOptionR::ParameterType::parameter_uint: - printf("Type: uint\n"); - printf("Range: [%u,%u]\n",options[k].minv.toUInt(),options[k].maxv.toUInt()); - printf("Default value: %u\n",options[k].defaultval.toUInt()); - break; - case qmpOptionR::ParameterType::parameter_double: - printf("Type: double\n"); - printf("Range: [%.2f,%.2f]\n",options[k].minv.toDouble(),options[k].maxv.toDouble()); - printf("Default value: %.f2\n",options[k].defaultval.toDouble()); - break; - case qmpOptionR::ParameterType::parameter_bool: - printf("Type: bool\n"); - printf("Default value: %s\n",options[k].defaultval.toBool()?"true":"false"); - break; - case qmpOptionR::ParameterType::parameter_str: - printf("Type: str\n"); - printf("Default value: %s\n",options[k].defaultval.toString().toStdString().c_str()); - break; - case qmpOptionR::ParameterType::parameter_url: - printf("Type: url\n"); - printf("Default value: %s\n",options[k].defaultval.toString().toStdString().c_str()); - break; - case qmpOptionR::ParameterType::parameter_enum: - printf("Type: enum\n"); - printf("Possible values: "); - for(size_t i=0;i enumlist; + 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){} + 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); + 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); - void setopt(std::string key,std::string val); - void listopt(); + void load(const char *path); + void setopt(std::string key, std::string val); + void listopt(); private: - std::map options; - std::vector optionlist; - QVariantMap settings; + std::map options; + std::vector optionlist; + QVariantMap settings; }; #endif diff --git a/visualization/renderer/qmpvisrendercore.cpp b/visualization/renderer/qmpvisrendercore.cpp index b12ed91..9d58206 100644 --- a/visualization/renderer/qmpvisrendercore.cpp +++ b/visualization/renderer/qmpvisrendercore.cpp @@ -19,262 +19,271 @@ #include #include #include -qmpVisRenderCore *qmpVisRenderCore::inst=nullptr; +qmpVisRenderCore *qmpVisRenderCore::inst = nullptr; -qmpVisRenderCore::qmpVisRenderCore(QCommandLineParser *_clp):QObject(nullptr),clp(_clp) +qmpVisRenderCore::qmpVisRenderCore(QCommandLineParser *_clp): QObject(nullptr), clp(_clp) { - inst=this; - player=new CMidiPlayer(); - api=new qmpPluginAPIStub(this); - msettings=new qmpSettingsRO(); - frameno=0; - 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); + inst = this; + player = new CMidiPlayer(); + api = new qmpPluginAPIStub(this); + msettings = new qmpSettingsRO(); + frameno = 0; + 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); } bool qmpVisRenderCore::loadVisualizationLibrary() { #ifdef _WIN32 - std::vector libpath={ - QCoreApplication::applicationDirPath().toStdWString()+L"/plugins/libvisualization.dll", - L"libvisualization.dll", - L"../libvisualization.dll"//for debugging only...? - }; + std::vector libpath = + { + QCoreApplication::applicationDirPath().toStdWString() + L"/plugins/libvisualization.dll", + L"libvisualization.dll", + L"../libvisualization.dll"//for debugging only...? + }; #else - std::vector libpath={ - QCoreApplication::applicationDirPath().toStdString()+"/plugins/libvisualization.so", - QT_STRINGIFY(INSTALL_PREFIX)+std::string("/lib/qmidiplayer/libvisualization.so"), - "../libvisualization.so"//for debugging only - }; + std::vector libpath = + { + QCoreApplication::applicationDirPath().toStdString() + "/plugins/libvisualization.so", + QT_STRINGIFY(INSTALL_PREFIX) + std::string("/lib/qmidiplayer/libvisualization.so"), + "../libvisualization.so"//for debugging only + }; #endif - for(auto&l:libpath) - { - mp=dlopen(l.c_str(),RTLD_LAZY); - if(mp)break; - } - if(!mp) - { - fprintf(stderr,"failed to load the visualization module!\n"); - return false; - } - GetInterface_func getintf=reinterpret_cast(dlsym(mp,"qmpPluginGetInterface")); - SwitchMode_func switchmode=reinterpret_cast(dlsym(mp,"switchToRenderMode")); - vf=nullptr; - vp=getintf(api); - switchmode(&qmpVisRenderCore::framefunc,!clp->isSet("show-window")); - vp->init(); - resetcb(nullptr,nullptr); - if(clp->isSet("list-options")) - { - msettings->listopt(); - exit(0); - } - return true; + for (auto &l : libpath) + { + mp = dlopen(l.c_str(), RTLD_LAZY); + if (mp) + break; + } + if (!mp) + { + fprintf(stderr, "failed to load the visualization module!\n"); + return false; + } + GetInterface_func getintf = reinterpret_cast(dlsym(mp, "qmpPluginGetInterface")); + SwitchMode_func switchmode = reinterpret_cast(dlsym(mp, "switchToRenderMode")); + vf = nullptr; + vp = getintf(api); + switchmode(&qmpVisRenderCore::framefunc, !clp->isSet("show-window")); + vp->init(); + resetcb(nullptr, nullptr); + if (clp->isSet("list-options")) + { + msettings->listopt(); + exit(0); + } + return true; } void qmpVisRenderCore::unloadVisualizationLibrary() { - vp->deinit(); - dlclose(mp); + vp->deinit(); + dlclose(mp); } void qmpVisRenderCore::loadSettings() { - if(clp->isSet("config")) - msettings->load(clp->value("config").toStdString().c_str()); - for(auto &o:clp->values("option")) - { - int sp=o.indexOf('='); - if(!~sp) - { - qDebug("invalid option pair: %s",o.toStdString().c_str()); - continue; - } - QString key=o.left(sp); - QString value=o.mid(sp+1); - msettings->setopt(key.toStdString(),value.toStdString()); - } + if (clp->isSet("config")) + msettings->load(clp->value("config").toStdString().c_str()); + for (auto &o : clp->values("option")) + { + int sp = o.indexOf('='); + if (!~sp) + { + qDebug("invalid option pair: %s", o.toStdString().c_str()); + continue; + } + QString key = o.left(sp); + QString value = o.mid(sp + 1); + msettings->setopt(key.toStdString(), value.toStdString()); + } } void qmpVisRenderCore::setMIDIFile(const char *url) { - player->playerLoadFile(url); + player->playerLoadFile(url); } void qmpVisRenderCore::startRender() { - assert(vf); - subst={ - {'w',QString::number(msettings->getOptionInt("Visualization/wwidth"))}, - {'h',QString::number(msettings->getOptionInt("Visualization/wheight"))}, - {'r',QString::number(msettings->getOptionInt("Visualization/tfps"))}, - {'i', - QStringList() - <<"-f"<<"rawvideo" - <<"-pixel_format"<<"rgba" - <<"-video_size"<getOptionInt("Visualization/wwidth")).arg(msettings->getOptionInt("Visualization/wheight")) - <<"-framerate"<getOptionInt("Visualization/tfps")) - <<"-i"<<"pipe:" - }, - {'o',clp->value("output-file")} - }; - if(clp->value("receiver-execution")=="per-frame") - { - subst['o']=clp->value("output-file").replace("%f",QString("%1").arg(frameno,6,10,QChar('0'))); - oneshot=false; - } - else - { - oneshot=true; - if(clp->value("receiver-execution")!="one-shot") - qWarning("Invalid value set for --receiver-execution. Using default value."); - } - rxproc=new QProcess(); - QStringList arguments=process_arguments(clp->value("receiver"),subst); - assert(arguments.length()>0); - rxproc->setProgram(arguments.front()); - arguments.pop_front(); - rxproc->setArguments(arguments); - frameconn=connect(this,&qmpVisRenderCore::frameRendered,this, - [this](void* px,size_t sz,uint32_t c,uint32_t t) - { - if(sz) - { - if(!oneshot) - { - subst['f']=QString("%1").arg(frameno,6,10,QChar('0')); - subst['o']=clp->value("output-file").replace("%f",QString("%1").arg(frameno,6,10,QChar('0'))); - frameno++; - QStringList arguments=process_arguments(clp->value("receiver"),subst); - arguments.pop_front(); - rxproc->setArguments(arguments); - rxproc->start(); - rxproc->waitForStarted(); - } - if(!rxproc->isOpen())return; - rxproc->write(static_cast(px),static_cast(sz)); - while(rxproc->bytesToWrite()>(oneshot?(1<<26):0)) - rxproc->waitForBytesWritten(); - if(!oneshot) - { - rxproc->closeWriteChannel(); - rxproc->waitForFinished(-1); - } - } - fprintf(stderr,"Rendered tick %u of %u, %.2f%% done.\r",c,t,std::min(100.,100.*c/t)); - if(c>t) - { - this->rxproc->closeWriteChannel(); - disconnect(frameconn); - qApp->exit(0); - } - },Qt::ConnectionType::BlockingQueuedConnection); - connect(rxproc,QOverload::of(&QProcess::finished), - [this](int x,QProcess::ExitStatus st){ - qDebug("%s",this->rxproc->readAllStandardError().data()); - if(oneshot) - { - disconnect(frameconn); - if(x||st==QProcess::ExitStatus::CrashExit) - qApp->exit(1); - else - qApp->exit(0); - } - }); - QMetaObject::invokeMethod(this,[this](){ - if(oneshot) - rxproc->start(); - vf->show(); - startcb(nullptr,nullptr); - },Qt::ConnectionType::QueuedConnection); + assert(vf); + subst = + { + {'w', QString::number(msettings->getOptionInt("Visualization/wwidth"))}, + {'h', QString::number(msettings->getOptionInt("Visualization/wheight"))}, + {'r', QString::number(msettings->getOptionInt("Visualization/tfps"))}, + { + 'i', + QStringList() + << "-f" << "rawvideo" + << "-pixel_format" << "rgba" + << "-video_size" << QString("%1x%2").arg(msettings->getOptionInt("Visualization/wwidth")).arg(msettings->getOptionInt("Visualization/wheight")) + << "-framerate" << QString::number(msettings->getOptionInt("Visualization/tfps")) + << "-i" << "pipe:" + }, + {'o', clp->value("output-file")} + }; + if (clp->value("receiver-execution") == "per-frame") + { + subst['o'] = clp->value("output-file").replace("%f", QString("%1").arg(frameno, 6, 10, QChar('0'))); + oneshot = false; + } + else + { + oneshot = true; + if (clp->value("receiver-execution") != "one-shot") + qWarning("Invalid value set for --receiver-execution. Using default value."); + } + rxproc = new QProcess(); + QStringList arguments = process_arguments(clp->value("receiver"), subst); + assert(arguments.length() > 0); + rxproc->setProgram(arguments.front()); + arguments.pop_front(); + rxproc->setArguments(arguments); + frameconn = connect(this, &qmpVisRenderCore::frameRendered, this, + [this](void *px, size_t sz, uint32_t c, uint32_t t) + { + if (sz) + { + if (!oneshot) + { + subst['f'] = QString("%1").arg(frameno, 6, 10, QChar('0')); + subst['o'] = clp->value("output-file").replace("%f", QString("%1").arg(frameno, 6, 10, QChar('0'))); + frameno++; + QStringList arguments = process_arguments(clp->value("receiver"), subst); + arguments.pop_front(); + rxproc->setArguments(arguments); + rxproc->start(); + rxproc->waitForStarted(); + } + if (!rxproc->isOpen()) + return; + rxproc->write(static_cast(px), static_cast(sz)); + while (rxproc->bytesToWrite() > (oneshot ? (1 << 26) : 0)) + rxproc->waitForBytesWritten(); + if (!oneshot) + { + rxproc->closeWriteChannel(); + rxproc->waitForFinished(-1); + } + } + fprintf(stderr, "Rendered tick %u of %u, %.2f%% done.\r", c, t, std::min(100., 100.*c / t)); + if (c > t) + { + this->rxproc->closeWriteChannel(); + disconnect(frameconn); + qApp->exit(0); + } + }, Qt::ConnectionType::BlockingQueuedConnection); + connect(rxproc, QOverload::of(&QProcess::finished), + [this](int x, QProcess::ExitStatus st) + { + qDebug("%s", this->rxproc->readAllStandardError().data()); + if (oneshot) + { + disconnect(frameconn); + if (x || st == QProcess::ExitStatus::CrashExit) + qApp->exit(1); + else + qApp->exit(0); + } + }); + QMetaObject::invokeMethod(this, [this]() + { + if (oneshot) + rxproc->start(); + vf->show(); + startcb(nullptr, nullptr); + }, Qt::ConnectionType::QueuedConnection); } -QStringList qmpVisRenderCore::process_arguments(QString a,QMap subst) +QStringList qmpVisRenderCore::process_arguments(QString a, QMap subst) { - QStringList ret; - QString buf; - bool escaped=false; - bool substi=false; - for(int i=0;iframeRendered(px,sz,curf,totf); + emit inst->frameRendered(px, sz, curf, totf); } diff --git a/visualization/renderer/qmpvisrendercore.hpp b/visualization/renderer/qmpvisrendercore.hpp index 71eeaed..ba978f4 100644 --- a/visualization/renderer/qmpvisrendercore.hpp +++ b/visualization/renderer/qmpvisrendercore.hpp @@ -15,44 +15,47 @@ class QCommandLineParser; class QProcess; -class qmpVisRenderCore:public QObject +class qmpVisRenderCore: public QObject { - Q_OBJECT + Q_OBJECT public: - qmpVisRenderCore(QCommandLineParser *_clp); - bool loadVisualizationLibrary(); - void unloadVisualizationLibrary(); - void loadSettings(); - void setMIDIFile(const char* url); - void startRender(); - - qmpSettingsRO* settings(){return msettings;} + qmpVisRenderCore(QCommandLineParser *_clp); + bool loadVisualizationLibrary(); + void unloadVisualizationLibrary(); + void loadSettings(); + void setMIDIFile(const char *url); + void startRender(); + + qmpSettingsRO *settings() + { + return msettings; + } signals: - void frameRendered(void* px,size_t sz,uint32_t current_tick,uint32_t total_ticks); + void frameRendered(void *px, size_t sz, uint32_t current_tick, uint32_t total_ticks); private: - qmpPluginIntf *vp; - qmpFuncBaseIntf *vf; - callback_t startcb; - callback_t resetcb; - void *mp; - qmpPluginAPIStub *api; - CMidiPlayer *player; - qmpSettingsRO *msettings; - QProcess *rxproc; - QMap subst; - QCommandLineParser *clp; - QStringList process_arguments(QString a, QMap subst); - int frameno; - bool oneshot; - QMetaObject::Connection frameconn; - typedef qmpPluginIntf*(*GetInterface_func)(qmpPluginAPI*); - typedef void(*SwitchMode_func)(void(*frameCallback)(void*,size_t,uint32_t,uint32_t),bool hidewindow); - - friend class qmpPluginAPIStub; - static void framefunc(void* px, size_t sz, uint32_t curf, uint32_t totf); - static qmpVisRenderCore *inst; + qmpPluginIntf *vp; + qmpFuncBaseIntf *vf; + callback_t startcb; + callback_t resetcb; + void *mp; + qmpPluginAPIStub *api; + CMidiPlayer *player; + qmpSettingsRO *msettings; + QProcess *rxproc; + QMap subst; + QCommandLineParser *clp; + QStringList process_arguments(QString a, QMap subst); + int frameno; + bool oneshot; + QMetaObject::Connection frameconn; + typedef qmpPluginIntf *(*GetInterface_func)(qmpPluginAPI *); + typedef void(*SwitchMode_func)(void(*frameCallback)(void *, size_t, uint32_t, uint32_t), bool hidewindow); + + friend class qmpPluginAPIStub; + static void framefunc(void *px, size_t sz, uint32_t curf, uint32_t totf); + static qmpVisRenderCore *inst; }; #endif // QMPVISRENDERCORE_HPP -- cgit v1.2.3