From b79c4b7e3cab3711e87ba9e28fa8423a84ea7efa Mon Sep 17 00:00:00 2001 From: Chris Xiong Date: Tue, 27 Dec 2016 23:15:15 +0800 Subject: First official version with experimental support for the visualization plugin on Windows. Fixed several critical bugs causing the plugin to crash QMP. --- ChangeLog | 7 ++++- INSTALL | 7 +++-- README.md | 11 ++++++- debian/changelog | 13 ++++++++ debian/control | 6 +++- doc/APIdoc.md | 47 +++++++++++++++++++++++++++++ doc/version_internal.html | 4 +-- qmidiplayer-desktop/qmidiplayer-desktop.pro | 1 + qmidiplayer-desktop/qmphelpwindow.cpp | 1 + qmidiplayer-desktop/qmphelpwindow.hpp | 5 +++ qmidiplayer.pro | 13 +++----- visualization/extrasmeltutils.cpp | 1 + visualization/qmpvisualization.cpp | 14 ++++++--- visualization/visualization.pro | 23 +++++++++++--- 14 files changed, 128 insertions(+), 25 deletions(-) create mode 100644 doc/APIdoc.md diff --git a/ChangeLog b/ChangeLog index ac03d46..6d7c17a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,9 @@ -2016-09-23 0.8.3 alpha +2016-12-27 0.8.3 alpha +First official version with experimental support for +the visualization plugin on Windows. Fixed several +critical bugs causing the plugin to crash QMP. + +2016-12-11 0.8.3 alpha Update the preset selection dialog to improve support for external MIDI devices. diff --git a/INSTALL b/INSTALL index 83c734b..631d26d 100644 --- a/INSTALL +++ b/INSTALL @@ -1,9 +1,12 @@ Use qmake or Qt Creator. Dependencies: -> libfluidsynth 1.1.4+, Qt5 (not sure whether 4 will work) and RtMidi. +> libfluidsynth 1.1.4+, Qt5 and RtMidi. -C++11 is required to build the project. +C++11 is required to build the project. Qt4 will not work without +several tweaks. To build the default visualization plugin, you need the latest SMELT, which can be found [here](https://github.com/BearKidsTeam/SMELT). +Some dependencies in the project file are hard-coded paths. You may +have to modify them first. diff --git a/README.md b/README.md index c878a1f..ba87e64 100644 --- a/README.md +++ b/README.md @@ -9,10 +9,19 @@ Features: * Playlists * Editing synthesizer effects * Rendering midi to wave file -* Visualization using SMELT (currently Linux only) +* Visualization using SMELT (highly experimental Windows version now available) * MIDI mapping (based on RtMidi) Tested on Debian sid and Windows Vista~10. A QML version is now in construction. It's only a technology preview and should not be used for non-testing purpose. + +# Building QMidiPlayer +Please follow the instruction found in the file "INSTALL". + +_Warning: building QMidiPlayer for Windows is somehow a formidable task._ +_Go ahead if you are ready to deal with metaphysics._ + +# Manual +Try the button in the top-right corner. diff --git a/debian/changelog b/debian/changelog index 00d2283..8e099e7 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,16 @@ +qmidiplayer (0.8.3-2) UNRELEASED; urgency=low + + * New upstream release. + + -- chrisoft Tue, 27 Dec 2016 23:14:32 +0800 + + +qmidiplayer (0.8.3-1) UNRELEASED; urgency=low + + * New upstream release. + + -- chrisoft Fri, 28 Oct 2016 16:41:20 +0800 + qmidiplayer (0.8.3-0) UNRELEASED; urgency=low * New upstream release. diff --git a/debian/control b/debian/control index 51e40c3..2773d44 100644 --- a/debian/control +++ b/debian/control @@ -12,7 +12,11 @@ Build-Depends: debhelper (>= 9), qml-module-qtquick-window2, qml-module-qtquick2, libqt5qml5, - librtmidi-dev + librtmidi-dev, + libglfw3-dev, + libglew-dev, + libfreetype6-dev, + zlib1g-dev Package: qmidiplayer Architecture: any diff --git a/doc/APIdoc.md b/doc/APIdoc.md new file mode 100644 index 0000000..043c1c0 --- /dev/null +++ b/doc/APIdoc.md @@ -0,0 +1,47 @@ +# The API documentation of QMidiPlayer for plugin developers + +*This manual is not yet complete. It's only a working draft for the always-changing plugin system in QMP.* +*Handle with care.* + +# 0. Overview + +Plugin for QMidiPlayer is a dynamically-loaded library that exports the symbol "qmpPluginGetInterface". +Before starting developing your own plugin, make sure to have a look at the sample plugin in the "sample-plugin" folder. + +# 1. "QMidiPlayer Plugin SDK" + +SDK for developing QMidiPlayer plugins is merely the "qmpcorepublic.hpp" header found in the "include" directory in +the source tree. It includes classes used by QMidiPlayer's internal plugin infrastructure. + +# 2. Basics for a working plugin. + +First of all, you should make your library distinct from other libraries that are not QMidiPlayer plugins. You can achive +it by exporting the symbol "qmpPluginGetInterface". Specifically, what you should do is to add the following snipplet to +somewhere of your code: + +> extern "C"{ +> EXPORTSYM qmpPluginIntf* qmpPluginGetInterface(qmpPluginAPI* api) +> //semicolon or implementation here. +> } + +The EXPORTSYM macro tells the compiler to export the following symbol. qmpPluginIntf is the abstract class which every +plugin class should derive from. The parameter api provides access to QMidiPlayer's plugin API, which should be stored +for future use. + +Next you should create your own plugin class which implements the abstract class "qmpPluginIntf". + +# 3. A Peek into the class "qmpPluginIntf" + +It has 6 public members: one default constructor, one default destructor and four methods: + +- void init() + Called on start up if the plugin is loaded successfully and enabled. +- void deinit() + Called on shutdown if the plugin is enabled. +- const char* pluginGetName() + This function should return the display name of the plugin. +- const char* pluginGetVersion() + This function should return the version of the plugin, which will be shown in the plugin manager. + +Your plugin is expected to register handlers and functionalities when init() is called by the host, +and do clean-up jobs when deinit() is caled. diff --git a/doc/version_internal.html b/doc/version_internal.html index e68a10e..ddd32c8 100644 --- a/doc/version_internal.html +++ b/doc/version_internal.html @@ -10,11 +10,11 @@ QMidiPlayer -- An MIDI player based on fluidsynth and Qt.
Written by Chris Xiong.
Version APP_VERSION
- Built at BUILD_DATE
+ Built at BUILD_DATE on BUILD_MACHINE
libfluidsynth version: RT_FLUIDSYNTH_VERSION (Built against CT_FLUIDSYNTH_VERSION)
Qt version: RT_QT_VERSION_STR (Built against CT_QT_VERSION_STR)

Return - \ No newline at end of file + diff --git a/qmidiplayer-desktop/qmidiplayer-desktop.pro b/qmidiplayer-desktop/qmidiplayer-desktop.pro index 1aa1a27..5572479 100644 --- a/qmidiplayer-desktop/qmidiplayer-desktop.pro +++ b/qmidiplayer-desktop/qmidiplayer-desktop.pro @@ -55,6 +55,7 @@ FORMS += qmpmainwindow.ui \ qmphelpwindow.ui TRANSLATIONS += translations/qmp_zh_CN.ts +DEFINES += BUILD_MACHINE=$${QMAKE_HOST.name} unix{ isEmpty(PREFIX) { diff --git a/qmidiplayer-desktop/qmphelpwindow.cpp b/qmidiplayer-desktop/qmphelpwindow.cpp index c9f4667..b2346dd 100644 --- a/qmidiplayer-desktop/qmphelpwindow.cpp +++ b/qmidiplayer-desktop/qmphelpwindow.cpp @@ -40,6 +40,7 @@ void qmpHelpWindow::on_textBrowser_sourceChanged(const QUrl &src) s.replace("RT_FLUIDSYNTH_VERSION",fluid_version_str()); s.replace("APP_VERSION",APP_VERSION); s.replace("BUILD_DATE",parseDate(__DATE__).c_str()); + s.replace("BUILD_MACHINE",sss(BUILD_MACHINE)); ui->textBrowser->setHtml(s); } } diff --git a/qmidiplayer-desktop/qmphelpwindow.hpp b/qmidiplayer-desktop/qmphelpwindow.hpp index 690d126..61d9963 100644 --- a/qmidiplayer-desktop/qmphelpwindow.hpp +++ b/qmidiplayer-desktop/qmphelpwindow.hpp @@ -3,6 +3,11 @@ #include #define APP_VERSION "0.8.3" +#ifndef BUILD_MACHINE +#define BUILD_MACHINE UNKNOWN +#endif +#define ss(s) #s +#define sss(s) ss(s) namespace Ui { class qmpHelpWindow; diff --git a/qmidiplayer.pro b/qmidiplayer.pro index 62515f5..0f4a262 100644 --- a/qmidiplayer.pro +++ b/qmidiplayer.pro @@ -2,15 +2,12 @@ TEMPLATE = subdirs !android { SUBDIRS = \ - qmidiplayer-desktop \ - qmidiplayer-lite \ - sample-plugin + qmidiplayer-desktop \ + qmidiplayer-lite \ + sample-plugin \ + visualization } android { SUBDIRS = \ - qmidiplayer-lite -} - -!win32 { -SUBDIRS += visualization\ + qmidiplayer-lite } diff --git a/visualization/extrasmeltutils.cpp b/visualization/extrasmeltutils.cpp index 18fafa9..6c8dd93 100644 --- a/visualization/extrasmeltutils.cpp +++ b/visualization/extrasmeltutils.cpp @@ -61,6 +61,7 @@ void smEntity3DBuffer::addTransformedEntity(smEntity3D *entity,smMatrix t,smvec3 } void smEntity3DBuffer::drawBatch() { + if(!vertices.size())return; sm->smDrawCustomIndexedVertices(&vertices[0],&indices[0],vertices.size(),indices.size(),BLEND_ALPHABLEND,0); vertices.clear();indices.clear(); } diff --git a/visualization/qmpvisualization.cpp b/visualization/qmpvisualization.cpp index 29a1925..f17a92a 100644 --- a/visualization/qmpvisualization.cpp +++ b/visualization/qmpvisualization.cpp @@ -14,8 +14,8 @@ int wwidth=800,wheight=600,wsupersample=1,wmultisample=0,showparticle=1; int horizontal=1,flat=0,osdpos=0,fontsize=16; int fov=60,vsync=1,tfps=60,usespectrum=0; DWORD chkrtint=0xFF999999; -const char* minors="abebbbf c g d a e b f#c#g#d#a#"; -const char* majors="CbGbDbAbEbBbF C G D A E B F#C#"; +const wchar_t* minors=L"abebbbf c g d a e b f#c#g#d#a#"; +const wchar_t* majors=L"CbGbDbAbEbBbF C G D A E B F#C#"; double fpoffsets[]={1,18,28,50,55,82,98,109,130,137,161,164,191}; double froffsets[]={0,18,33,50,65,82,98,113,130,145,161,176,191}; DWORD iccolors[]={0XFFFF0000,0XFFFF8000,0XFFFFBF00,0XFFFFFF00, @@ -131,12 +131,15 @@ void qmpVisualization::showThread() tdparticles=sm->smTargetCreate(wwidth*wsupersample,wheight*wsupersample,wmultisample); if(!font.loadTTF("/usr/share/fonts/truetype/freefont/FreeMono.ttf",fontsize)) if(!font.loadTTF("/usr/share/fonts/gnu-free-fonts/FreeMono.otf",fontsize)) + if(!font.loadTTF("C:/Windows/Fonts/cour.ttf",fontsize)) printf("W: Font load failed.\n"); if(!fonthdpi.loadTTF("/usr/share/fonts/truetype/freefont/FreeMono.ttf",180)) if(!fonthdpi.loadTTF("/usr/share/fonts/gnu-free-fonts/FreeMono.otf",180)) + if(!fonthdpi.loadTTF("C:/Windows/Fonts/cour.ttf",180)) printf("W: Font load failed.\n"); if(!font2.loadTTF("/usr/share/fonts/truetype/wqy/wqy-microhei.ttc",fontsize)) if(!font2.loadTTF("/usr/share/fonts/wenquanyi/wqy-microhei/wqy-microhei.ttc",fontsize)) + if(!font2.loadTTF("C:/Windows/Fonts/segoeui.ttf",fontsize)) printf("W: Font load failed.\n"); if(horizontal) { @@ -175,7 +178,7 @@ void qmpVisualization::close() }else return; if(showpiano&&!horizontal)for(int i=0;i<16;++i)delete p3d[i]; - if(showparticle&&!horizontal)for(int i=0;i>16;++i)for(int j=0;j<128;++j)delete pss[i][j]; + if(showparticle&&!horizontal)for(int i=0;i>16;++i)for(int j=0;j<128;++j){delete pss[i][j];pss[i][j]=0;} if(noteappearance==1)delete nebuf; sm->smFinale(); if(savevp) @@ -657,7 +660,7 @@ bool qmpVisualization::update() } if(osdpos==4){sm->smRenderEnd();return shouldclose;} int t,r;t=api->getKeySig();r=(int8_t)((t>>8)&0xFF)+7;t&=0xFF; - std::string ts(t?minors:majors);ts=ts.substr(2*r,2); + std::wstring ts(t?minors:majors);ts=ts.substr(2*r,2); int step=int(1.25*fontsize),xp=(osdpos&1)?wwidth-step-1:1,yp=osdpos<2?wheight-step*5-4:step+4,align=osdpos&1?ALIGN_RIGHT:ALIGN_LEFT; font2.updateString(L"Title: %ls",api->getWTitle().c_str()); font2.render(xp,yp,0.5,0xFFFFFFFF,align); @@ -665,7 +668,7 @@ bool qmpVisualization::update() font.updateString(L"Time Sig: %d/%d",api->getTimeSig()>>8,1<<(api->getTimeSig()&0xFF)); font.render(xp,yp+=step,0.5,0xFFFFFFFF,align); font.render(xp-1,yp-1,0.5,0xFF000000,align); - font.updateString(L"Key Sig: %s",ts.c_str()); + font.updateString(L"Key Sig: %ls",ts.c_str()); font.render(xp,yp+=step,0.5,0xFFFFFFFF,align); font.render(xp-1,yp-1,0.5,0xFF000000,align); font.updateString(L"Tempo: %.2f",api->getRealTempo()); @@ -776,6 +779,7 @@ void qmpVisualization::init() accolors[i]=api->getOptionUint("Visualization/chActiveColor"+std::to_string(i)); iccolors[i]=api->getOptionUint("Visualization/chInactiveColor"+std::to_string(i)); } + memset(pss,0,sizeof(pss)); } void qmpVisualization::deinit() { diff --git a/visualization/visualization.pro b/visualization/visualization.pro index 65f1a48..fedd636 100644 --- a/visualization/visualization.pro +++ b/visualization/visualization.pro @@ -32,9 +32,22 @@ unix { QMAKE_LFLAGS_RELEASE += -O3 res.path = $$DATADIR/qmidiplayer/img res.files += ../img/chequerboard.png ../img/particle.png ../img/kb_128.png + #well... + INCLUDEPATH += /home/chrisoft/devel/SMELT/include/ /usr/include/freetype2 + LIBS += -L/home/chrisoft/devel/SMELT/smelt/glfw/ + LIBS += -L/home/chrisoft/devel/SMELT/extensions/ + LIBS += -lstdc++ -lfreetype -lz -lsmeltext -lsmelt-dumb -lCxImage -ljpeg -lpng -lglfw -lGLEW -lGL +} +win32 { + #Change these before producing your own build! + INCLUDEPATH += "C:\Users\Chris Xiong\Documents\devel\SMELT\include" + INCLUDEPATH += "C:\Users\Chris Xiong\Documents\devel\freetype-2.7\include" + INCLUDEPATH += "C:\Users\Chris Xiong\Documents\devel\zlib-1.2.8" + CONFIG(release, debug|release){ + LIBS += -L"C:\Users\Chris Xiong\Documents\devel\SMELT\msvc\libdeps" + LIBS += -lfreetype27MT -lzlib -lsmeltext -lsmelt -ljpeg-static -llibpng16 -lglfw3 -lglew32s -lopengl32 -luser32 -lgdi32 -lshell32 + }else{ + LIBS += -L"C:\Users\Chris Xiong\Documents\devel\SMELT\msvc\libdepsd" + LIBS += -lfreetype27MTd -lzlib -lsmeltextd -lsmeltd -ljpeg-static -llibpng16 -lglfw3 -lglew32sd -lopengl32 -luser32 -lgdi32 -lshell32 + } } -#well... -INCLUDEPATH += /home/chrisoft/devel/SMELT/include/ /usr/include/freetype2 -LIBS += -L/home/chrisoft/devel/SMELT/smelt/glfw/ -LIBS += -L/home/chrisoft/devel/SMELT/extensions/ -LIBS += -lstdc++ -lfreetype -lz -lsmeltext -lsmelt-dumb -lCxImage -ljpeg -lpng -lglfw -lGLEW -lGL -- cgit v1.2.3