diff options
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | core/qmpmidiplay.cpp | 3 | ||||
-rw-r--r-- | core/qmpmidiplay.hpp | 3 | ||||
-rw-r--r-- | include/qmpcorepublic.hpp | 2 | ||||
-rw-r--r-- | qmidiplayer-desktop/qmpmainwindow.cpp | 42 | ||||
-rw-r--r-- | qmidiplayer-desktop/qmpmainwindow.hpp | 7 | ||||
-rw-r--r-- | qmidiplayer-desktop/qmpmainwindow.ui | 3 | ||||
-rw-r--r-- | qmidiplayer-desktop/qmpplugin.cpp | 29 | ||||
-rw-r--r-- | visualization/qmpvisualization.cpp | 156 | ||||
-rw-r--r-- | visualization/qmpvisualization.hpp | 28 |
11 files changed, 200 insertions, 79 deletions
@@ -1,3 +1,7 @@ +2016-04-26 0.7.8 beta +Now the default visualization plugin works as expected. +Avoid null pointers in the API implementation. + 2016-04-25 0.7.8 alpha Plugin API now works correctly. Port part of the old visualization code to the @@ -9,7 +9,7 @@ Features: * Playlists * Editing synthesizer effects * Rendering midi to wave file -* Visualization using SMELT (not implemented) +* Visualization using SMELT (currently Linux only) * MIDI mapping (based on RtMidi) Tested on Debian sid and Windows Vista~10. diff --git a/core/qmpmidiplay.cpp b/core/qmpmidiplay.cpp index ca2878c..5021640 100644 --- a/core/qmpmidiplay.cpp +++ b/core/qmpmidiplay.cpp @@ -196,7 +196,7 @@ void CMidiPlayer::prePlayInit() } void CMidiPlayer::playEvents() { - for(uint32_t ct=midiFile->getEvent(0)->time;tceptr<midiFile->getEventCount();) + for(ct=midiFile->getEvent(0)->time;tceptr<midiFile->getEventCount();) { while(tcpaused)std::this_thread::sleep_for(std::chrono::milliseconds(100)); using namespace std::chrono; @@ -402,6 +402,7 @@ uint32_t CMidiPlayer::getFileStandard(){return midiFile?midiFile->getStandard(): const char* CMidiPlayer::getTitle(){return midiFile?midiFile->getTitle():"";} const char* CMidiPlayer::getCopyright(){return midiFile?midiFile->getCopyright():"";} 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::getTCpaused(){return tcpaused;} diff --git a/core/qmpmidiplay.hpp b/core/qmpmidiplay.hpp index a89a925..96dfd12 100644 --- a/core/qmpmidiplay.hpp +++ b/core/qmpmidiplay.hpp @@ -73,7 +73,7 @@ class CMidiPlayer 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 tceptr,tcpaused,tcstop,ct; uint32_t finished,resumed; qmpMidiMapperRtMidi *mapper; int mappedoutput[16],deviceusage[16],deviceiid[128]; @@ -123,6 +123,7 @@ class CMidiPlayer uint32_t getFileNoteCount(); uint32_t getFileStandard(); double getTempo(); + uint32_t getTick(); uint32_t getRawTempo(); uint32_t getDivision(); const char* getTitle(); diff --git a/include/qmpcorepublic.hpp b/include/qmpcorepublic.hpp index 3654a75..8c67562 100644 --- a/include/qmpcorepublic.hpp +++ b/include/qmpcorepublic.hpp @@ -49,7 +49,7 @@ class qmpPluginAPI virtual uint32_t getCurrentPolyphone(); virtual uint32_t getMaxPolyphone(); virtual uint32_t getCurrentTimeStamp(); - virtual int registerVisualizationIntf(qmpVisualizationIntf* i); + virtual int registerVisualizationIntf(qmpVisualizationIntf* intf); virtual void unregisterVisualizationIntf(int intfhandle); virtual int registerEventReaderIntf(IMidiCallBack* cb,void* userdata); virtual void unregisterEventReaderIntf(int intfhandle); diff --git a/qmidiplayer-desktop/qmpmainwindow.cpp b/qmidiplayer-desktop/qmpmainwindow.cpp index 9d73626..53a2031 100644 --- a/qmidiplayer-desktop/qmpmainwindow.cpp +++ b/qmidiplayer-desktop/qmpmainwindow.cpp @@ -27,6 +27,7 @@ char* wcsto8bit(const wchar_t* s) } #define LOAD_FILE \ {\ + for(int i=0;i<16;++i)if(VIs[i])VIs[i]->reset();\ char* c=wcsto8bit(fns.toStdWString().c_str());\ if(!player->playerLoadFile(c)){free(c);QMessageBox::critical(this,tr("Error"),tr("%1 is not a valid midi file.").arg(fns));return;}\ free(c);\ @@ -35,7 +36,10 @@ char* wcsto8bit(const wchar_t* s) #define LOAD_SOUNDFONT \ player->pushSoundFont(settingsw->getSFWidget()->item(i)->text().toStdString().c_str()) #define LOAD_FILE \ - if(!player->playerLoadFile(fns.toStdString().c_str())){QMessageBox::critical(this,tr("Error"),tr("%1 is not a valid midi file.").arg(fns));return;} + {\ + for(int i=0;i<16;++i)if(VIs[i])VIs[i]->reset();\ + if(!player->playerLoadFile(fns.toStdString().c_str())){QMessageBox::critical(this,tr("Error"),tr("%1 is not a valid midi file.").arg(fns));return;}\ + } #endif #define UPDATE_INTERVAL 66 @@ -48,7 +52,7 @@ qmpMainWindow::qmpMainWindow(QWidget *parent) : ui->setupUi(this); ui->lnPolyphone->display("00000-00000"); ui->lbFileName->setText("");ref=this; - playing=false;stopped=true;dragging=false; + playing=false;stopped=true;dragging=false;memset(VIs,0,sizeof(VIs)); settingsw=new qmpSettingsWindow(this);pmgr=new qmpPluginManager(); plistw=new qmpPlistWindow(this);player=NULL;timer=NULL; singleFS=qmpSettingsWindow::getSettingsIntf()->value("Behavior/SingleInstance",0).toInt(); @@ -217,6 +221,7 @@ void qmpMainWindow::updateWidgets() if(!plistw->getRepeat()) { timer->stop();stopped=true;playing=false; + for(int i=0;i<16;++i)if(VIs[i])VIs[i]->stop(); fnA2->setEnabled(stopped);chnlw->resetAcitivity(); player->playerDeinit();playerTh->join(); delete playerTh;playerTh=NULL; @@ -232,6 +237,7 @@ void qmpMainWindow::updateWidgets() timer->stop();player->playerDeinit();playerTh->join(); delete playerTh;playerTh=NULL; ui->hsTimer->setValue(0); + for(int i=0;i<16;++i)if(VIs[i])VIs[i]->stop(); if(singleFS)player->playerPanic(true); chnlw->on_pbUnmute_clicked();chnlw->on_pbUnsolo_clicked(); QString fns=plistw->getNextItem(); @@ -244,6 +250,7 @@ void qmpMainWindow::updateWidgets() player->playerInit();if(!singleFS){playerSetup();player->fluidInitialize(); for(int i=settingsw->getSFWidget()->count()-1;i>=0;--i) LOAD_SOUNDFONT;} + for(int i=0;i<16;++i)if(VIs[i])VIs[i]->start(); player->setGain(ui->vsMasterVol->value()/250.);efxw->sendEfxChange(); player->setWaitVoice(qmpSettingsWindow::getSettingsIntf()->value("Midi/WaitVoice",1).toInt()); playerTh=new std::thread(&CMidiPlayer::playerThread,player); @@ -346,6 +353,7 @@ void qmpMainWindow::on_pbPlayPause_clicked() player->playerInit();if(!singleFS){playerSetup();player->fluidInitialize(); for(int i=settingsw->getSFWidget()->count()-1;i>=0;--i) LOAD_SOUNDFONT;} + for(int i=0;i<16;++i)if(VIs[i])VIs[i]->start(); player->setGain(ui->vsMasterVol->value()/250.);efxw->sendEfxChange(); player->setWaitVoice(qmpSettingsWindow::getSettingsIntf()->value("Midi/WaitVoice",1).toInt()); playerTh=new std::thread(&CMidiPlayer::playerThread,player); @@ -369,6 +377,7 @@ void qmpMainWindow::on_pbPlayPause_clicked() player->setResumed(); } player->setTCpaused(!playing); + for(int i=0;i<16;++i)if(VIs[i])VIs[i]->pause(); } ui->pbPlayPause->setIcon(QIcon(playing?":/img/pause.png":":/img/play.png")); } @@ -410,6 +419,7 @@ void qmpMainWindow::on_pbStop_clicked() if(!stopped) { timer->stop();stopped=true;playing=false; + for(int i=0;i<16;++i)if(VIs[i])VIs[i]->stop(); player->playerDeinit();fnA2->setEnabled(stopped); if(singleFS)player->playerPanic(true);chnlw->resetAcitivity(); if(playerTh){playerTh->join();delete playerTh;playerTh=NULL;} @@ -460,6 +470,7 @@ void qmpMainWindow::on_pbPrev_clicked() timer->stop();player->playerDeinit(); if(playerTh){playerTh->join();delete playerTh;playerTh=NULL;} if(singleFS)player->playerPanic(true); + for(int i=0;i<16;++i)if(VIs[i])VIs[i]->stop(); ui->hsTimer->setValue(0);chnlw->on_pbUnmute_clicked();chnlw->on_pbUnsolo_clicked(); QString fns=plistw->getPrevItem();if(fns.length()==0)return on_pbStop_clicked(); ui->lbFileName->setText(QUrl::fromLocalFile(fns).fileName().left(QUrl::fromLocalFile(fns).fileName().lastIndexOf('.'))); @@ -471,6 +482,7 @@ void qmpMainWindow::on_pbPrev_clicked() player->playerInit();if(!singleFS){playerSetup();player->fluidInitialize(); for(int i=settingsw->getSFWidget()->count()-1;i>=0;--i) LOAD_SOUNDFONT;} + for(int i=0;i<16;++i)if(VIs[i])VIs[i]->start(); player->setGain(ui->vsMasterVol->value()/250.);efxw->sendEfxChange(); player->setWaitVoice(qmpSettingsWindow::getSettingsIntf()->value("Midi/WaitVoice",1).toInt()); playerTh=new std::thread(&CMidiPlayer::playerThread,player); @@ -486,6 +498,7 @@ void qmpMainWindow::on_pbNext_clicked() timer->stop();player->playerDeinit(); if(playerTh){playerTh->join();delete playerTh;playerTh=NULL;} if(singleFS)player->playerPanic(true); + for(int i=0;i<16;++i)if(VIs[i])VIs[i]->stop(); ui->hsTimer->setValue(0);chnlw->on_pbUnmute_clicked();chnlw->on_pbUnsolo_clicked(); QString fns=plistw->getNextItem();if(fns.length()==0)return on_pbStop_clicked(); ui->lbFileName->setText(QUrl::fromLocalFile(fns).fileName().left(QUrl::fromLocalFile(fns).fileName().lastIndexOf('.'))); @@ -497,6 +510,7 @@ void qmpMainWindow::on_pbNext_clicked() player->playerInit();if(!singleFS){playerSetup();player->fluidInitialize(); for(int i=settingsw->getSFWidget()->count()-1;i>=0;--i) LOAD_SOUNDFONT;} + for(int i=0;i<16;++i)if(VIs[i])VIs[i]->start(); player->setGain(ui->vsMasterVol->value()/250.);efxw->sendEfxChange(); player->setWaitVoice(qmpSettingsWindow::getSettingsIntf()->value("Midi/WaitVoice",1).toInt()); playerTh=new std::thread(&CMidiPlayer::playerThread,player); @@ -512,6 +526,7 @@ void qmpMainWindow::selectionChanged() stopped=false;playing=true; ui->pbPlayPause->setIcon(QIcon(":/img/pause.png")); timer->stop();player->playerDeinit(); + for(int i=0;i<16;++i)if(VIs[i])VIs[i]->stop(); if(playerTh){playerTh->join();delete playerTh;playerTh=NULL;} if(singleFS)player->playerPanic(true); ui->hsTimer->setValue(0); @@ -526,6 +541,7 @@ void qmpMainWindow::selectionChanged() player->playerInit();if(!singleFS){playerSetup();player->fluidInitialize(); for(int i=settingsw->getSFWidget()->count()-1;i>=0;--i) LOAD_SOUNDFONT;} + for(int i=0;i<16;++i)if(VIs[i])VIs[i]->start(); player->setGain(ui->vsMasterVol->value()/250.);efxw->sendEfxChange(); player->setWaitVoice(qmpSettingsWindow::getSettingsIntf()->value("Midi/WaitVoice",1).toInt()); playerTh=new std::thread(&CMidiPlayer::playerThread,player); @@ -570,6 +586,20 @@ void qmpMainWindow::onfnChanged() ui->lbFileName->setFont(f); } +int qmpMainWindow::registerVisualizationIntf(qmpVisualizationIntf* intf) +{ + for(int i=0;i<16;++i) + { + if(VIs[i]==intf)return i; + if(VIs[i]==NULL){VIs[i]=intf;return i;} + } + return -1; +} +void qmpMainWindow::unregisterVisualizationIntf(int handle) +{ + VIs[handle]=NULL; +} + void qmpMainWindow::onfnA1() { infow->show(); @@ -609,3 +639,11 @@ void qmpMainWindow::on_pushButton_clicked() { helpw->show(); } + +void qmpMainWindow::on_pbVisualization_clicked() +{ + if(ui->pbVisualization->isChecked()) + {for(int i=0;i<16;++i)if(VIs[i])VIs[i]->show();} + else + {for(int i=0;i<16;++i)if(VIs[i])VIs[i]->close();} +} diff --git a/qmidiplayer-desktop/qmpmainwindow.hpp b/qmidiplayer-desktop/qmpmainwindow.hpp index b88169b..a981559 100644 --- a/qmidiplayer-desktop/qmpmainwindow.hpp +++ b/qmidiplayer-desktop/qmpmainwindow.hpp @@ -63,6 +63,8 @@ class qmpMainWindow:public QMainWindow bool isFinalizing(){return fin;} QString getFileName(); int pharseArgs(); + int registerVisualizationIntf(qmpVisualizationIntf* intf); + void unregisterVisualizationIntf(int handle); private slots: void on_pbPlayPause_clicked(); @@ -84,7 +86,9 @@ class qmpMainWindow:public QMainWindow void on_pushButton_clicked(); - public slots: + void on_pbVisualization_clicked(); + + public slots: void dialogClosed(); void selectionChanged(); @@ -104,6 +108,7 @@ class qmpMainWindow:public QMainWindow qmpInfoWindow *infow; qmpSettingsWindow *settingsw; qmpHelpWindow *helpw; + qmpVisualizationIntf* VIs[16]; QAction *fnA1,*fnA2,*fnA3; void onfnChanged(); diff --git a/qmidiplayer-desktop/qmpmainwindow.ui b/qmidiplayer-desktop/qmpmainwindow.ui index 2a9a420..69a3496 100644 --- a/qmidiplayer-desktop/qmpmainwindow.ui +++ b/qmidiplayer-desktop/qmpmainwindow.ui @@ -492,6 +492,9 @@ <height>32</height> </size> </property> + <property name="checkable"> + <bool>true</bool> + </property> </widget> </item> </layout> diff --git a/qmidiplayer-desktop/qmpplugin.cpp b/qmidiplayer-desktop/qmpplugin.cpp index aea01da..a71b869 100644 --- a/qmidiplayer-desktop/qmpplugin.cpp +++ b/qmidiplayer-desktop/qmpplugin.cpp @@ -62,25 +62,30 @@ void qmpPluginManager::initPlugins() plugins[i].interface->init(); } } +void qmpPluginManager::deinitPlugins() +{ + for(unsigned i=0;i<plugins.size();++i) + plugins[i].interface->deinit(); +} uint32_t qmpPluginAPI::getDivision() -{return qmw->getPlayer()->getDivision();} +{return qmw&&qmw->getPlayer()?qmw->getPlayer()->getDivision():0;} uint32_t qmpPluginAPI::getRawTempo() -{return qmw->getPlayer()->getRawTempo();} +{return qmw&&qmw->getPlayer()?qmw->getPlayer()->getRawTempo():0;} double qmpPluginAPI::getRealTempo() -{return qmw->getPlayer()->getTempo();} +{return qmw&&qmw->getPlayer()?qmw->getPlayer()->getTempo():0;} uint32_t qmpPluginAPI::getTimeSig() -{int n,d=0,t;qmw->getPlayer()->getCurrentTimeSignature(&n,&t);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 qmpPluginAPI::getKeySig() -{return qmw->getPlayer()->getCurrentKeySignature();} +{return qmw&&qmw->getPlayer()?qmw->getPlayer()->getCurrentKeySignature():0;} uint32_t qmpPluginAPI::getNoteCount() -{return qmw->getPlayer()->getFileNoteCount();} +{return qmw&&qmw->getPlayer()?qmw->getPlayer()->getFileNoteCount():0;} uint32_t qmpPluginAPI::getCurrentPolyphone() -{return qmw->getPlayer()->getPolyphone();} +{return qmw&&qmw->getPlayer()?qmw->getPlayer()->getPolyphone():0;} uint32_t qmpPluginAPI::getMaxPolyphone() -{return qmw->getPlayer()->getMaxPolyphone();} +{return qmw&&qmw->getPlayer()?qmw->getPlayer()->getMaxPolyphone():0;} uint32_t qmpPluginAPI::getCurrentTimeStamp() -{return qmw->getPlayer()->getTCeptr();} +{return qmw&&qmw->getPlayer()?qmw->getPlayer()->getTick():0;} int qmpPluginAPI::registerEventHandlerIntf(IMidiCallBack *cb,void *userdata) {return qmw->getPlayer()->setEventHandlerCB(cb,userdata);} void qmpPluginAPI::unregisterEventHandlerIntf(int intfhandle) @@ -89,8 +94,10 @@ int qmpPluginAPI::registerEventReaderIntf(IMidiCallBack *cb,void *userdata) {return qmw->getPlayer()->setEventReaderCB(cb,userdata);} void qmpPluginAPI::unregisterEventReaderIntf(int intfhandle) {qmw->getPlayer()->unsetEventReaderCB(intfhandle);} -int qmpPluginAPI::registerVisualizationIntf(qmpVisualizationIntf*){return 0;} -void qmpPluginAPI::unregisterVisualizationIntf(int){} +int qmpPluginAPI::registerVisualizationIntf(qmpVisualizationIntf* intf) +{return qmw->registerVisualizationIntf(intf);} +void qmpPluginAPI::unregisterVisualizationIntf(int intfhandle) +{qmw->unregisterVisualizationIntf(intfhandle);} void qmpPluginAPI::registerOptionInt(std::string,std::string,int){} int qmpPluginAPI::getOptionInt(std::string){return 0;} void qmpPluginAPI::registerOptionDouble(std::string,std::string,double){} diff --git a/visualization/qmpvisualization.cpp b/visualization/qmpvisualization.cpp index 2d0b494..8c8033c 100644 --- a/visualization/qmpvisualization.cpp +++ b/visualization/qmpvisualization.cpp @@ -2,17 +2,24 @@ #include <cstdlib> #include <cstring> #include <cmath> +#include <algorithm> #include "qmpvisualization.hpp" const int viewdist=100; const int notestretch=100;//length of quarter note const int minnotelength=100; +const int noteappearance=1; DWORD chcolors[]={0XFFFF0000,0XFFFF8000,0XFFFFBF00,0XFFFFFF00, 0XFFBFFF00,0XFF80FF00,0XFF00FF00,0XFF00FFBF, 0XFF00FFFF,0XFF333333,0XFF00BFFF,0XFF007FFF, 0XFF0000FF,0XFF7F00FF,0XFFBF00FF,0XFFFF00BF}; -void CTestCallBack::callBack(void *callerdata,void *) +bool cmp(MidiVisualEvent* a,MidiVisualEvent* b) +{ + if(a->tcs<b->tcs)return true;if(a->tcs>b->tcs)return false; + if(a->tce<b->tce)return true;return false; +} +void CReaderCallBack::callBack(void *callerdata,void *) { SEventCallBackData* cbd=(SEventCallBackData*)callerdata; switch(cbd->type&0xF0) @@ -25,15 +32,21 @@ void CTestCallBack::callBack(void *callerdata,void *) break; } } -void qmpVisualization::show() +void CHandlerCallBack::callBack(void*,void*) +{ + if(par->ctk>par->api->getCurrentTimeStamp()+par->api->getDivision()/3) + par->elb=0; + par->ctk=par->api->getCurrentTimeStamp(); +} +void qmpVisualization::showThread() { sm=smGetInterface(SMELT_APILEVEL); sm->smVidMode(800,600,true); - sm->smUpdateFunc(h); - sm->smWinTitle("A Stupid Midi Visualization"); + sm->smUpdateFunc(h);sm->smQuitFunc(closeh); + sm->smWinTitle("QMidiPlayer Visualization"); sm->smSetFPS(FPS_VSYNC); sm->smNoSuspend(true); - sm->smInit(); + sm->smInit();shouldclose=false; sm->smTextureOpt(TPOT_POT,TFLT_LINEAR); chequer=sm->smTextureLoad("chequerboard.png"); tdscn=sm->smTargetCreate(800,600); @@ -41,10 +54,16 @@ void qmpVisualization::show() 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); + sm->smMainLoop(); +} +void qmpVisualization::show() +{ + rendererTh=new std::thread(&qmpVisualization::showThread,this); } void qmpVisualization::close() { + shouldclose=true; + rendererTh->join(); sm->smFinale(); font.releaseTTF(); sm->smTextureFree(chequer); @@ -54,13 +73,16 @@ void qmpVisualization::close() void qmpVisualization::reset() { for(unsigned i=0;i<pool.size();++i)delete pool[i]; - pool.clear(); + pool.clear();elb=ctk=0; 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(); } } +void qmpVisualization::start(){playing=true;std::sort(pool.begin(),pool.end(),cmp);} +void qmpVisualization::stop(){playing=false;} +void qmpVisualization::pause(){playing=!playing;} bool qmpVisualization::update() { smQuad q; @@ -104,20 +126,21 @@ bool qmpVisualization::update() 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 + double lpt=(double)notestretch/api->getDivision()/10.; + 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) { 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); + smvec3d b(((double)pool[i]->key-64)+.9,pool[i]->ch*-2.+.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; + if(playing)ctk+=(int)(1e6/(api->getRawTempo()/api->getDivision())*sm->smGetDelta()); + while(pool.size()&&((double)ctk-pool[elb]->tce)*lpt>viewdist*2)++elb; + //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); @@ -128,70 +151,90 @@ bool qmpVisualization::update() 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"Tempo: %.2f",api->getRealTempo()); + font.render(1,556,0xFFFFFFFF,ALIGN_LEFT); + font.render(0,555,0xFF000000,ALIGN_LEFT); + font.updateString(L"Current tick: %d",ctk); + font.render(1,576,0xFFFFFFFF,ALIGN_LEFT); + font.render(0,575,0xFF000000,ALIGN_LEFT); font.updateString(L"FPS: %.2f",sm->smGetFPS()); - font.render(1,586,0xFFFFFFFF,ALIGN_LEFT); - font.render(0,585,0xFF000000,ALIGN_LEFT); + font.render(1,596,0xFFFFFFFF,ALIGN_LEFT); + font.render(0,595,0xFF000000,ALIGN_LEFT); sm->smRenderEnd(); - return false; + return shouldclose; } 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); + if(noteappearance==1) + { + //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); + } + 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(qmpPluginAPI* _api){api=_api;} qmpVisualization::~qmpVisualization(){api=NULL;} void qmpVisualization::init() { - puts("hello world from test plugin!"); - cb=new CTestCallBack(this); + cb=new CReaderCallBack(this); + hcb=new CHandlerCallBack(this); vi=new CDemoVisualization(this); h=new CMidiVisualHandler(this); + closeh=new RefuseCloseHandler(); api->registerVisualizationIntf(vi); api->registerEventReaderIntf(cb,NULL); + api->registerEventHandlerIntf(hcb,NULL); } void qmpVisualization::deinit() { - delete cb;delete vi; - delete h; + close(); + delete cb;delete hcb;delete vi; + delete h;delete closeh; } const char* qmpVisualization::pluginGetName() {return "QMidiPlayer Default Visualization Plugin";} @@ -210,6 +253,7 @@ void qmpVisualization::pushNoteOff(uint32_t tc,uint32_t ch,uint32_t key) 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(tc>fintk)fintk=tc; } diff --git a/visualization/qmpvisualization.hpp b/visualization/qmpvisualization.hpp index df9255c..438b98a 100644 --- a/visualization/qmpvisualization.hpp +++ b/visualization/qmpvisualization.hpp @@ -10,14 +10,22 @@ #include "../include/qmpcorepublic.hpp" class qmpVisualization; -class CTestCallBack:public IMidiCallBack +class CReaderCallBack:public IMidiCallBack { private: qmpVisualization *par; public: - CTestCallBack(qmpVisualization *_par){par=_par;} + CReaderCallBack(qmpVisualization *_par){par=_par;} void callBack(void *callerdata,void *userdata); }; +class CHandlerCallBack:public IMidiCallBack +{ + private: + qmpVisualization *par; + public: + CHandlerCallBack(qmpVisualization *_par){par=_par;} + void callBack(void*,void*); +}; struct MidiVisualEvent { uint32_t tcs,tce; @@ -26,22 +34,26 @@ struct MidiVisualEvent }; class qmpVisualization:public qmpPluginIntf { + friend class CHandlerCallBack; private: qmpPluginAPI* api; - CTestCallBack* cb; + CReaderCallBack* cb; + CHandlerCallBack* hcb; qmpVisualizationIntf* vi; std::thread* rendererTh; std::vector<MidiVisualEvent*>pool; - smHandler* h; + smHandler *h,*closeh; 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; + uint32_t ctc,ctk,fintk,elb; double etps; + bool shouldclose,playing; void drawCube(smvec3d a,smvec3d b,DWORD col,SMTEX tex); + void showThread(); public: qmpVisualization(qmpPluginAPI* _api); ~qmpVisualization(); @@ -71,6 +83,12 @@ class CMidiVisualHandler:public smHandler bool handlerFunc(){return p->update();} }; +class RefuseCloseHandler:public smHandler +{ + public: + bool handlerFunc(){return true;} +}; + class CDemoVisualization:public qmpVisualizationIntf { private: |