aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4
-rw-r--r--README.md2
-rw-r--r--core/qmpmidiplay.cpp3
-rw-r--r--core/qmpmidiplay.hpp3
-rw-r--r--include/qmpcorepublic.hpp2
-rw-r--r--qmidiplayer-desktop/qmpmainwindow.cpp42
-rw-r--r--qmidiplayer-desktop/qmpmainwindow.hpp7
-rw-r--r--qmidiplayer-desktop/qmpmainwindow.ui3
-rw-r--r--qmidiplayer-desktop/qmpplugin.cpp29
-rw-r--r--visualization/qmpvisualization.cpp156
-rw-r--r--visualization/qmpvisualization.hpp28
11 files changed, 200 insertions, 79 deletions
diff --git a/ChangeLog b/ChangeLog
index 589b4aa..f0a23ef 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
diff --git a/README.md b/README.md
index 05de0e8..c878a1f 100644
--- a/README.md
+++ b/README.md
@@ -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: