aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Chris Xiong <chirs241097@gmail.com> 2016-04-27 23:45:24 +0800
committerGravatar Chris Xiong <chirs241097@gmail.com> 2016-04-27 23:45:24 +0800
commit8eac5088101595422753030b1b259411d63f83a8 (patch)
tree43c4c3e9b92657bbf6c7c55cf75d297ec85a5b7f
parentdfcc193d4070c99bf217ac74a492160968dba766 (diff)
downloadQMidiPlayer-8eac5088101595422753030b1b259411d63f83a8.tar.xz
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.
-rw-r--r--ChangeLog7
-rw-r--r--core/qmpmidiplay.cpp6
-rw-r--r--core/qmpmidiplay.hpp3
-rw-r--r--include/qmpcorepublic.hpp21
-rw-r--r--qmidiplayer-desktop/qmpmainwindow.cpp16
-rw-r--r--qmidiplayer-desktop/qmpmainwindow.hpp1
-rw-r--r--qmidiplayer-desktop/qmpplugin.cpp13
-rw-r--r--qmidiplayer-desktop/qmpplugin.hpp1
-rw-r--r--qmidiplayer-desktop/qmpsettingswindow.cpp2
-rw-r--r--visualization/qmpvisualization.cpp41
-rw-r--r--visualization/qmpvisualization.hpp9
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 <cstdint>
#include <string>
+//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 <QFileInfo>
#include <QMimeData>
#include <QFont>
+#include <QTextCodec>
#include <QDirIterator>
#include <QDesktopWidget>
#include <QMessageBox>
@@ -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<std::string> 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 <string>
#include <vector>
#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)*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.+.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)*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);
}
@@ -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;}
};