aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Chris Xiong <chirs241097@gmail.com> 2020-04-29 11:25:58 +0800
committerGravatar Chris Xiong <chirs241097@gmail.com> 2020-04-29 11:25:58 +0800
commit65a8bde4e4beca860a13491e94631dc16b5e71af (patch)
treed92df4a6538af18c4231dca015a6f504d8c65cd2
parent73020aae5bf0b7dd49c78880e2768deb19181b81 (diff)
downloadQMidiPlayer-65a8bde4e4beca860a13491e94631dc16b5e71af.tar.xz
Decouple CMidiPlayer and qmpMidiOutFluid.
Visualization renderer should no longer depend on the fluidsynth library. Reworked the "wait voice" option: now it only takes effect if an automatic track switch happens. Actually process events while waiting for async operation to finish.
-rw-r--r--core/qmpmidiplay.cpp39
-rw-r--r--core/qmpmidiplay.hpp13
-rw-r--r--qmidiplayer-desktop/CMakeLists.txt1
-rw-r--r--qmidiplayer-desktop/qmpefxwindow.cpp2
-rw-r--r--qmidiplayer-desktop/qmpmainwindow.cpp88
-rw-r--r--qmidiplayer-desktop/qmpmainwindow.hpp7
-rw-r--r--qmidiplayer-desktop/qmpplugin.cpp4
-rw-r--r--qmidiplayer-desktop/qmppresetselect.cpp3
8 files changed, 88 insertions, 69 deletions
diff --git a/core/qmpmidiplay.cpp b/core/qmpmidiplay.cpp
index cb9e726..01045c1 100644
--- a/core/qmpmidiplay.cpp
+++ b/core/qmpmidiplay.cpp
@@ -3,7 +3,6 @@
#include <algorithm>
#include <chrono>
#include <thread>
-#include <fluidsynth.h>
#include "qmpmidiplay.hpp"
#ifdef _WIN32
#define NOMINMAX
@@ -40,7 +39,6 @@ bool CMidiPlayer::processEvent(const SEvent *e)
{
if(rpnid[ch]==0)
{
- internalFluid->rpnMessage(ch,0,rpnval[ch]<<7);
mididev[mappedoutput[ch]].dev->rpnMessage(ch,0,rpnval[ch]<<7);
pbr[ch]=rpnval[ch];
}
@@ -230,8 +228,8 @@ void CMidiPlayer::playEvents()
if(tcstop||!midiReaders)break;
ct=getEvent(tceptr)->time;
}
- while(!tcstop&&(waitvoice&&internalFluid->getPolyphone()>0))std::this_thread::sleep_for(std::chrono::milliseconds(2));
- finished=1;
+ if(tceptr>=ecnt)
+ finished=1;
}
void CMidiPlayer::fileTimer1Pass()
{
@@ -284,8 +282,7 @@ void CMidiPlayer::fileTimer2Pass()
CMidiPlayer::CMidiPlayer()
{
midiReaders=new CMidiFileReaderCollection();
- resumed=false;midiFile=nullptr;internalFluid=new qmpMidiOutFluid();
- registerMidiOutDevice(internalFluid,"Internal FluidSynth");
+ resumed=false;midiFile=nullptr;
waitvoice=true;
event_handlers_id=event_read_handlers_id=file_read_finish_hooks_id=0;
memset(eventHandlerCB,0,sizeof(eventHandlerCB));
@@ -294,8 +291,7 @@ CMidiPlayer::CMidiPlayer()
memset(eventReaderCBuserdata,0,sizeof(eventReaderCBuserdata));
memset(fileReadFinishCB,0,sizeof(fileReadFinishCB));
memset(fileReadFinishCBuserdata,0,sizeof(fileReadFinishCBuserdata));
- memset(mappedoutput,0,sizeof(mappedoutput));
- mididev[0].refcnt=16;
+ memset(mappedoutput,0xff,sizeof(mappedoutput));
memset(chstatus,0,sizeof(chstatus));
for(int i=0;i<16;++i)
memset(chstatus[i],0xff,128*sizeof(uint8_t));
@@ -306,12 +302,6 @@ CMidiPlayer::CMidiPlayer()
}
CMidiPlayer::~CMidiPlayer()
{
- if(internalFluid)
- {
- internalFluid->deviceDeinit();
- delete internalFluid;
- internalFluid=nullptr;
- }
if(midiFile)delete midiFile;delete midiReaders;
}
void CMidiPlayer::playerPanic(bool reset)
@@ -356,7 +346,7 @@ bool CMidiPlayer::playerLoadFile(const char* fn)
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;
+ tceptr=0;tcstop=false;tcpaused=0;finished=0;mute=solo=0;
for(int i=0;i<16;++i)pbr[i]=2,pbv[i]=8192;
sendSysEx=true;memset(rpnid,0xFF,sizeof(rpnid));memset(rpnval,0xFF,sizeof(rpnval));
memset(chstatus,0,sizeof(chstatus));
@@ -365,7 +355,7 @@ void CMidiPlayer::playerInit()
}
void CMidiPlayer::playerDeinit()
{
- tceptr=0;tcstop=1;tcpaused=0;
+ tceptr=0;tcstop=true;tcpaused=0;
delete midiFile;midiFile=nullptr;
}
void CMidiPlayer::playerThread()
@@ -380,7 +370,7 @@ uint32_t CMidiPlayer::getTCeptr(){return tceptr;}
void CMidiPlayer::setTCeptr(uint32_t ep,uint32_t st)
{
resumed=true;
- if(ep==ecnt)tcstop=1;else tceptr=ep;
+ if(ep==ecnt)tcstop=true;else tceptr=ep;
for(int i=0;i<16;++i)
{
qmpMidiOutDevice* dest=mididev[mappedoutput[i]].dev;
@@ -388,16 +378,12 @@ void CMidiPlayer::setTCeptr(uint32_t ep,uint32_t st)
{
if(~ccstamps[st][i][j])
{
- internalFluid->basicMessage(0xB0|i,j,ccstamps[st][i][j]);
dest->basicMessage(0xB0|i,j,ccstamps[st][i][j]);
chstatus[i][j]=ccstamps[st][i][j];
}
}
- internalFluid->basicMessage(0xC0|i,ccstamps[st][i][128],0);
dest->basicMessage(0xC0|i,ccstamps[st][i][128],0);
chstatus[i][128]=ccstamps[st][i][128];
- //fluid_synth_pitch_bend(synth,i,ccstamps[st][i][130]);
- internalFluid->rpnMessage(i,0,ccstamps[st][i][134]<<7);
dest->rpnMessage(i,0,ccstamps[st][i][134]<<7);
pbr[i]=ccstamps[st][i][134];
ctempo=ccstamps[st][0][131];dpt=ctempo*1000./divs;
@@ -421,13 +407,8 @@ 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;}
+bool CMidiPlayer::stopFlag(){return tcstop;}
void CMidiPlayer::setResumed(){resumed=true;}
-void CMidiPlayer::setWaitVoice(bool wv){waitvoice=wv;}
-
-void CMidiPlayer::registerFluidOptions(qmpPluginAPI *coreapi)
-{
- internalFluid->registerOptions(coreapi);
-}
void CMidiPlayer::setChannelPreset(int ch,int b,int p)
{
@@ -471,8 +452,6 @@ void CMidiPlayer::setCC(int ch,int id,int val)
mididev[mappedoutput[ch]].dev->basicMessage(0xB0|ch,id,val);
}
-qmpMidiOutFluid* CMidiPlayer::fluid(){return internalFluid;}
-
void CMidiPlayer::registerMidiOutDevice(qmpMidiOutDevice* dev,std::string name)
{
SMidiDev d;
@@ -508,6 +487,8 @@ qmpMidiOutDevice* CMidiPlayer::getChannelOutputDevice(int ch)
void CMidiPlayer::setChannelOutput(int ch,int outid)
{
int origoutput=mappedoutput[ch];
+ if(origoutput==outid)
+ return;
SMidiDev& dnew=mididev[outid];
dnew.dev->onMapped(ch,++dnew.refcnt);
for(int i=0;i<124;++i)
diff --git a/core/qmpmidiplay.hpp b/core/qmpmidiplay.hpp
index f896338..83a7128 100644
--- a/core/qmpmidiplay.hpp
+++ b/core/qmpmidiplay.hpp
@@ -9,9 +9,7 @@
#include <utility>
#include <vector>
#define QMP_MAIN
-#include "../include/qmpcorepublic.hpp"
-#include "qmpmidioutrtmidi.hpp"
-#include "qmpmidioutfluid.hpp"
+#include "qmpcorepublic.hpp"
class CMidiPlayer;
class CSMFReader:public qmpFileReader
{
@@ -66,12 +64,12 @@ class CMidiPlayer
double ftime;
bool sendSysEx,waitvoice;
uint8_t chstatus[16][130];//0..127: cc 128: pc
- qmpMidiOutFluid* internalFluid;
uint32_t ctempo,ctsn,ctsd,divs,cks;
double dpt;//time per tick
//raw tempo, timesig num., timesig den., division, keysig
//thread control
- uint32_t tceptr,tcpaused,tcstop,ct;
+ uint32_t tceptr,tcpaused,ct;
+ bool tcstop;
uint32_t finished,resumed;
uint32_t pbr[16],pbv[16];
//playback correction
@@ -123,9 +121,8 @@ class CMidiPlayer
uint32_t getTCpaused();
void setTCpaused(uint32_t ps);
uint32_t isFinished();
+ bool stopFlag();
void setResumed();
- void setWaitVoice(bool wv);
- void registerFluidOptions(qmpPluginAPI *coreapi);
double getFtime();
void getCurrentTimeSignature(int *n,int *d);
@@ -150,8 +147,6 @@ class CMidiPlayer
uint16_t getCC(int ch,int id);
void setCC(int ch,int id,int val);
- qmpMidiOutFluid* fluid();
-
void registerMidiOutDevice(qmpMidiOutDevice* dev,std::string name);
void unregisterMidiOutDevice(std::string name);
std::vector<std::string> getMidiOutDevices();
diff --git a/qmidiplayer-desktop/CMakeLists.txt b/qmidiplayer-desktop/CMakeLists.txt
index c34f258..419bb05 100644
--- a/qmidiplayer-desktop/CMakeLists.txt
+++ b/qmidiplayer-desktop/CMakeLists.txt
@@ -58,6 +58,7 @@ set(CMAKE_AUTOUIC ON)
include_directories(${fluidsynth_INCLUDE_DIRS})
include_directories(${rtmidi_INCLUDE_DIRS})
include_directories(${PROJECT_SOURCE_DIR}/include/)
+include_directories(${PROJECT_SOURCE_DIR}/core/)
cmake_host_system_information(RESULT build_host QUERY HOSTNAME)
add_definitions(-DBUILD_MACHINE=${build_host})
diff --git a/qmidiplayer-desktop/qmpefxwindow.cpp b/qmidiplayer-desktop/qmpefxwindow.cpp
index f8731ba..7691756 100644
--- a/qmidiplayer-desktop/qmpefxwindow.cpp
+++ b/qmidiplayer-desktop/qmpefxwindow.cpp
@@ -103,7 +103,7 @@ void qmpEfxWindow::sendEfxChange(void *_fs)
cfb=ui->sbFeedBack->value();cl=ui->sbLevelC->value()/100.;
cr=ui->sbRate->value();cd=ui->sbDepth->value();
IFluidSettings* fs=(IFluidSettings*)_fs;
- if(!_fs)fs=qmpMainWindow::getInstance()->getPlayer()->fluid();
+ if(!_fs)fs=qmpMainWindow::getInstance()->getFluid();
fs->setReverbPara(ui->cbEnabledR->isChecked()?1:0,rr,rd,rw,rl);
fs->setChorusPara(ui->cbEnabledC->isChecked()?1:0,cfb,cl,cr,cd,ct);
diff --git a/qmidiplayer-desktop/qmpmainwindow.cpp b/qmidiplayer-desktop/qmpmainwindow.cpp
index 50c92b4..ea90493 100644
--- a/qmidiplayer-desktop/qmpmainwindow.cpp
+++ b/qmidiplayer-desktop/qmpmainwindow.cpp
@@ -67,6 +67,8 @@ qmpMainWindow::~qmpMainWindow()
delete renderf;renderf=nullptr;
delete reloadsynf;reloadsynf=nullptr;
if(player)delete player;
+ internalfluid->deviceDeinit();
+ delete internalfluid;
delete ui;
}
@@ -82,17 +84,24 @@ void qmpMainWindow::init()
[this]
{
player=new CMidiPlayer();
+ internalfluid=new qmpMidiOutFluid();
+ player->registerMidiOutDevice(internalfluid,"Internal FluidSynth");
reloadsynf=new qmpReloadSynthFunc(this);
- player->registerFluidOptions(pmgr->pluginAPI);
- playerSetup(player->fluid());
- player->fluid()->deviceInit();
- loadSoundFont(player->fluid());
+
+ internalfluid->registerOptions(pmgr->pluginAPI);
+ playerSetup(internalfluid);
+ internalfluid->deviceInit();
+ loadSoundFont(internalfluid);
+ for(int i=0;i<16;++i)
+ player->setChannelOutput(i,0);
+
auto rtdev=qmpRtMidiManager::getDevices();
for(auto &i:rtdev)
player->registerMidiOutDevice(i.first,i.second);
}
);
- while(f.wait_for(std::chrono::milliseconds(100))==std::future_status::timeout);
+ while(f.wait_for(std::chrono::milliseconds(100))==std::future_status::timeout)
+ QApplication::processEvents();
ui->centralWidget->setEnabled(true);
settingsw->registerSoundFontOption();
@@ -231,7 +240,14 @@ void qmpMainWindow::updateWidgets()
timer->stop();stopped=true;playing=false;
invokeCallback("main.stop",nullptr);
setFuncEnabled("Render",stopped);setFuncEnabled("ReloadSynth",stopped);
- player->playerDeinit();playerTh->join();
+ player->playerDeinit();
+ auto f=std::async([this]{playerTh->join();});
+ while(f.wait_for(std::chrono::milliseconds(100))==std::future_status::timeout)
+ {
+ QApplication::processEvents();
+ ui->lbCurPoly->setText(QString("%1").arg(internalfluid->getPolyphone(),5,10,QChar('0')));
+ ui->lbMaxPoly->setText(QString("%1").arg(internalfluid->getMaxPolyphone(),5,10,QChar('0')));
+ }
delete playerTh;playerTh=nullptr;
player->playerPanic(true);
chnlw->on_pbUnmute_clicked();chnlw->on_pbUnsolo_clicked();
@@ -241,7 +257,7 @@ void qmpMainWindow::updateWidgets()
ui->lbCurTime->setText("00:00");
}
else
- switchTrack(plistw->getNextItem());
+ switchTrack(plistw->getNextItem(),false);
}
if(renderTh)
{
@@ -264,20 +280,35 @@ void qmpMainWindow::updateWidgets()
char ts[100];
sprintf(ts,"%02d:%02d",(int)(elapsed.count()+offset)/60,(int)(elapsed.count()+offset)%60);
ui->lbCurTime->setText(ts);
- ui->lbCurPoly->setText(QString("%1").arg(player->fluid()->getPolyphone(),5,10,QChar('0')));
- ui->lbMaxPoly->setText(QString("%1").arg(player->fluid()->getMaxPolyphone(),5,10,QChar('0')));
+ ui->lbCurPoly->setText(QString("%1").arg(internalfluid->getPolyphone(),5,10,QChar('0')));
+ ui->lbMaxPoly->setText(QString("%1").arg(internalfluid->getMaxPolyphone(),5,10,QChar('0')));
}
}
QString qmpMainWindow::getFileName(){return ui->lbFileName->text();}
-void qmpMainWindow::switchTrack(QString s)
+void qmpMainWindow::switchTrack(QString s,bool interrupt)
{
stopped=false;playing=true;
setFuncEnabled("Render",stopped);setFuncEnabled("ReloadSynth",stopped);
ui->pbPlayPause->setIcon(QIcon(getThemedIcon(":/img/pause.svg")));
- timer->stop();player->playerDeinit();
+ if(interrupt)
+ {
+ player->playerDeinit();
+ player->playerPanic();
+ }
invokeCallback("main.stop",nullptr);
- if(playerTh){playerTh->join();delete playerTh;playerTh=nullptr;}
+ if(playerTh)
+ {
+ auto f=std::async([this]{playerTh->join();});
+ while(f.wait_for(std::chrono::milliseconds(100))==std::future_status::timeout)
+ {
+ QApplication::processEvents();
+ ui->lbCurPoly->setText(QString("%1").arg(internalfluid->getPolyphone(),5,10,QChar('0')));
+ ui->lbMaxPoly->setText(QString("%1").arg(internalfluid->getMaxPolyphone(),5,10,QChar('0')));
+ }
+ delete playerTh;playerTh=nullptr;
+ }
+ timer->stop();
player->playerPanic(true);
ui->hsTimer->setValue(0);
chnlw->on_pbUnmute_clicked();chnlw->on_pbUnsolo_clicked();
@@ -290,9 +321,13 @@ void qmpMainWindow::switchTrack(QString s)
ui->lbFinTime->setText(ts);
player->playerInit();
invokeCallback("main.start",nullptr);
- player->fluid()->setGain(ui->vsMasterVol->value()/250.);efxw->sendEfxChange();
- player->setWaitVoice(settings->getOptionBool("Midi/WaitVoice"));
- playerTh=new std::thread(&CMidiPlayer::playerThread,player);
+ internalfluid->setGain(ui->vsMasterVol->value()/250.);efxw->sendEfxChange();
+ playerTh=new std::thread([this]{
+ player->playerThread();
+ if(settings->getOptionBool("Midi/WaitVoice")&&player->isFinished())
+ while(internalfluid->getPolyphone()>0)
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ });
#ifdef _WIN32
SetThreadPriority((void*)playerTh->native_handle(),THREAD_PRIORITY_TIME_CRITICAL);
#endif
@@ -415,9 +450,13 @@ void qmpMainWindow::on_pbPlayPause_clicked()
ui->lbFinTime->setText(ts);
player->playerInit();
invokeCallback("main.start",nullptr);
- player->fluid()->setGain(ui->vsMasterVol->value()/250.);efxw->sendEfxChange();
- player->setWaitVoice(settings->getOptionBool("Midi/WaitVoice"));
- playerTh=new std::thread(&CMidiPlayer::playerThread,player);
+ internalfluid->setGain(ui->vsMasterVol->value()/250.);efxw->sendEfxChange();
+ playerTh=new std::thread([this]{
+ player->playerThread();
+ if(settings->getOptionBool("Midi/WaitVoice")&&player->isFinished())
+ while(internalfluid->getPolyphone()>0)
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ });
#ifdef _WIN32
SetThreadPriority((void*)playerTh->native_handle(),THREAD_PRIORITY_TIME_CRITICAL);
#endif
@@ -498,7 +537,7 @@ void qmpMainWindow::playerSeek(uint32_t percentage)
void qmpMainWindow::on_vsMasterVol_valueChanged()
{
- if(!stopped)player->fluid()->setGain(ui->vsMasterVol->value()/250.);
+ if(!stopped)internalfluid->setGain(ui->vsMasterVol->value()/250.);
settings->setOptionRaw("FluidSynth/Gain",ui->vsMasterVol->value());
}
@@ -642,13 +681,14 @@ void qmpMainWindow::reloadSynth()
std::future<void> f=std::async(std::launch::async,
[this]
{
- player->fluid()->deviceDeinit(true);
- playerSetup(player->fluid());
- player->fluid()->deviceInit();
- loadSoundFont(player->fluid());
+ internalfluid->deviceDeinit(true);
+ playerSetup(internalfluid);
+ internalfluid->deviceInit();
+ loadSoundFont(internalfluid);
}
);
- while(f.wait_for(std::chrono::milliseconds(100))==std::future_status::timeout);
+ while(f.wait_for(std::chrono::milliseconds(100))==std::future_status::timeout)
+ QApplication::processEvents();
ui->centralWidget->setEnabled(true);
}
diff --git a/qmidiplayer-desktop/qmpmainwindow.hpp b/qmidiplayer-desktop/qmpmainwindow.hpp
index 700b501..d98029d 100644
--- a/qmidiplayer-desktop/qmpmainwindow.hpp
+++ b/qmidiplayer-desktop/qmpmainwindow.hpp
@@ -20,7 +20,8 @@
#include <future>
#include <map>
#include <unordered_map>
-#include "../core/qmpmidiplay.hpp"
+#include "qmpmidioutfluid.hpp"
+#include "qmpmidiplay.hpp"
#include "qmpplugin.hpp"
#include "qmpplistwindow.hpp"
#include "qmpchannelswindow.hpp"
@@ -141,11 +142,12 @@ class qmpMainWindow:public QMainWindow
void dragEnterEvent(QDragEnterEvent *event);
~qmpMainWindow();
CMidiPlayer* getPlayer(){return player;}
+ qmpMidiOutFluid* getFluid(){return internalfluid;}
qmpSettings* getSettings(){return settings.get();}
QTimer* getTimer(){return timer;}
bool isFinalizing(){return fin;}
QString getFileName();
- void switchTrack(QString s);
+ void switchTrack(QString s,bool interrupt=true);
std::string getTitle();
std::wstring getWTitle();
uint32_t getPlaybackPercentage();
@@ -193,6 +195,7 @@ class qmpMainWindow:public QMainWindow
std::chrono::steady_clock::time_point st;
double offset;
CMidiPlayer *player;
+ qmpMidiOutFluid *internalfluid;
qmpFileRendererFluid *fluidrenderer;
qmpPluginManager *pmgr;
QPointer<qmpPlistWindow> plistw;
diff --git a/qmidiplayer-desktop/qmpplugin.cpp b/qmidiplayer-desktop/qmpplugin.cpp
index 8a156ba..6e53302 100644
--- a/qmidiplayer-desktop/qmpplugin.cpp
+++ b/qmidiplayer-desktop/qmpplugin.cpp
@@ -144,9 +144,9 @@ uint32_t qmpPluginAPI::getNoteCount()
uint32_t qmpPluginAPI::getMaxTick()
{return qmw&&qmw->getPlayer()?qmw->getPlayer()->getMaxTick():0;}
uint32_t qmpPluginAPI::getCurrentPolyphone()
-{return qmw&&qmw->getPlayer()?qmw->getPlayer()->fluid()->getPolyphone():0;}
+{return qmw&&qmw->getPlayer()?qmw->getFluid()->getPolyphone():0;}
uint32_t qmpPluginAPI::getMaxPolyphone()
-{return qmw&&qmw->getPlayer()?qmw->getPlayer()->fluid()->getMaxPolyphone():0;}
+{return qmw&&qmw->getPlayer()?qmw->getFluid()->getMaxPolyphone():0;}
uint32_t qmpPluginAPI::getCurrentTimeStamp()
{return qmw&&qmw->getPlayer()?qmw->getPlayer()->getTick():0;}
uint32_t qmpPluginAPI::getCurrentPlaybackPercentage()
diff --git a/qmidiplayer-desktop/qmppresetselect.cpp b/qmidiplayer-desktop/qmppresetselect.cpp
index 52b0b66..821eced 100644
--- a/qmidiplayer-desktop/qmppresetselect.cpp
+++ b/qmidiplayer-desktop/qmppresetselect.cpp
@@ -18,8 +18,7 @@ qmpPresetSelector::~qmpPresetSelector()
void qmpPresetSelector::showEvent(QShowEvent *e)
{
memset(presets,0,sizeof(presets));
- CMidiPlayer *plyr=qmpMainWindow::getInstance()->getPlayer();
- if(!plyr->fluid()->getSFCount())return e->ignore();
+ if(!qmpMainWindow::getInstance()->getFluid()->getSFCount())return e->ignore();
ui->lwBankSelect->clear();
ui->lwPresetSelect->clear();
e->accept();