diff options
author | Chris Xiong <chirs241097@gmail.com> | 2017-01-02 22:09:28 +0800 |
---|---|---|
committer | Chris Xiong <chirs241097@gmail.com> | 2017-01-02 22:09:28 +0800 |
commit | b7842ae90b28618affdad6977c9c814aa573a3fe (patch) | |
tree | d43616b5b01a7c0b20044ff4564251043f313e9e | |
parent | b79c4b7e3cab3711e87ba9e28fa8423a84ea7efa (diff) | |
download | QMidiPlayer-b7842ae90b28618affdad6977c9c814aa573a3fe.tar.xz |
Can show measure indicators now.
Added new options to specify custom fonts.
Added a new handler API.
Minor rework on handler calling.
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | core/qmpmidiplay.cpp | 20 | ||||
-rw-r--r-- | core/qmpmidiplay.hpp | 11 | ||||
-rw-r--r-- | core/qmpmidiread.cpp | 7 | ||||
-rw-r--r-- | include/qmpcorepublic.hpp | 3 | ||||
-rw-r--r-- | qmidiplayer-desktop/qmpplugin.cpp | 6 | ||||
-rw-r--r-- | visualization/qmpvisualization.cpp | 94 | ||||
-rw-r--r-- | visualization/qmpvisualization.hpp | 29 |
8 files changed, 152 insertions, 24 deletions
@@ -1,3 +1,9 @@ +2017-01-02 0.8.3 alpha +Can show measure indicators now. +Added new options to specify custom fonts. +Added a new handler API. +Minor rework on handler calling. + 2016-12-27 0.8.3 alpha First official version with experimental support for the visualization plugin on Windows. Fixed several diff --git a/core/qmpmidiplay.cpp b/core/qmpmidiplay.cpp index bb2279d..1d32501 100644 --- a/core/qmpmidiplay.cpp +++ b/core/qmpmidiplay.cpp @@ -322,9 +322,11 @@ void CMidiPlayer::playerPanic(bool reset) } bool CMidiPlayer::playerLoadFile(const char* fn) { - midiFile=new CMidiFile(fn,this->eventReaderCB,this->eventReaderCBuserdata); + midiFile=new CMidiFile(fn,this); if(!midiFile->isValid())return false; divs=midiFile->getDivision(); + for(int i=0;i<16;++i)if(fileReadFinishCB[i]) + fileReadFinishCB[i]->callBack(NULL,fileReadFinishCBuserdata[i]); fileTimer1Pass(); fileTimer2Pass(); return true; @@ -411,6 +413,7 @@ 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];} uint32_t CMidiPlayer::getTCpaused(){return tcpaused;} void CMidiPlayer::setTCpaused(uint32_t ps){tcpaused=ps;} @@ -580,5 +583,20 @@ int CMidiPlayer::setEventReaderCB(IMidiCallBack *cb,void *userdata) } void CMidiPlayer::unsetEventReaderCB(int id) {eventReaderCB[id]=NULL;eventReaderCBuserdata[id]=NULL;} +int CMidiPlayer::setFileReadFinishedCB(IMidiCallBack *cb,void *userdata) +{ + for(int i=0;i<16;++i) + { + if(fileReadFinishCB[i]==cb)return i; + if(fileReadFinishCB[i]==NULL) + { + fileReadFinishCB[i]=cb;fileReadFinishCBuserdata[i]=userdata; + return i; + } + } + return -1; +} +void CMidiPlayer::unsetFileReadFinishedCB(int id) +{fileReadFinishCB[id]=NULL;fileReadFinishCBuserdata[id]=NULL;} void CMidiPlayer::discardLastEvent(){midiFile?midiFile->discardLastEvent():(void)0;} void CMidiPlayer::commitEventChange(SEventCallBackData d){midiFile?midiFile->commitEventChange(d):(void)0;} diff --git a/core/qmpmidiplay.hpp b/core/qmpmidiplay.hpp index f7b81af..5b6c5a7 100644 --- a/core/qmpmidiplay.hpp +++ b/core/qmpmidiplay.hpp @@ -21,6 +21,7 @@ struct SEvent if(s){str=new char[strlen(s)+2];strcpy(str,s);}else str=NULL; } }; +class CMidiPlayer; class CMidiFile { private: @@ -44,7 +45,7 @@ class CMidiFile int chunkReader(int hdrXp); void dumpEvents(); public: - CMidiFile(const char* fn,IMidiCallBack** ercb,void** ercbdata); + CMidiFile(const char* fn,CMidiPlayer* par); ~CMidiFile(); const SEvent* getEvent(uint32_t id); uint32_t getEventCount(); @@ -59,9 +60,10 @@ class CMidiFile }; class CMidiPlayer { + friend class CMidiFile; private: CMidiFile *midiFile; - uint32_t stamps[101]; + uint32_t stamps[101],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]; @@ -83,8 +85,10 @@ class CMidiPlayer uint8_t chstate[16],chstatus[16][130];//0..127: cc 128: pc IMidiCallBack* eventHandlerCB[16]; IMidiCallBack* eventReaderCB[16]; + IMidiCallBack* fileReadFinishCB[16]; void* eventHandlerCBuserdata[16]; void* eventReaderCBuserdata[16]; + void* fileReadFinishCBuserdata[16]; void setBit(uint16_t &n,uint16_t bn,uint16_t b); void processEvent(const SEvent *e); @@ -129,6 +133,7 @@ class CMidiPlayer uint32_t getTick(); uint32_t getRawTempo(); uint32_t getDivision(); + uint32_t getMaxTick(); double getPitchBend(int ch); const char* getTitle(); const char* getCopyright(); @@ -164,6 +169,8 @@ class CMidiPlayer void unsetEventHandlerCB(int id); int setEventReaderCB(IMidiCallBack *cb,void *userdata); void unsetEventReaderCB(int id); + int setFileReadFinishedCB(IMidiCallBack *cb,void *userdata); + void unsetFileReadFinishedCB(int id); void discardLastEvent(); void commitEventChange(SEventCallBackData d); diff --git a/core/qmpmidiread.cpp b/core/qmpmidiread.cpp index 33a1bd4..58a9786 100644 --- a/core/qmpmidiread.cpp +++ b/core/qmpmidiread.cpp @@ -229,11 +229,11 @@ void CMidiFile::dumpEvents() printf("type %x #%d @%d p1 %d p2 %d\n",eventList[i]->type, eventList[i]->iid,eventList[i]->time,eventList[i]->p1,eventList[i]->p2); } -CMidiFile::CMidiFile(const char* fn,IMidiCallBack **ercb,void **ercbdata) +CMidiFile::CMidiFile(const char* fn,CMidiPlayer* par) { title=copyright=NULL;notes=0;std=0;valid=1; - memcpy(eventReaderCB,ercb,sizeof(eventReaderCB)); - memcpy(eventReaderCBuserdata,ercbdata,sizeof(eventReaderCBuserdata)); + memcpy(eventReaderCB,par->eventReaderCB,sizeof(eventReaderCB)); + memcpy(eventReaderCBuserdata,par->eventReaderCBuserdata,sizeof(eventReaderCBuserdata)); try { if(!(f=fopen(fn,"rb")))throw (fprintf(stderr,"E: file %s doesn't exist!\n",fn),2); @@ -241,6 +241,7 @@ CMidiFile::CMidiFile(const char* fn,IMidiCallBack **ercb,void **ercbdata) for(uint32_t i=0;i<trk;i+=chunkReader(0)); fclose(f); std::sort(eventList.begin(),eventList.end(),cmp); + par->maxtk=eventList[eventList.size()-1]->time; } catch(int){fprintf(stderr,"E: %s is not a supported file.\n",fn);valid=0;} } diff --git a/include/qmpcorepublic.hpp b/include/qmpcorepublic.hpp index 683bde9..850fddd 100644 --- a/include/qmpcorepublic.hpp +++ b/include/qmpcorepublic.hpp @@ -65,6 +65,7 @@ class qmpPluginAPI virtual uint32_t getTimeSig(); virtual int getKeySig(); virtual uint32_t getNoteCount(); + virtual uint32_t getMaxTick(); virtual uint32_t getCurrentPolyphone(); virtual uint32_t getMaxPolyphone(); virtual uint32_t getCurrentTimeStamp(); @@ -93,6 +94,8 @@ class qmpPluginAPI virtual void unregisterEventReaderIntf(int intfhandle); virtual int registerEventHandlerIntf(IMidiCallBack* cb,void* userdata); virtual void unregisterEventHandlerIntf(int intfhandle); + virtual int registerFileReadFinishedHandlerIntf(IMidiCallBack* cb,void* userdata); + virtual void unregisterFileReadFinishedHandlerIntf(int intfhandle); //if desc=="", the option won't be visible in the settings form. //it will only show up in the configuration file. diff --git a/qmidiplayer-desktop/qmpplugin.cpp b/qmidiplayer-desktop/qmpplugin.cpp index 7193ade..0c8c04d 100644 --- a/qmidiplayer-desktop/qmpplugin.cpp +++ b/qmidiplayer-desktop/qmpplugin.cpp @@ -122,6 +122,8 @@ int qmpPluginAPI::getKeySig() {return qmw&&qmw->getPlayer()?qmw->getPlayer()->getCurrentKeySignature():0;} uint32_t qmpPluginAPI::getNoteCount() {return qmw&&qmw->getPlayer()?qmw->getPlayer()->getFileNoteCount():0;} +uint32_t qmpPluginAPI::getMaxTick() +{return qmw&&qmw->getPlayer()?qmw->getPlayer()->getMaxTick():0;} uint32_t qmpPluginAPI::getCurrentPolyphone() {return qmw&&qmw->getPlayer()?qmw->getPlayer()->getPolyphone():0;} uint32_t qmpPluginAPI::getMaxPolyphone() @@ -178,6 +180,10 @@ int qmpPluginAPI::registerVisualizationIntf(qmpVisualizationIntf* intf) {return qmw->registerVisualizationIntf(intf);} void qmpPluginAPI::unregisterVisualizationIntf(int intfhandle) {qmw->unregisterVisualizationIntf(intfhandle);} +int qmpPluginAPI::registerFileReadFinishedHandlerIntf(IMidiCallBack* cb,void* userdata) +{qmw->getPlayer()->setFileReadFinishedCB(cb,userdata);} +void qmpPluginAPI::unregisterFileReadFinishedHandlerIntf(int intfhandle) +{qmw->getPlayer()->unsetFileReadFinishedCB(intfhandle);} void qmpPluginAPI::registerOptionInt(std::string tab,std::string desc,std::string key,int min,int max,int defaultval) {qsw->registerOptionInt(tab,desc,key,min,max,defaultval);} diff --git a/visualization/qmpvisualization.cpp b/visualization/qmpvisualization.cpp index f17a92a..11abb3f 100644 --- a/visualization/qmpvisualization.cpp +++ b/visualization/qmpvisualization.cpp @@ -11,7 +11,7 @@ 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; +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#"; @@ -52,14 +52,37 @@ void CReaderCallBack::callBack(void *callerdata,void *) case 0x90: par->pushNoteOn(cbd->time,cbd->type&0x0F,cbd->p1,cbd->p2); break; + case 0xF0: + if(cbd->type==0xFF&&cbd->p1==0x58) + par->tspool.push_back(std::make_pair(cbd->time,cbd->p2)); + break; } } -void CHandlerCallBack::callBack(void*,void*) +void CEventHandlerCallBack::callBack(void*,void*) { if(par->ctk>par->api->getCurrentTimeStamp()+par->api->getDivision()/3) par->elb=0; + /*if(abs((int)par->ctk-(int)par->api->getCurrentTimeStamp())>par->api->getDivision()/4) + fprintf(stderr,"Visualization: out of sync! %u vs %u ad: %u\n",par->ctk,par->api->getCurrentTimeStamp());*/ par->ctk=par->api->getCurrentTimeStamp(); } +void CFRFinishedCallBack::callBack(void*,void*) +{ + std::sort(par->tspool.begin(),par->tspool.end()); + for(int tk=0,n=4,s=0;tk<=par->api->getMaxTick();){ + while(tk<(s>=par->tspool.size()?par->api->getMaxTick():par->tspool[s].first)){ + par->pool.push_back(new MidiVisualEvent{tk,tk,0,0,999}); + tk+=n*par->api->getDivision(); + } + tk=(s>=par->tspool.size()?par->api->getMaxTick():par->tspool[s].first); + if(tk==par->api->getMaxTick()){ + par->pool.push_back(new MidiVisualEvent{tk,tk,0,0,999}); + ++tk;break; + } + else n=par->tspool[s++].second>>24; + } + std::sort(par->pool.begin(),par->pool.end(),cmp); +} void qmpVisualization::showThread() { wwidth=api->getOptionInt("Visualization/wwidth"); @@ -74,6 +97,7 @@ void qmpVisualization::showThread() 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"); @@ -129,14 +153,17 @@ void qmpVisualization::showThread() if(noteappearance==1)nebuf=new smEntity3DBuffer();else nebuf=NULL; 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-fonts/FreeMono.otf",fontsize)) if(!font.loadTTF("C:/Windows/Fonts/cour.ttf",fontsize)) printf("W: Font load failed.\n"); + if(!api->getOptionString("Visualization/font2").length()||!font.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-fonts/FreeMono.otf",180)) if(!fonthdpi.loadTTF("C:/Windows/Fonts/cour.ttf",180)) printf("W: Font load failed.\n"); + if(!api->getOptionString("Visualization/font1").length()||!font.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("C:/Windows/Fonts/segoeui.ttf",fontsize)) @@ -204,7 +231,7 @@ void qmpVisualization::close() void qmpVisualization::reset() { for(unsigned i=0;i<pool.size();++i)delete pool[i]; - pool.clear();elb=ctk=0; + pool.clear();elb=ctk=0;tspool.clear(); for(int i=0;i<16;++i)for(int j=0;j<128;++j) { if(showparticle&&!horizontal&&pss[i][j])pss[i][j]->stopPS(); @@ -212,7 +239,7 @@ void qmpVisualization::reset() while(!pendingv[i][j].empty())pendingv[i][j].pop(); } } -void qmpVisualization::start(){playing=true;std::sort(pool.begin(),pool.end(),cmp);} +void qmpVisualization::start(){playing=true;} void qmpVisualization::stop(){playing=false;} void qmpVisualization::pause(){playing=!playing;} bool qmpVisualization::update() @@ -291,6 +318,29 @@ bool qmpVisualization::update() 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){ + if(!horizontal&&stairpiano){ + for(int ch=0;ch<16;++ch){ + smvec3d a(0.63*(-80)+.1,(stairpiano?(56-ch*7.):(64-ch*8.))-1,((double)pool[i]->tce+1-ctk)*lpt+(stairpiano&&showpiano&&!horizontal)*ch*2.); + smvec3d b(0.63*80+.7,(stairpiano?(56-ch*7.):(64-ch*8.))+4,((double)pool[i]->tcs-ctk)*lpt+(stairpiano&&showpiano&&!horizontal)*ch*2.); + if(horizontal){ + a=smvec3d(((double)pool[i]->tcs-ctk)*lpt-20,(16-ch*2.),0.63*(-64)+.1); + b=smvec3d(((double)pool[i]->tce+1-ctk)*lpt-20,(16-ch*2.)+.4,0.63*64+.7); + } + if(showmeasure)drawCube(a,b,0x80808080,0); + } + } + else{ + smvec3d a(0.63*(-64)+.1,(stairpiano?(56-0*7.):(64-0*8.)),((double)pool[i]->tce+1-ctk)*lpt+(stairpiano&&showpiano&&!horizontal)*0*2.); + smvec3d b(0.63*64+.7,(stairpiano?(56-15*7.):(64-15*8.))+.4,((double)pool[i]->tcs-ctk)*lpt+(stairpiano&&showpiano&&!horizontal)*15*2.); + if(horizontal){ + a=smvec3d(((double)pool[i]->tcs-ctk)*lpt-20,(16-0*2.),0.63*(-64)+.1); + b=smvec3d(((double)pool[i]->tce+1-ctk)*lpt-20,(16-15*2.)+.4,0.63*64+.7); + } + if(showmeasure)drawCube(a,b,0x80808080,0); + } + 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.); @@ -370,7 +420,7 @@ bool qmpVisualization::update() fonthdpi.render(-49.05,stairpiano?56.05-i*7:63.05-i*8,stairpiano*i*2+0.2,0xFF000000,ALIGN_RIGHT,.008,0.01); } } - if(playing)ctk+=(int)(1e6/(api->getRawTempo()/api->getDivision())*sm->smGetDelta()); + if(playing)ctk+=(int)1e6/((double)api->getRawTempo()/api->getDivision())*sm->smGetDelta(); while(pool.size()&&elb<pool.size()&&((double)ctk-pool[elb]->tce)*lpt>viewdist*2)++elb; sm->smRenderEnd(); if(showparticle&&!horizontal) @@ -412,6 +462,15 @@ bool qmpVisualization::update() if(((double)pool[i]->tcs-ctk)*lpt+wheight-nh<0)break; if(fabs((double)pool[i]->tcs-ctk)*lpt+wheight-nh>0||fabs((double)pool[i]->tce-ctk)*lpt+wheight-nh<wheight) { + 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); + 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(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); @@ -531,6 +590,15 @@ bool qmpVisualization::update() if(((double)pool[i]->tcs-ctk)*lpt+nh>wwidth)break; if(fabs((double)pool[i]->tcs-ctk)*lpt+nh<wwidth||fabs((double)pool[i]->tce-ctk)*lpt+nh>0) { + if(pool[i]->ch==999){ + smvec2d a(((double)pool[i]->tcs-ctk)*lpt+nh-minnotelength*0.02,0); + smvec2d b(((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(api->getChannelMask(pool[i]->ch))continue; smvec2d a(((double)pool[i]->tce-ctk)*lpt+nh,(froffsets[12]*(pool[i]->key/12)+froffsets[pool[i]->key%12])*wheight/2048.); smvec2d b(((double)pool[i]->tcs-ctk)*lpt+nh,a.y+notew*0.9); @@ -642,7 +710,7 @@ bool qmpVisualization::update() } } } - if(playing)ctk+=(int)(1e6/(api->getRawTempo()/api->getDivision())*sm->smGetDelta()); + if(playing)ctk+=(int)1e6/((double)api->getRawTempo()/api->getDivision())*sm->smGetDelta(); } else { @@ -708,9 +776,10 @@ qmpVisualization::~qmpVisualization(){api=NULL;} void qmpVisualization::init() { cb=new CReaderCallBack(this); - hcb=new CHandlerCallBack(this); + hcb=new CEventHandlerCallBack(this); vi=new CDemoVisualization(this); h=new CMidiVisualHandler(this); + frcb=new CFRFinishedCallBack(this); closeh=new CloseHandler(this); rendererTh=NULL;playing=false; memset(spectra,0,sizeof(spectra)); @@ -718,13 +787,15 @@ void qmpVisualization::init() hvif=api->registerVisualizationIntf(vi); herif=api->registerEventReaderIntf(cb,NULL); hehif=api->registerEventHandlerIntf(hcb,NULL); + hfrf=api->registerFileReadFinishedHandlerIntf(frcb,NULL); 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",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); @@ -737,6 +808,8 @@ void qmpVisualization::init() std::vector<std::string> 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",""); + api->registerOptionString("Visualization-Video","Custom Monospace Font","Visualization/font2",""); 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); @@ -783,12 +856,13 @@ void qmpVisualization::init() } void qmpVisualization::deinit() { - if(!api)return;close(); + if(!api)return;close();tspool.clear(); for(unsigned i=0;i<pool.size();++i)delete pool[i];pool.clear(); api->unregisterVisualizationIntf(hvif); api->unregisterEventReaderIntf(herif); api->unregisterEventHandlerIntf(hehif); - delete cb;delete hcb;delete vi; + api->unregisterFileReadFinishedHandlerIntf(hfrf); + delete cb;delete hcb;delete vi;delete frcb; delete h;delete closeh; } const char* qmpVisualization::pluginGetName() diff --git a/visualization/qmpvisualization.hpp b/visualization/qmpvisualization.hpp index 21339b5..fea96f4 100644 --- a/visualization/qmpvisualization.hpp +++ b/visualization/qmpvisualization.hpp @@ -1,9 +1,10 @@ #ifndef QMPVISUALIZATION_H #define QMPVISUALIZATION_H -#include <vector> #include <stack> #include <thread> +#include <utility> +#include <vector> #include <smelt.hpp> #include <smmath.hpp> #include <smttfont.hpp> @@ -19,12 +20,20 @@ class CReaderCallBack:public IMidiCallBack CReaderCallBack(qmpVisualization *_par){par=_par;} void callBack(void *callerdata,void *userdata); }; -class CHandlerCallBack:public IMidiCallBack +class CEventHandlerCallBack:public IMidiCallBack +{ + private: + qmpVisualization *par; + public: + CEventHandlerCallBack(qmpVisualization *_par){par=_par;} + void callBack(void*,void*); +}; +class CFRFinishedCallBack:public IMidiCallBack { private: qmpVisualization *par; public: - CHandlerCallBack(qmpVisualization *_par){par=_par;} + CFRFinishedCallBack(qmpVisualization *_par){par=_par;} void callBack(void*,void*); }; struct MidiVisualEvent @@ -35,13 +44,16 @@ struct MidiVisualEvent }; class qmpVisualization:public qmpPluginIntf { - friend class CHandlerCallBack; + friend class CEventHandlerCallBack; + friend class CReaderCallBack; friend class CloseHandler; + friend class CFRFinishedCallBack; private: qmpPluginAPI* api; CReaderCallBack* cb; - CHandlerCallBack* hcb; + CEventHandlerCallBack* hcb; qmpVisualizationIntf* vi; + CFRFinishedCallBack* frcb; std::thread* rendererTh; std::vector<MidiVisualEvent*>pool; smHandler *h,*closeh; @@ -58,16 +70,17 @@ class qmpVisualization:public qmpPluginIntf uint32_t ctc,ctk,fintk,elb; double etps; bool shouldclose,playing; - int hvif,herif,hehif; + int hvif,herif,hehif,hfrf; + std::vector<std::pair<uint32_t,uint32_t>>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); 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); public: qmpVisualization(qmpPluginAPI* _api); ~qmpVisualization(); - 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); bool update(); void start(); void stop(); |