From 8eac5088101595422753030b1b259411d63f83a8 Mon Sep 17 00:00:00 2001 From: Chris Xiong Date: Wed, 27 Apr 2016 23:45:24 +0800 Subject: Handle pitch bend in visualization. Handle mute and solo in the default visualization. Show file name in window title. A little plugin sdk documentaion... Remove stupid things. --- ChangeLog | 7 ++++++ core/qmpmidiplay.cpp | 6 +++++ core/qmpmidiplay.hpp | 3 +++ include/qmpcorepublic.hpp | 21 ++++++++++++++++ qmidiplayer-desktop/qmpmainwindow.cpp | 16 ++++++++++-- qmidiplayer-desktop/qmpmainwindow.hpp | 1 + qmidiplayer-desktop/qmpplugin.cpp | 13 ++++++++++ qmidiplayer-desktop/qmpplugin.hpp | 1 + qmidiplayer-desktop/qmpsettingswindow.cpp | 2 +- visualization/qmpvisualization.cpp | 41 +++++++++++-------------------- visualization/qmpvisualization.hpp | 9 +++++-- 11 files changed, 89 insertions(+), 31 deletions(-) diff --git a/ChangeLog b/ChangeLog index f0a23ef..c7d5fbc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2016-04-27 0.7.8 beta +Show file name in window title. +Handle pitch bend in visualization. +Handle mute and solo in the default visualization. +A little plugin sdk documentaion... +Remove stupid things. + 2016-04-26 0.7.8 beta Now the default visualization plugin works as expected. Avoid null pointers in the API implementation. diff --git a/core/qmpmidiplay.cpp b/core/qmpmidiplay.cpp index 5021640..bb09e4a 100644 --- a/core/qmpmidiplay.cpp +++ b/core/qmpmidiplay.cpp @@ -75,6 +75,7 @@ void CMidiPlayer::processEvent(const SEvent *e) if(~rpnid&&~rpnval) { if(rpnid==0)fluid_synth_pitch_wheel_sens(synth,e->type&0x0F,rpnval); + pbr[e->type&0x0F]=rpnval; rpnid=rpnval=-1; } chstatus[e->type&0x0F][e->p1]=e->p2; @@ -91,6 +92,7 @@ void CMidiPlayer::processEvent(const SEvent *e) fluid_synth_program_change(synth,e->type&0x0F,e->p1); break; case 0xE0://PW + pbv[e->type&0x0F]=e->p1; if(mappedoutput[e->type&0x0F]) mapper->pitchBend(mappedoutput[e->type&0x0F]-1,e->type&0x0F,e->p1); else @@ -328,6 +330,7 @@ void CMidiPlayer::playerInit() { ctempo=0x7A120;ctsn=4;ctsd=4;cks=0;dpt=ctempo*1000/divs; tceptr=0;tcstop=0;tcpaused=0;finished=0;mute=solo=0; + for(int i=0;i<16;++i)pbr[i]=2,pbv[i]=8192; sendSysEx=true;rpnid=rpnval=-1;memset(chstatus,0,sizeof(chstatus)); for(int i=0;i<16;++i) chstatus[i][7]=100,chstatus[i][11]=127, @@ -405,6 +408,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;} +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;} uint32_t CMidiPlayer::isFinished(){return finished;} @@ -457,6 +461,8 @@ void CMidiPlayer::setMute(int ch,bool m) {setBit(mute,ch,m?1:0);} void CMidiPlayer::setSolo(int ch,bool s) {setBit(solo,ch,s?1:0);} +bool CMidiPlayer::getChannelMask(int ch) +{return((mute>>ch)&1)||(solo&&!((solo>>ch)&1));} int CMidiPlayer::getCC(int ch,int id) { int ret=0; diff --git a/core/qmpmidiplay.hpp b/core/qmpmidiplay.hpp index 96dfd12..0587cf2 100644 --- a/core/qmpmidiplay.hpp +++ b/core/qmpmidiplay.hpp @@ -75,6 +75,7 @@ class CMidiPlayer //thread control uint32_t tceptr,tcpaused,tcstop,ct; uint32_t finished,resumed; + uint32_t pbr[16],pbv[16]; qmpMidiMapperRtMidi *mapper; int mappedoutput[16],deviceusage[16],deviceiid[128]; uint8_t chstate[16],chstatus[16][130];//0..127: cc 128: pc @@ -126,6 +127,7 @@ class CMidiPlayer uint32_t getTick(); uint32_t getRawTempo(); uint32_t getDivision(); + double getPitchBend(int ch); const char* getTitle(); const char* getCopyright(); @@ -139,6 +141,7 @@ class CMidiPlayer void getChannelPreset(int ch,int *b,int *p,char *name); void setMute(int ch,bool m); void setSolo(int ch,bool s); + bool getChannelMask(int ch); int getCC(int ch,int id); void setCC(int ch,int id,int val); void getReverbPara(double *r,double *d,double *w,double *l); diff --git a/include/qmpcorepublic.hpp b/include/qmpcorepublic.hpp index 8c67562..a8e3fa8 100644 --- a/include/qmpcorepublic.hpp +++ b/include/qmpcorepublic.hpp @@ -2,11 +2,15 @@ #define QMPCOREPUBLIC_H #include #include +//This struct is used by event reader callbacks and event handler callbacks +//as caller data struct struct SEventCallBackData { uint32_t time,type,p1,p2; SEventCallBackData(uint32_t _t,uint32_t _p1,uint32_t _p2,uint32_t _tm){type=_t;p1=_p1;p2=_p2;time=_tm;} }; +//Generic callback function that can be used for hooking the core. +//"userdata" is set when you register the callback function. class IMidiCallBack { public: @@ -14,6 +18,7 @@ class IMidiCallBack virtual void callBack(void* callerdata,void* userdata)=0; virtual ~IMidiCallBack(){} }; +//Main plugin interface. class qmpPluginIntf { public: @@ -24,6 +29,8 @@ class qmpPluginIntf virtual const char* pluginGetName(){return "";} virtual const char* pluginGetVersion(){return "";} }; +//Visualization plugin interface. If your plugin implements a visualization, +//you should implement this interface. class qmpVisualizationIntf { public: @@ -36,7 +43,11 @@ class qmpVisualizationIntf virtual void reset()=0; virtual ~qmpVisualizationIntf(){} }; +#ifdef QMP_MAIN extern "C"{ +#endif +//The API class provided by the core. Plugins use this class to interact with +//the core. class qmpPluginAPI { public: @@ -49,6 +60,9 @@ class qmpPluginAPI virtual uint32_t getCurrentPolyphone(); virtual uint32_t getMaxPolyphone(); virtual uint32_t getCurrentTimeStamp(); + virtual double getPitchBend(int ch); + virtual bool getChannelMask(int ch); + virtual std::string getTitle(); virtual int registerVisualizationIntf(qmpVisualizationIntf* intf); virtual void unregisterVisualizationIntf(int intfhandle); virtual int registerEventReaderIntf(IMidiCallBack* cb,void* userdata); @@ -62,6 +76,13 @@ class qmpPluginAPI virtual void registerOptionString(std::string desc,std::string key,std::string defaultval); virtual std::string getOptionString(std::string key); }; +#ifdef QMP_MAIN } +#endif +//The entry type for the plugin. Your plugin should implement +//qmpPluginIntf* qmpPluginGetInterface(qmpPluginAPI* api) +//as its entry point. A pointer to the core API is also passed to the plugin +//through the parameter. This function should return a pointer to a class +//that implementes the plugin interface (qmpPluginIntf). typedef qmpPluginIntf*(*qmpPluginEntry)(qmpPluginAPI*); #endif // QMPCOREPUBLIC_H diff --git a/qmidiplayer-desktop/qmpmainwindow.cpp b/qmidiplayer-desktop/qmpmainwindow.cpp index 53a2031..58b28b7 100644 --- a/qmidiplayer-desktop/qmpmainwindow.cpp +++ b/qmidiplayer-desktop/qmpmainwindow.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -240,7 +241,7 @@ void qmpMainWindow::updateWidgets() 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(); + QString fns=plistw->getNextItem();setWindowTitle(QUrl::fromLocalFile(fns).fileName().left(QUrl::fromLocalFile(fns).fileName().lastIndexOf('.'))+" - QMidiPlayer"); ui->lbFileName->setText(QUrl::fromLocalFile(fns).fileName().left(QUrl::fromLocalFile(fns).fileName().lastIndexOf('.'))); onfnChanged(); LOAD_FILE; @@ -296,6 +297,14 @@ void qmpMainWindow::updateWidgets() } QString qmpMainWindow::getFileName(){return ui->lbFileName->text();} +std::string qmpMainWindow::getTitle() +{ + if(!qmpSettingsWindow::getSettingsIntf())return ""; + return QTextCodec::codecForName( + qmpSettingsWindow::getSettingsIntf()->value("Midi/TextEncoding",""). + toString().toStdString().c_str())-> + toUnicode(player->getTitle()).toStdString(); +} void qmpMainWindow::playerSetup() { @@ -343,7 +352,7 @@ void qmpMainWindow::on_pbPlayPause_clicked() plistw->on_pbAdd_clicked(); fns=plistw->getFirstItem(); if(!fns.length())return(void)(playing=false); - } + }setWindowTitle(QUrl::fromLocalFile(fns).fileName().left(QUrl::fromLocalFile(fns).fileName().lastIndexOf('.'))+" - QMidiPlayer"); ui->lbFileName->setText(QUrl::fromLocalFile(fns).fileName().left(QUrl::fromLocalFile(fns).fileName().lastIndexOf('.'))); onfnChanged(); LOAD_FILE; @@ -473,6 +482,7 @@ void qmpMainWindow::on_pbPrev_clicked() 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(); + setWindowTitle(QUrl::fromLocalFile(fns).fileName().left(QUrl::fromLocalFile(fns).fileName().lastIndexOf('.'))+" - QMidiPlayer"); ui->lbFileName->setText(QUrl::fromLocalFile(fns).fileName().left(QUrl::fromLocalFile(fns).fileName().lastIndexOf('.'))); onfnChanged(); LOAD_FILE; @@ -502,6 +512,7 @@ void qmpMainWindow::on_pbNext_clicked() 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('.'))); + setWindowTitle(QUrl::fromLocalFile(fns).fileName().left(QUrl::fromLocalFile(fns).fileName().lastIndexOf('.'))+" - QMidiPlayer"); onfnChanged(); LOAD_FILE; char ts[100]; @@ -533,6 +544,7 @@ void qmpMainWindow::selectionChanged() chnlw->on_pbUnmute_clicked();chnlw->on_pbUnsolo_clicked(); QString fns=plistw->getSelectedItem(); ui->lbFileName->setText(QUrl::fromLocalFile(fns).fileName().left(QUrl::fromLocalFile(fns).fileName().lastIndexOf('.'))); + setWindowTitle(QUrl::fromLocalFile(fns).fileName().left(QUrl::fromLocalFile(fns).fileName().lastIndexOf('.'))+" - QMidiPlayer"); onfnChanged(); LOAD_FILE; char ts[100]; diff --git a/qmidiplayer-desktop/qmpmainwindow.hpp b/qmidiplayer-desktop/qmpmainwindow.hpp index a981559..bf55fb9 100644 --- a/qmidiplayer-desktop/qmpmainwindow.hpp +++ b/qmidiplayer-desktop/qmpmainwindow.hpp @@ -62,6 +62,7 @@ class qmpMainWindow:public QMainWindow QTimer* getTimer(){return timer;} bool isFinalizing(){return fin;} QString getFileName(); + std::string getTitle(); int pharseArgs(); int registerVisualizationIntf(qmpVisualizationIntf* intf); void unregisterVisualizationIntf(int handle); diff --git a/qmidiplayer-desktop/qmpplugin.cpp b/qmidiplayer-desktop/qmpplugin.cpp index a71b869..837f4db 100644 --- a/qmidiplayer-desktop/qmpplugin.cpp +++ b/qmidiplayer-desktop/qmpplugin.cpp @@ -13,6 +13,12 @@ qmpPluginAPI pluginAPI; qmpMainWindow* qmw; qmpSettingsWindow* qsw; #ifdef _WIN32 +void qmpPluginManager::scanPlugins() +{ + HANDLE dir; + std::vector cpluginpaths; + //FindFirstFile, FindNextFile, FindClose +} #else void qmpPluginManager::scanPlugins() { @@ -86,6 +92,13 @@ uint32_t qmpPluginAPI::getMaxPolyphone() {return qmw&&qmw->getPlayer()?qmw->getPlayer()->getMaxPolyphone():0;} uint32_t qmpPluginAPI::getCurrentTimeStamp() {return qmw&&qmw->getPlayer()?qmw->getPlayer()->getTick():0;} +double qmpPluginAPI::getPitchBend(int ch) +{return qmw&&qmw->getPlayer()?qmw->getPlayer()->getPitchBend(ch):0;} +bool qmpPluginAPI::getChannelMask(int ch) +{return qmw&&qmw->getPlayer()?qmw->getPlayer()->getChannelMask(ch):false;} +std::string qmpPluginAPI::getTitle() +{return qmw?qmw->getTitle():"";} + int qmpPluginAPI::registerEventHandlerIntf(IMidiCallBack *cb,void *userdata) {return qmw->getPlayer()->setEventHandlerCB(cb,userdata);} void qmpPluginAPI::unregisterEventHandlerIntf(int intfhandle) diff --git a/qmidiplayer-desktop/qmpplugin.hpp b/qmidiplayer-desktop/qmpplugin.hpp index 8d14596..81a16a7 100644 --- a/qmidiplayer-desktop/qmpplugin.hpp +++ b/qmidiplayer-desktop/qmpplugin.hpp @@ -1,5 +1,6 @@ #ifndef QMPPLUGIN_H #define QMPPLUGIN_H +#define QMP_MAIN #include #include #include "../include/qmpcorepublic.hpp" diff --git a/qmidiplayer-desktop/qmpsettingswindow.cpp b/qmidiplayer-desktop/qmpsettingswindow.cpp index 2e6af6d..985fb6e 100644 --- a/qmidiplayer-desktop/qmpsettingswindow.cpp +++ b/qmidiplayer-desktop/qmpsettingswindow.cpp @@ -25,7 +25,7 @@ qmpSettingsWindow::qmpSettingsWindow(QWidget *parent) : qmpSettingsWindow::~qmpSettingsWindow() { - delete settings; + delete settings;settings=NULL; delete ui; } diff --git a/visualization/qmpvisualization.cpp b/visualization/qmpvisualization.cpp index 8c8033c..1e64b22 100644 --- a/visualization/qmpvisualization.cpp +++ b/visualization/qmpvisualization.cpp @@ -52,6 +52,8 @@ void qmpVisualization::showThread() tdscn=sm->smTargetCreate(800,600); if(!font.loadTTF("/usr/share/fonts/truetype/freefont/FreeMono.ttf",16)) printf("W: Font load failed.\n"); + if(!font2.loadTTF("/usr/share/fonts/truetype/wqy/wqy-microhei.ttc",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; sm->smMainLoop(); @@ -66,6 +68,7 @@ void qmpVisualization::close() rendererTh->join(); sm->smFinale(); font.releaseTTF(); + font2.releaseTTF(); sm->smTextureFree(chequer); sm->smTargetFree(tdscn); sm->smRelease(); @@ -132,8 +135,12 @@ bool qmpVisualization::update() if(((double)pool[i]->tcs-ctk)*lpt>viewdist*2)break; if(fabs((double)pool[i]->tcs-ctk)*lpttce-ctk)*lptkey-64),pool[i]->ch*-2.,((double)pool[i]->tce-ctk)*lpt); - smvec3d b(((double)pool[i]->key-64)+.9,pool[i]->ch*-2.+.6,((double)pool[i]->tcs-ctk)*lpt); + if(api->getChannelMask(pool[i]->ch))continue; + smvec3d a(((double)pool[i]->key-64),15+pool[i]->ch*-3.,((double)pool[i]->tce-ctk)*lpt); + smvec3d b(((double)pool[i]->key-64)+.9,15+pool[i]->ch*-3.+.6,((double)pool[i]->tcs-ctk)*lpt); + if(pool[i]->tcs<=ctk&&pool[i]->tce>=ctk) + a.x=((double)pool[i]->key-64+api->getPitchBend(pool[i]->ch)), + b.x=((double)pool[i]->key-64+api->getPitchBend(pool[i]->ch))+.9; if(((double)pool[i]->tce-pool[i]->tcs)*lpttcs-ctk)*lpt-minnotelength/100.; drawCube(a,b,SETA(chcolors[pool[i]->ch],pool[i]->vel),0); } @@ -151,6 +158,11 @@ 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); + wchar_t ws[1024];memset(ws,0,sizeof(ws)); + mbstowcs(ws,api->getTitle().c_str(),1024); + font2.updateString(L"Title: %ls",ws); + font2.render(1,536,0xFFFFFFFF,ALIGN_LEFT); + font2.render(0,535,0xFF000000,ALIGN_LEFT); font.updateString(L"Tempo: %.2f",api->getRealTempo()); font.render(1,556,0xFFFFFFFF,ALIGN_LEFT); font.render(0,555,0xFF000000,ALIGN_LEFT); @@ -225,7 +237,7 @@ void qmpVisualization::init() hcb=new CHandlerCallBack(this); vi=new CDemoVisualization(this); h=new CMidiVisualHandler(this); - closeh=new RefuseCloseHandler(); + closeh=new CloseHandler(this); api->registerVisualizationIntf(vi); api->registerEventReaderIntf(cb,NULL); api->registerEventHandlerIntf(hcb,NULL); @@ -256,26 +268,3 @@ void qmpVisualization::pushNoteOff(uint32_t tc,uint32_t ch,uint32_t key) pool.push_back(ne); if(tc>fintk)fintk=tc; } - -//dummy implementations of the api... -uint32_t qmpPluginAPI::getDivision(){return 0;} -uint32_t qmpPluginAPI::getRawTempo(){return 0;} -double qmpPluginAPI::getRealTempo(){return 0;} -uint32_t qmpPluginAPI::getTimeSig(){return 0;} -int qmpPluginAPI::getKeySig(){return 0;} -uint32_t qmpPluginAPI::getNoteCount(){return 0;} -uint32_t qmpPluginAPI::getCurrentPolyphone(){return 0;} -uint32_t qmpPluginAPI::getMaxPolyphone(){return 0;} -uint32_t qmpPluginAPI::getCurrentTimeStamp(){return 0;} -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 438b98a..afc57a4 100644 --- a/visualization/qmpvisualization.hpp +++ b/visualization/qmpvisualization.hpp @@ -35,6 +35,7 @@ struct MidiVisualEvent class qmpVisualization:public qmpPluginIntf { friend class CHandlerCallBack; + friend class CloseHandler; private: qmpPluginAPI* api; CReaderCallBack* cb; @@ -47,7 +48,7 @@ class qmpVisualization:public qmpPluginIntf SMELT *sm; SMTRG tdscn; SMTEX chequer; - smTTFont font; + smTTFont font,font2; float pos[3],rot[3],lastx,lasty; uint32_t ctc,ctk,fintk,elb; double etps; @@ -83,8 +84,12 @@ class CMidiVisualHandler:public smHandler bool handlerFunc(){return p->update();} }; -class RefuseCloseHandler:public smHandler +class CloseHandler:public smHandler { + private: + qmpVisualization *p; + public: + CloseHandler(qmpVisualization* par){p=par;} public: bool handlerFunc(){return true;} }; -- cgit v1.2.3