aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--core/qmpmidiplay.cpp20
-rw-r--r--core/qmpmidiplay.hpp11
-rw-r--r--core/qmpmidiread.cpp7
-rw-r--r--include/qmpcorepublic.hpp3
-rw-r--r--qmidiplayer-desktop/qmpplugin.cpp6
-rw-r--r--visualization/qmpvisualization.cpp94
-rw-r--r--visualization/qmpvisualization.hpp29
8 files changed, 152 insertions, 24 deletions
diff --git a/ChangeLog b/ChangeLog
index 6d7c17a..f04f5f8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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();