diff options
Diffstat (limited to 'visualization')
-rw-r--r-- | visualization/qmpvisualization.cpp | 214 | ||||
-rw-r--r-- | visualization/qmpvisualization.hpp | 61 | ||||
-rw-r--r-- | visualization/visualization.pro | 6 |
3 files changed, 268 insertions, 13 deletions
diff --git a/visualization/qmpvisualization.cpp b/visualization/qmpvisualization.cpp index e8bb9fb..2d0b494 100644 --- a/visualization/qmpvisualization.cpp +++ b/visualization/qmpvisualization.cpp @@ -1,34 +1,218 @@ #include <cstdio> +#include <cstdlib> +#include <cstring> +#include <cmath> #include "qmpvisualization.hpp" +const int viewdist=100; +const int notestretch=100;//length of quarter note +const int minnotelength=100; +DWORD chcolors[]={0XFFFF0000,0XFFFF8000,0XFFFFBF00,0XFFFFFF00, + 0XFFBFFF00,0XFF80FF00,0XFF00FF00,0XFF00FFBF, + 0XFF00FFFF,0XFF333333,0XFF00BFFF,0XFF007FFF, + 0XFF0000FF,0XFF7F00FF,0XFFBF00FF,0XFFFF00BF}; + void CTestCallBack::callBack(void *callerdata,void *) { - if(par->c<3) + SEventCallBackData* cbd=(SEventCallBackData*)callerdata; + switch(cbd->type&0xF0) { - SEventCallBackData* cbd=(SEventCallBackData*)callerdata; - printf("type %#x p1 %d p2 %d\n",cbd->type,cbd->p1,cbd->p2); + case 0x80: + par->pushNoteOff(cbd->time,cbd->type&0x0F,cbd->p1); + break; + case 0x90: + par->pushNoteOn(cbd->time,cbd->type&0x0F,cbd->p1,cbd->p2); + break; } } +void qmpVisualization::show() +{ + sm=smGetInterface(SMELT_APILEVEL); + sm->smVidMode(800,600,true); + sm->smUpdateFunc(h); + sm->smWinTitle("A Stupid Midi Visualization"); + sm->smSetFPS(FPS_VSYNC); + sm->smNoSuspend(true); + sm->smInit(); + sm->smTextureOpt(TPOT_POT,TFLT_LINEAR); + chequer=sm->smTextureLoad("chequerboard.png"); + tdscn=sm->smTargetCreate(800,600); + if(!font.loadTTF("/usr/share/fonts/truetype/freefont/FreeMono.ttf",16)) + printf("W: Font load failed.\n"); + pos[0]=-0;pos[1]=70;pos[2]=20; + rot[0]=0;rot[1]=90;rot[2]=90;ctk=0; + rendererTh=new std::thread(&SMELT::smMainLoop,sm); +} +void qmpVisualization::close() +{ + sm->smFinale(); + font.releaseTTF(); + sm->smTextureFree(chequer); + sm->smTargetFree(tdscn); + sm->smRelease(); +} +void qmpVisualization::reset() +{ + for(unsigned i=0;i<pool.size();++i)delete pool[i]; + pool.clear(); + for(int i=0;i<16;++i)for(int j=0;j<128;++j) + { + while(!pendingt[i][j].empty())pendingt[i][j].pop(); + while(!pendingv[i][j].empty())pendingv[i][j].pop(); + } +} +bool qmpVisualization::update() +{ + smQuad q; + for(int i=0;i<4;++i) + {q.v[i].col=0xFF999999;q.v[i].z=0;} + q.tex=chequer;q.blend=BLEND_ALPHABLEND; + q.v[0].x=q.v[3].x=-60;q.v[1].x=q.v[2].x=60; + q.v[0].y=q.v[1].y=-60;q.v[2].y=q.v[3].y=60; + q.v[0].tx=q.v[3].tx=0;q.v[1].tx=q.v[2].tx=15; + q.v[0].ty=q.v[1].ty=0;q.v[2].ty=q.v[3].ty=15; + sm->smRenderBegin3D(60,tdscn); + sm->sm3DCamera6f2v(pos,rot); + sm->smClrscr(0xFF666666); + sm->smRenderQuad(&q); + 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_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); + 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; + //printf("pos: %f %f %f\n",pos[0],pos[1],pos[2]); + //printf("rot: %f %f %f\n",rot[0],rot[1],rot[2]); + double lpt=(double)notestretch/dvs/10.; + for(uint32_t i=0;i<pool.size();++i)//need optimisation here + { + if(fabs((double)pool[i]->tcs-ctk)*lpt<viewdist*2||fabs((double)pool[i]->tce-ctk)*lpt<viewdist*2) + { + smvec3d a(((double)pool[i]->key-64),pool[i]->ch*-2.,((double)pool[i]->tce-ctk)*lpt); + smvec3d b(((double)pool[i]->key-64)+.9,pool[i]->ch*-2.+1.6,((double)pool[i]->tcs-ctk)*lpt); + if(((double)pool[i]->tce-pool[i]->tcs)*lpt<minnotelength/100.)a.z=((double)pool[i]->tcs-ctk)*lpt-minnotelength/100.; + drawCube(a,b,SETA(chcolors[pool[i]->ch],pool[i]->vel),0); + } + } + //ctk+=(int)(etps*sm->smGetDelta()); + ctk=api->getCurrentTimeStamp(); + if(ctk>fintk)return true; + sm->smRenderEnd(); + for(int i=0;i<4;++i){q.v[i].col=0xFFFFFFFF;q.v[i].z=0;} + q.tex=sm->smTargetTexture(tdscn); + sm->smRenderBegin2D(); + sm->smClrscr(0xFF000000); + 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=800; + q.v[0].y=q.v[3].y=0;q.v[1].y=q.v[2].y=600; + sm->smRenderQuad(&q); + font.updateString(L"FPS: %.2f",sm->smGetFPS()); + font.render(1,586,0xFFFFFFFF,ALIGN_LEFT); + font.render(0,585,0xFF000000,ALIGN_LEFT); + sm->smRenderEnd(); + return false; +} + +void qmpVisualization::drawCube(smvec3d a,smvec3d b,DWORD col,SMTEX tex) +{ + smQuad q;q.blend=BLEND_ALPHABLEND; + q.tex=tex;for(int i=0;i<4;++i)q.v[i].col=col; + //top + q.v[0].x=a.x;q.v[0].y=a.y;q.v[0].z=a.z; + q.v[1].x=b.x;q.v[1].y=a.y;q.v[1].z=a.z; + q.v[2].x=b.x;q.v[2].y=b.y;q.v[2].z=a.z; + q.v[3].x=a.x;q.v[3].y=b.y;q.v[3].z=a.z; + sm->smRenderQuad(&q); + //bottom + q.v[0].x=a.x;q.v[0].y=a.y;q.v[0].z=b.z; + q.v[1].x=b.x;q.v[1].y=a.y;q.v[1].z=b.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); + //left + q.v[0].x=a.x;q.v[0].y=b.y;q.v[0].z=a.z; + q.v[1].x=a.x;q.v[1].y=b.y;q.v[1].z=b.z; + q.v[2].x=a.x;q.v[2].y=a.y;q.v[2].z=b.z; + q.v[3].x=a.x;q.v[3].y=a.y;q.v[3].z=a.z; + sm->smRenderQuad(&q); + //right + q.v[0].x=b.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=b.z; + q.v[2].x=b.x;q.v[2].y=a.y;q.v[2].z=b.z; + q.v[3].x=b.x;q.v[3].y=a.y;q.v[3].z=a.z; + sm->smRenderQuad(&q); + //front + 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); + //back + q.v[0].x=a.x;q.v[0].y=a.y;q.v[0].z=a.z; + q.v[1].x=b.x;q.v[1].y=a.y;q.v[1].z=a.z; + q.v[2].x=b.x;q.v[2].y=a.y;q.v[2].z=b.z; + q.v[3].x=a.x;q.v[3].y=a.y;q.v[3].z=b.z; + sm->smRenderQuad(&q); +} -qmpVisualization::qmpVisualization(qmpPluginAPI* _api) -{api=_api;} -qmpVisualization::~qmpVisualization() -{api=NULL;} +qmpVisualization::qmpVisualization(qmpPluginAPI* _api){api=_api;} +qmpVisualization::~qmpVisualization(){api=NULL;} void qmpVisualization::init() { puts("hello world from test plugin!"); - puts("I'll try to print the first 3 events from the file!"); - cb=new CTestCallBack(this);c=0; - //!!FIXME: not working properly... + cb=new CTestCallBack(this); + vi=new CDemoVisualization(this); + h=new CMidiVisualHandler(this); + api->registerVisualizationIntf(vi); api->registerEventReaderIntf(cb,NULL); } void qmpVisualization::deinit() -{} +{ + delete cb;delete vi; + delete h; +} const char* qmpVisualization::pluginGetName() {return "QMidiPlayer Default Visualization Plugin";} const char* qmpVisualization::pluginGetVersion() {return "0.7.8";} +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); +} +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(); + if(tc>fintk)fintk=tc; +} + //dummy implementations of the api... uint32_t qmpPluginAPI::getDivision(){return 0;} uint32_t qmpPluginAPI::getRawTempo(){return 0;} @@ -43,3 +227,11 @@ int qmpPluginAPI::registerEventHandlerIntf(IMidiCallBack*,void*){return -1;} void qmpPluginAPI::unregisterEventHandlerIntf(int){} int qmpPluginAPI::registerEventReaderIntf(IMidiCallBack*,void*){return -1;} void qmpPluginAPI::unregisterEventReaderIntf(int){} +int qmpPluginAPI::registerVisualizationIntf(qmpVisualizationIntf*){return 0;} +void qmpPluginAPI::unregisterVisualizationIntf(int){} +void qmpPluginAPI::registerOptionInt(std::string,std::string,int){} +int qmpPluginAPI::getOptionInt(std::string){return 0;} +void qmpPluginAPI::registerOptionDouble(std::string,std::string,double){} +double qmpPluginAPI::getOptionDouble(std::string){return 0;} +void qmpPluginAPI::registerOptionString(std::string,std::string,std::string){} +std::string qmpPluginAPI::getOptionString(std::string){return "";} diff --git a/visualization/qmpvisualization.hpp b/visualization/qmpvisualization.hpp index 847f37b..df9255c 100644 --- a/visualization/qmpvisualization.hpp +++ b/visualization/qmpvisualization.hpp @@ -1,6 +1,12 @@ #ifndef QMPVISUALIZATION_H #define QMPVISUALIZATION_H +#include <vector> +#include <stack> +#include <thread> +#include <smelt.hpp> +#include <smmath.hpp> +#include <smttfont.hpp> #include "../include/qmpcorepublic.hpp" class qmpVisualization; @@ -12,22 +18,73 @@ class CTestCallBack:public IMidiCallBack CTestCallBack(qmpVisualization *_par){par=_par;} void callBack(void *callerdata,void *userdata); }; +struct MidiVisualEvent +{ + uint32_t tcs,tce; + uint32_t key,vel; + uint32_t ch; +}; class qmpVisualization:public qmpPluginIntf { - friend class CTestCallBack; private: qmpPluginAPI* api; - int c; CTestCallBack* cb; + qmpVisualizationIntf* vi; + std::thread* rendererTh; + std::vector<MidiVisualEvent*>pool; + smHandler* h; + std::stack<uint32_t> pendingt[16][128],pendingv[16][128]; + SMELT *sm; + SMTRG tdscn; + SMTEX chequer; + smTTFont font; + float pos[3],rot[3],lastx,lasty; + uint32_t ctc,dvs,ctk,fintk; + double etps; + void drawCube(smvec3d a,smvec3d b,DWORD col,SMTEX tex); 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); + void pushPitchBend(uint32_t tc,uint32_t ch,uint32_t key); + bool update(); + void start(); + void stop(); + void pause(); + void show(); + void close(); + void reset(); + void init(); void deinit(); const char* pluginGetName(); const char* pluginGetVersion(); }; +class CMidiVisualHandler:public smHandler +{ + private: + qmpVisualization *p; + public: + CMidiVisualHandler(qmpVisualization* par){p=par;} + bool handlerFunc(){return p->update();} +}; + +class CDemoVisualization:public qmpVisualizationIntf +{ + private: + qmpVisualization* par; + public: + CDemoVisualization(qmpVisualization *p){par=p;} + void show(){par->show();} + void close(){par->close();} + void start(){par->start();} + void stop(){par->stop();} + void pause(){par->pause();} + void reset(){par->reset();} +}; + extern "C"{ qmpPluginIntf* qmpPluginGetInterface(qmpPluginAPI* api) {return new qmpVisualization(api);} diff --git a/visualization/visualization.pro b/visualization/visualization.pro index 8cce718..10048bd 100644 --- a/visualization/visualization.pro +++ b/visualization/visualization.pro @@ -20,4 +20,10 @@ HEADERS += qmpvisualization.hpp unix { target.path = /usr/lib/qmidiplayer INSTALLS += target + QMAKE_CXXFLAGS += -pthread -fPIC } +#well... +INCLUDEPATH += /home/chrisoft/devel/BulletLabRemixIII/include/ /usr/include/freetype2 +LIBS += -L/home/chrisoft/devel/BulletLabRemixIII/smelt/sdl/ +LIBS += -L/home/chrisoft/devel/BulletLabRemixIII/extensions/ +LIBS += -lstdc++ -lSDL2 -ljpeg -lpng -lfreetype -lz -lsmeltext -lsmelt-dumb -lCxImage |