summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--README.md10
-rw-r--r--main.cpp4
-rw-r--r--qmpchannelswindow.cpp21
-rw-r--r--qmpchannelswindow.hpp4
-rw-r--r--qmpefxwindow.cpp62
-rw-r--r--qmpefxwindow.hpp4
-rw-r--r--qmpinfowindow.cpp2
-rw-r--r--qmpmainwindow.cpp118
-rw-r--r--qmpmainwindow.hpp9
-rw-r--r--qmpmidiplay.cpp49
-rw-r--r--qmpmidiplay.hpp8
-rw-r--r--qmpplistwindow.cpp125
-rw-r--r--qmpplistwindow.hpp8
-rw-r--r--qmppresetselect.cpp2
-rw-r--r--qmpsettingswindow.cpp27
-rw-r--r--qmpsettingswindow.hpp2
-rw-r--r--qmpsettingswindow.ui2
18 files changed, 420 insertions, 43 deletions
diff --git a/ChangeLog b/ChangeLog
index f3e5e97..55da5c1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2016-01-03 0.6.0 alpha
+Implemented most of the options.
+"Render to Wave" is now implemented.
+Finished saving & loading playlists.
+Fixed several leakage and bugs.
+
2016-01-02 0.5.1
Now sends SysEx(optional).
Primitive settings implementation(some of the audio tab and the
diff --git a/README.md b/README.md
index 3c86da4..aa991d9 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,14 @@
# QMidiPlayer
A cross-platform midi file player based on libfluidsynth and Qt.
-Currently it's still very incomplete and not suitable for everyday use.
+Now it's in alpha stage. There are still a whole bunch of bugs, be careful...
-Planned features:
+Features:
* Channel mute/solo
* Editing channel parameters on-the-fly
* Playlists
* Editing synthesizer effects
-* Visualization (not implemented)
-* Rendering midi to wave file (not implemented)
+* Rendering midi to wave file
+* Visualization using SMELT (not implemented)
+
+Tested on Debian sid. A few changes are required to make it work correctly on Windows.
diff --git a/main.cpp b/main.cpp
index 7e24b69..a2c703a 100644
--- a/main.cpp
+++ b/main.cpp
@@ -1,15 +1,11 @@
#include "qmpmainwindow.hpp"
#include <QApplication>
#include <QStyle>
-#include <QDesktopWidget>
int main(int argc, char *argv[])
{
QApplication a(argc,argv);
qmpMainWindow w;
- w.setGeometry(QStyle::alignedRect(
- Qt::LeftToRight,Qt::AlignCenter,w.size(),
- qApp->desktop()->availableGeometry()));
w.show();
return a.exec();
diff --git a/qmpchannelswindow.cpp b/qmpchannelswindow.cpp
index b73f71b..448e5b7 100644
--- a/qmpchannelswindow.cpp
+++ b/qmpchannelswindow.cpp
@@ -37,13 +37,34 @@ qmpChannelsWindow::qmpChannelsWindow(QWidget *parent) :
ui->twChannels->setColumnWidth(4,32);
}
+void qmpChannelsWindow::showEvent(QShowEvent *event)
+{
+ if(qmpSettingsWindow::getSettingsIntf()->value("Behavior/DialogStatus","").toInt())
+ {
+ qmpSettingsWindow::getSettingsIntf()->setValue("DialogStatus/ChnlWShown",1);
+ }
+ event->accept();
+}
+
void qmpChannelsWindow::closeEvent(QCloseEvent *event)
{
setVisible(false);
+ if(!qmpMainWindow::getInstance()->isFinalizing()&&qmpSettingsWindow::getSettingsIntf()->value("Behavior/DialogStatus","").toInt())
+ {
+ qmpSettingsWindow::getSettingsIntf()->setValue("DialogStatus/ChnlWShown",0);
+ }
emit dialogClosing();
event->accept();
}
+void qmpChannelsWindow::moveEvent(QMoveEvent *event)
+{
+ if(qmpSettingsWindow::getSettingsIntf()->value("Behavior/DialogStatus","").toInt())
+ {
+ qmpSettingsWindow::getSettingsIntf()->setValue("DialogStatus/ChnlW",event->pos());
+ }
+}
+
void qmpChannelsWindow::channelWindowsUpdate()
{
for(int i=0;i<16;++i)
diff --git a/qmpchannelswindow.hpp b/qmpchannelswindow.hpp
index 992b264..aba2a8d 100644
--- a/qmpchannelswindow.hpp
+++ b/qmpchannelswindow.hpp
@@ -4,7 +4,9 @@
#include <QLabel>
#include <QPushButton>
#include <QDialog>
+#include <QShowEvent>
#include <QCloseEvent>
+#include <QMoveEvent>
#include "qmppresetselect.hpp"
#include "qmpchanneleditor.hpp"
@@ -47,7 +49,9 @@ class qmpChannelsWindow:public QDialog
public:
explicit qmpChannelsWindow(QWidget *parent = 0);
~qmpChannelsWindow();
+ void showEvent(QShowEvent *event);
void closeEvent(QCloseEvent *event);
+ void moveEvent(QMoveEvent *event);
signals:
void dialogClosing();
public slots:
diff --git a/qmpefxwindow.cpp b/qmpefxwindow.cpp
index b46cbb5..8e60d93 100644
--- a/qmpefxwindow.cpp
+++ b/qmpefxwindow.cpp
@@ -10,8 +10,19 @@ qmpEfxWindow::qmpEfxWindow(QWidget *parent) :
ui->setupUi(this);initialized=false;
connect(this,SIGNAL(dialogClosing()),parent,SLOT(dialogClosed()));
//stub. read these from settings after the setting module is implemented
- ui->cbEnabledC->setChecked(true);
- ui->cbEnabledR->setChecked(true);
+ QSettings *settings=qmpSettingsWindow::getSettingsIntf();
+ ui->cbEnabledC->setChecked(settings->value("Effects/ChorusEnabled",1).toInt());
+ ui->cbEnabledR->setChecked(settings->value("Effects/ReverbEnabled",1).toInt());
+ rr=settings->value("Effects/ReverbRoom",FLUID_REVERB_DEFAULT_ROOMSIZE).toDouble();
+ rd=settings->value("Effects/ReverbDamp",FLUID_REVERB_DEFAULT_DAMP).toDouble();
+ rw=settings->value("Effects/ReverbWidth",FLUID_REVERB_DEFAULT_WIDTH).toDouble();
+ rl=settings->value("Effects/ReverbLevel",FLUID_REVERB_DEFAULT_LEVEL).toDouble();
+
+ cfb=settings->value("Effects/ChorusFeedbk",FLUID_CHORUS_DEFAULT_N).toInt();
+ cl=settings->value("Effects/ChorusLevel",FLUID_CHORUS_DEFAULT_LEVEL).toDouble();
+ cr=settings->value("Effects/ChorusRate",FLUID_CHORUS_DEFAULT_SPEED).toDouble();
+ cd=settings->value("Effects/ChorusDepth",FLUID_CHORUS_DEFAULT_DEPTH).toDouble();
+ ct=settings->value("Effects/ChorusType",FLUID_CHORUS_DEFAULT_TYPE).toInt();
}
qmpEfxWindow::~qmpEfxWindow()
@@ -22,17 +33,25 @@ qmpEfxWindow::~qmpEfxWindow()
void qmpEfxWindow::closeEvent(QCloseEvent *event)
{
setVisible(false);
+ if(!qmpMainWindow::getInstance()->isFinalizing()&&qmpSettingsWindow::getSettingsIntf()->value("Behavior/DialogStatus","").toInt())
+ {
+ qmpSettingsWindow::getSettingsIntf()->setValue("DialogStatus/EfxWShown",0);
+ }
emit dialogClosing();
event->accept();
}
void qmpEfxWindow::showEvent(QShowEvent *event)
{
- CMidiPlayer* player=qmpMainWindow::getInstance()->getPlayer();
- player->getReverbPara(&rr,&rd,&rw,&rl);
- player->getChorusPara(&cfb,&cl,&cr,&cd,&ct);
+ //CMidiPlayer* player=qmpMainWindow::getInstance()->getPlayer();
+ //These parameters will never be modified outside this window...
+ /*if(initialized)
+ {
+ player->getReverbPara(&rr,&rd,&rw,&rl);
+ player->getChorusPara(&cfb,&cl,&cr,&cd,&ct);
+ }*/
ui->sbRoom->setValue((int)round(rr*100));ui->dRoom->setValue((int)round(rr*100));
- ui->sbDamp->setValue((int)round(rd*100));ui->dRoom->setValue((int)round(rd*100));
+ ui->sbDamp->setValue((int)round(rd*100));ui->dDamp->setValue((int)round(rd*100));
ui->sbWidth->setValue((int)round(rw*100));ui->dWidth->setValue((int)round(rw*100));
ui->sbLevelR->setValue((int)round(rl*100));ui->dLevelR->setValue((int)round(rl*100));
@@ -42,7 +61,20 @@ void qmpEfxWindow::showEvent(QShowEvent *event)
ui->sbLevelC->setValue((int)round(cl*100));ui->dLevelC->setValue((int)round(cl*100));
if(ct==FLUID_CHORUS_MOD_SINE)ui->rbSine->setChecked(true),ui->rbTriangle->setChecked(false);
if(ct==FLUID_CHORUS_MOD_TRIANGLE)ui->rbSine->setChecked(false),ui->rbTriangle->setChecked(true);
- initialized=true;event->accept();
+ initialized=true;
+ if(qmpSettingsWindow::getSettingsIntf()->value("Behavior/DialogStatus","").toInt())
+ {
+ qmpSettingsWindow::getSettingsIntf()->setValue("DialogStatus/EfxWShown",1);
+ }
+ event->accept();
+}
+
+void qmpEfxWindow::moveEvent(QMoveEvent *event)
+{
+ if(qmpSettingsWindow::getSettingsIntf()->value("Behavior/DialogStatus","").toInt())
+ {
+ qmpSettingsWindow::getSettingsIntf()->setValue("DialogStatus/EfxW",event->pos());
+ }
}
void qmpEfxWindow::sendEfxChange()
@@ -56,10 +88,25 @@ void qmpEfxWindow::sendEfxChange()
CMidiPlayer* player=qmpMainWindow::getInstance()->getPlayer();
player->setReverbPara(ui->cbEnabledR->isChecked()?1:0,rr,rd,rw,rl);
player->setChorusPara(ui->cbEnabledC->isChecked()?1:0,cfb,cl,cr,cd,ct);
+
+ QSettings *settings=qmpSettingsWindow::getSettingsIntf();
+ settings->setValue("Effects/ChorusEnabled",ui->cbEnabledC->isChecked()?1:0);
+ settings->setValue("Effects/ReverbEnabled",ui->cbEnabledR->isChecked()?1:0);
+ settings->setValue("Effects/ReverbRoom",rr);
+ settings->setValue("Effects/ReverbDamp",rd);
+ settings->setValue("Effects/ReverbWidth",rw);
+ settings->setValue("Effects/ReverbLevel",rl);
+
+ settings->setValue("Effects/ChorusFeedbk",cfb);
+ settings->setValue("Effects/ChorusLevel",cl);
+ settings->setValue("Effects/ChorusRate",cr);
+ settings->setValue("Effects/ChorusDepth",cd);
+ settings->setValue("Effects/ChorusType",ct);
}
void qmpEfxWindow::dailValueChange()
{
+ if(!initialized)return;
ui->sbRoom->setValue(ui->dRoom->value());
ui->sbDamp->setValue(ui->dDamp->value());
ui->sbWidth->setValue(ui->dWidth->value());
@@ -73,6 +120,7 @@ void qmpEfxWindow::dailValueChange()
void qmpEfxWindow::spinValueChange()
{
+ if(!initialized)return;
ui->dRoom->setValue(ui->sbRoom->value());
ui->dDamp->setValue(ui->sbDamp->value());
ui->dWidth->setValue(ui->sbWidth->value());
diff --git a/qmpefxwindow.hpp b/qmpefxwindow.hpp
index aa56263..4d4ede2 100644
--- a/qmpefxwindow.hpp
+++ b/qmpefxwindow.hpp
@@ -4,6 +4,7 @@
#include <QDialog>
#include <QCloseEvent>
#include <QShowEvent>
+#include <QMoveEvent>
namespace Ui {
class qmpEfxWindow;
@@ -18,6 +19,8 @@ class qmpEfxWindow : public QDialog
~qmpEfxWindow();
void closeEvent(QCloseEvent *event);
void showEvent(QShowEvent *event);
+ void moveEvent(QMoveEvent *event);
+ void sendEfxChange();
signals:
void dialogClosing();
@@ -47,7 +50,6 @@ class qmpEfxWindow : public QDialog
private:
void dailValueChange();
void spinValueChange();
- void sendEfxChange();
Ui::qmpEfxWindow *ui;
double rr,rd,rw,rl;
int cfb,ct,initialized;
diff --git a/qmpinfowindow.cpp b/qmpinfowindow.cpp
index aecd58f..689a756 100644
--- a/qmpinfowindow.cpp
+++ b/qmpinfowindow.cpp
@@ -24,7 +24,7 @@ void qmpInfoWindow::updateInfo()
{
char str[256];
CMidiPlayer* player=qmpMainWindow::getInstance()->getPlayer();
- const QSettings* settings=qmpSettingsWindow::getSettingsIntf();
+ QSettings* settings=qmpSettingsWindow::getSettingsIntf();
ui->lbFileName->setText(QString("File name: ")+qmpMainWindow::getInstance()->getFileName());
if(player->getTitle())
{
diff --git a/qmpmainwindow.cpp b/qmpmainwindow.cpp
index 525cb1e..d6cfc6e 100644
--- a/qmpmainwindow.cpp
+++ b/qmpmainwindow.cpp
@@ -1,5 +1,6 @@
#include <cstdio>
#include <QUrl>
+#include <QDesktopWidget>
#include "qmpmainwindow.hpp"
#include "ui_qmpmainwindow.h"
#include "qmpmidiplay.hpp"
@@ -20,8 +21,26 @@ qmpMainWindow::qmpMainWindow(QWidget *parent) :
infow=new qmpInfoWindow(this);
timer=new QTimer(this);
fnA1=new QAction("File Information",ui->lbFileName);
+ fnA2=new QAction("Render to Wave",ui->lbFileName);
ui->lbFileName->addAction(fnA1);
+ ui->lbFileName->addAction(fnA2);
+ if(qmpSettingsWindow::getSettingsIntf()->value("Behavior/DialogStatus","").toInt())
+ {
+ QRect g=geometry();
+ g.setTopLeft(qmpSettingsWindow::getSettingsIntf()->value("DialogStatus/MainW",QPoint(-999,-999)).toPoint());
+ if(g.topLeft()!=QPoint(-999,-999))setGeometry(g);
+ else setGeometry(QStyle::alignedRect(
+ Qt::LeftToRight,Qt::AlignCenter,size(),
+ qApp->desktop()->availableGeometry()));
+ }
+ if(qmpSettingsWindow::getSettingsIntf()->value("DialogStatus/PListWShown",0).toInt())
+ {ui->pbPList->setChecked(true);on_pbPList_clicked();}
+ if(qmpSettingsWindow::getSettingsIntf()->value("DialogStatus/ChnlWShown",0).toInt())
+ {ui->pbChannels->setChecked(true);on_pbChannels_clicked();}
+ if(qmpSettingsWindow::getSettingsIntf()->value("DialogStatus/EfxWShown",0).toInt())
+ {ui->pbEfx->setChecked(true);on_pbEfx_clicked();}
connect(fnA1,SIGNAL(triggered()),this,SLOT(onfnA1()));
+ connect(fnA2,SIGNAL(triggered()),this,SLOT(onfnA2()));
connect(timer,SIGNAL(timeout()),this,SLOT(updateWidgets()));
connect(timer,SIGNAL(timeout()),chnlw,SLOT(channelWindowsUpdate()));
connect(timer,SIGNAL(timeout()),infow,SLOT(updateInfo()));
@@ -35,7 +54,7 @@ qmpMainWindow::~qmpMainWindow()
void qmpMainWindow::closeEvent(QCloseEvent *event)
{
- on_pbStop_clicked();
+ on_pbStop_clicked();fin=true;
efxw->close();chnlw->close();
plistw->close();infow->close();
settingsw->close();
@@ -47,8 +66,17 @@ void qmpMainWindow::closeEvent(QCloseEvent *event)
event->accept();
}
+void qmpMainWindow::moveEvent(QMoveEvent *event)
+{
+ if(qmpSettingsWindow::getSettingsIntf()->value("Behavior/DialogStatus","").toInt())
+ {
+ qmpSettingsWindow::getSettingsIntf()->setValue("DialogStatus/MainW",event->pos());
+ }
+}
+
void qmpMainWindow::updateWidgets()
{
+ fnA2->setEnabled(stopped);
if(player->isFinished()&&playerTh)
{
if(!plistw->getRepeat())
@@ -77,12 +105,22 @@ void qmpMainWindow::updateWidgets()
player->playerInit();playerSetup();player->fluidInitialize();
for(int i=settingsw->getSFWidget()->count()-1;i>=0;--i)
player->pushSoundFont(settingsw->getSFWidget()->item(i)->text().toStdString().c_str());
- player->setGain(ui->vsMasterVol->value()/250.);
+ player->setGain(ui->vsMasterVol->value()/250.);efxw->sendEfxChange();
playerTh=new std::thread(&CMidiPlayer::playerThread,player);
st=std::chrono::steady_clock::now();offset=0;
timer->start(100);
}
}
+ if(renderTh)
+ {
+ if(player->isFinished())
+ {
+ renderTh->join();timer->stop();
+ ui->centralWidget->setEnabled(true);
+ delete renderTh;renderTh=NULL;
+ player->rendererDeinit();
+ }
+ }
while(!player->isFinished()&&player->getTCeptr()>player->getStamp(ui->hsTimer->value())
&&ui->hsTimer->value()<=100&&!dragging)
ui->hsTimer->setValue(ui->hsTimer->value()+1);
@@ -103,7 +141,7 @@ QString qmpMainWindow::getFileName(){return ui->lbFileName->text();}
void qmpMainWindow::playerSetup()
{
fluid_settings_t* fsettings=player->getFluidSettings();
- const QSettings* settings=qmpSettingsWindow::getSettingsIntf();
+ QSettings* settings=qmpSettingsWindow::getSettingsIntf();
fluid_settings_setstr(fsettings,"audio.driver",settings->value("Audio/Driver","").toString().toStdString().c_str());
fluid_settings_setint(fsettings,"audio.period-size",settings->value("Audio/BufSize","").toInt());
fluid_settings_setint(fsettings,"audio.periods",settings->value("Audio/BufCnt","").toInt());
@@ -111,6 +149,28 @@ void qmpMainWindow::playerSetup()
fluid_settings_setint(fsettings,"synth.sample-rate",settings->value("Audio/Frequency","").toInt());
fluid_settings_setint(fsettings,"synth.polyphony",settings->value("Audio/Polyphony","").toInt());
fluid_settings_setint(fsettings,"synth.cpu-cores",settings->value("Audio/Threads","").toInt());
+ char bsmode[4];
+ if(settings->value("Audio/AutoBS",1).toInt()&&player->getFileStandard())
+ switch(player->getFileStandard())
+ {
+ case 1:strcpy(bsmode,"gm");break;
+ case 2:strcpy(bsmode,"mma");break;
+ case 3:strcpy(bsmode,"gs");break;
+ case 4:strcpy(bsmode,"xg");break;
+ }
+ else
+ {
+ if(settings->value("Audio/BankSelect","CC#0").toString()==QString("Ignored"))
+ strcpy(bsmode,"gm");
+ if(settings->value("Audio/BankSelect","CC#0").toString()==QString("CC#0"))
+ strcpy(bsmode,"gs");
+ if(settings->value("Audio/BankSelect","CC#0").toString()==QString("CC#32"))
+ strcpy(bsmode,"xg");
+ if(settings->value("Audio/BankSelect","CC#0").toString()==QString("CC#0*128+CC#32"))
+ strcpy(bsmode,"mma");
+ }
+ fluid_settings_setstr(fsettings,"synth.midi-bank-select",bsmode);
+ player->sendSysX(settings->value("Midi/SendSysEx",1).toInt());
}
void qmpMainWindow::on_pbPlayPause_clicked()
@@ -128,7 +188,7 @@ void qmpMainWindow::on_pbPlayPause_clicked()
player->playerInit();playerSetup();player->fluidInitialize();
for(int i=settingsw->getSFWidget()->count()-1;i>=0;--i)
player->pushSoundFont(settingsw->getSFWidget()->item(i)->text().toStdString().c_str());
- player->setGain(ui->vsMasterVol->value()/250.);
+ player->setGain(ui->vsMasterVol->value()/250.);efxw->sendEfxChange();
playerTh=new std::thread(&CMidiPlayer::playerThread,player);
st=std::chrono::steady_clock::now();offset=0;
timer->start(100);
@@ -187,7 +247,7 @@ void qmpMainWindow::on_pbStop_clicked()
if(!stopped)
{
timer->stop();stopped=true;playing=false;
- player->playerDeinit();
+ player->playerDeinit();fnA2->setEnabled(stopped);
if(playerTh){playerTh->join();delete playerTh;playerTh=NULL;}
chnlw->on_pbUnmute_clicked();chnlw->on_pbUnsolo_clicked();
ui->pbPlayPause->setIcon(QIcon(":/img/play.png"));
@@ -207,12 +267,28 @@ void qmpMainWindow::dialogClosed()
void qmpMainWindow::on_pbPList_clicked()
{
- if(ui->pbPList->isChecked())plistw->show();else plistw->close();
+ if(ui->pbPList->isChecked())
+ {
+ QRect g=plistw->geometry();
+ g.setTopLeft(qmpSettingsWindow::getSettingsIntf()->value("DialogStatus/PListW",QPoint(-999,-999)).toPoint());
+ if(g.topLeft()==QPoint(-999,-999))
+ g.setTopLeft(window()->mapToGlobal(window()->rect().center())-plistw->rect().center());
+ plistw->setGeometry(g);
+ plistw->show();
+ }else plistw->close();
}
void qmpMainWindow::on_pbChannels_clicked()
{
- if(ui->pbChannels->isChecked())chnlw->show();else chnlw->close();
+ if(ui->pbChannels->isChecked())
+ {
+ QRect g=chnlw->geometry();
+ g.setTopLeft(qmpSettingsWindow::getSettingsIntf()->value("DialogStatus/ChnlW",QPoint(-999,-999)).toPoint());
+ if(g.topLeft()==QPoint(-999,-999))
+ g.setTopLeft(window()->mapToGlobal(window()->rect().center())-chnlw->rect().center());
+ chnlw->setGeometry(g);
+ chnlw->show();
+ }else chnlw->close();
}
void qmpMainWindow::on_pbPrev_clicked()
@@ -229,7 +305,7 @@ void qmpMainWindow::on_pbPrev_clicked()
player->playerInit();playerSetup();player->fluidInitialize();
for(int i=settingsw->getSFWidget()->count()-1;i>=0;--i)
player->pushSoundFont(settingsw->getSFWidget()->item(i)->text().toStdString().c_str());
- player->setGain(ui->vsMasterVol->value()/250.);
+ player->setGain(ui->vsMasterVol->value()/250.);efxw->sendEfxChange();
playerTh=new std::thread(&CMidiPlayer::playerThread,player);
st=std::chrono::steady_clock::now();offset=0;
timer->start(100);
@@ -249,7 +325,7 @@ void qmpMainWindow::on_pbNext_clicked()
player->playerInit();playerSetup();player->fluidInitialize();
for(int i=settingsw->getSFWidget()->count()-1;i>=0;--i)
player->pushSoundFont(settingsw->getSFWidget()->item(i)->text().toStdString().c_str());
- player->setGain(ui->vsMasterVol->value()/250.);
+ player->setGain(ui->vsMasterVol->value()/250.);efxw->sendEfxChange();
playerTh=new std::thread(&CMidiPlayer::playerThread,player);
st=std::chrono::steady_clock::now();offset=0;
timer->start(100);
@@ -272,7 +348,7 @@ void qmpMainWindow::selectionChanged()
player->playerInit();playerSetup();player->fluidInitialize();
for(int i=settingsw->getSFWidget()->count()-1;i>=0;--i)
player->pushSoundFont(settingsw->getSFWidget()->item(i)->text().toStdString().c_str());
- player->setGain(ui->vsMasterVol->value()/250.);
+ player->setGain(ui->vsMasterVol->value()/250.);efxw->sendEfxChange();
playerTh=new std::thread(&CMidiPlayer::playerThread,player);
st=std::chrono::steady_clock::now();offset=0;
timer->start(100);
@@ -280,7 +356,16 @@ void qmpMainWindow::selectionChanged()
void qmpMainWindow::on_pbEfx_clicked()
{
- if(ui->pbEfx->isChecked())efxw->show();else efxw->close();
+ if(ui->pbEfx->isChecked())
+ {
+ QRect g=efxw->geometry();
+ g.setTopLeft(qmpSettingsWindow::getSettingsIntf()->value("DialogStatus/EfxW",QPoint(-999,-999)).toPoint());
+ if(g.topLeft()==QPoint(-999,-999))
+ g.setTopLeft(window()->mapToGlobal(window()->rect().center())-efxw->rect().center());
+ efxw->setGeometry(g);
+ efxw->show();
+ }
+ else efxw->close();
}
void qmpMainWindow::on_lbFileName_customContextMenuRequested(const QPoint &pos)
@@ -295,6 +380,17 @@ void qmpMainWindow::onfnA1()
infow->show();
}
+void qmpMainWindow::onfnA2()
+{
+ player->rendererLoadFile((plistw->getSelectedItem()+QString(".wav")).toStdString().c_str());
+ playerSetup();player->rendererInit(plistw->getSelectedItem().toStdString().c_str());
+ ui->centralWidget->setEnabled(false);
+ for(int i=settingsw->getSFWidget()->count()-1;i>=0;--i)
+ player->pushSoundFont(settingsw->getSFWidget()->item(i)->text().toStdString().c_str());
+ player->setGain(ui->vsMasterVol->value()/250.);efxw->sendEfxChange();timer->start(100);
+ renderTh=new std::thread(&CMidiPlayer::rendererThread,player);
+}
+
void qmpMainWindow::on_pbSettings_clicked()
{
if(ui->pbSettings->isChecked())settingsw->show();else settingsw->close();
diff --git a/qmpmainwindow.hpp b/qmpmainwindow.hpp
index c251fc0..bd61b13 100644
--- a/qmpmainwindow.hpp
+++ b/qmpmainwindow.hpp
@@ -4,6 +4,7 @@
#include <QMainWindow>
#include <QTimer>
#include <QCloseEvent>
+#include <QMoveEvent>
#include <QAction>
#include <QMenu>
#include <thread>
@@ -26,9 +27,11 @@ class qmpMainWindow:public QMainWindow
public:
explicit qmpMainWindow(QWidget *parent = 0);
void closeEvent(QCloseEvent *event);
+ void moveEvent(QMoveEvent *event);
~qmpMainWindow();
CMidiPlayer* getPlayer(){return player;}
QTimer* getTimer(){return timer;}
+ bool isFinalizing(){return fin;}
private slots:
void on_pbPlayPause_clicked();
@@ -43,8 +46,9 @@ class qmpMainWindow:public QMainWindow
void on_pbChannels_clicked();
void on_pbEfx_clicked();
void on_lbFileName_customContextMenuRequested(const QPoint &pos);
- void onfnA1();
void on_pbSettings_clicked();
+ void onfnA1();
+ void onfnA2();
public slots:
void dialogClosed();
@@ -53,8 +57,9 @@ class qmpMainWindow:public QMainWindow
private:
Ui::qmpMainWindow *ui;
QTimer *timer;
- bool playing,stopped,dragging;
+ bool playing,stopped,dragging,fin;
std::thread *playerTh=NULL;
+ std::thread *renderTh=NULL;
std::chrono::steady_clock::time_point st;
double offset;
CMidiPlayer *player;
diff --git a/qmpmidiplay.cpp b/qmpmidiplay.cpp
index 2b3a2a9..2578d6c 100644
--- a/qmpmidiplay.cpp
+++ b/qmpmidiplay.cpp
@@ -65,7 +65,7 @@ void CMidiPlayer::processEvent(const SEvent *e)
if((e->type&0x0F)==0x00||(e->type&0x0F)==07)
{
int io=0;
- fluid_synth_sysex(synth,e->str,e->p1,NULL,&io,NULL,0);
+ if(sendSysEx)fluid_synth_sysex(synth,e->str,e->p1,NULL,&io,NULL,0);
}
break;
}
@@ -105,12 +105,13 @@ void CMidiPlayer::playEvents()
for(uint32_t ct=midiFile->getEvent(0)->time;tceptr<midiFile->getEventCount();)
{
while(tcpaused)std::this_thread::sleep_for(std::chrono::milliseconds(100));
- while(!tcstop&&tceptr<midiFile->getEventCount()&&ct==midiFile->getEvent(tceptr)->time)
+ while(!tcstop&&midiFile&&tceptr<midiFile->getEventCount()&&ct==midiFile->getEvent(tceptr)->time)
processEvent(midiFile->getEvent(tceptr++));
- if(tcstop||tceptr>=midiFile->getEventCount())break;
+ if(tcstop||!midiFile||tceptr>=midiFile->getEventCount())break;
if(resumed)resumed=false;
else
std::this_thread::sleep_for(std::chrono::nanoseconds(midiFile->getEvent(tceptr)->time-ct)*dpt);
+ if(tcstop||!midiFile)break;
ct=midiFile->getEvent(tceptr)->time;
}
while(!tcstop&&synth&&fluid_synth_get_active_voice_count(synth)>0)std::this_thread::sleep_for(std::chrono::microseconds(100));
@@ -167,10 +168,7 @@ CMidiPlayer::CMidiPlayer()
midiFile=NULL;resumed=false;
settings=NULL;synth=NULL;adriver=NULL;
}
-CMidiPlayer::~CMidiPlayer()
-{
-
-}
+CMidiPlayer::~CMidiPlayer(){}
void CMidiPlayer::playerPanic()
{
for(int i=0;i<16;++i)fluid_synth_all_notes_off(synth,i);
@@ -187,17 +185,50 @@ 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;
- settings=new_fluid_settings();
+ sendSysEx=true;settings=new_fluid_settings();
}
void CMidiPlayer::playerDeinit()
{
tceptr=0;tcstop=1;tcpaused=0;
+ //std::this_thread::sleep_for(std::chrono::milliseconds(100));
+ delete midiFile;midiFile=NULL;
fluidDeinitialize();
}
void CMidiPlayer::playerThread()
{
playEvents();
}
+
+void CMidiPlayer::rendererLoadFile(const char* ofn)
+{
+ settings=new_fluid_settings();
+ fluid_settings_setstr(settings,"audio.file.name",ofn);
+}
+void CMidiPlayer::rendererInit(const char* fn)
+{
+ finished=0;
+ synth=new_fluid_synth(settings);
+ player=new_fluid_player(synth);
+ fluid_player_add(player,fn);
+}
+void CMidiPlayer::rendererThread()
+{
+ fluid_file_renderer_t* renderer=new_fluid_file_renderer(synth);
+ fluid_player_play(player);
+ while(fluid_player_get_status(player)==FLUID_PLAYER_PLAYING)
+ if(fluid_file_renderer_process_block(renderer)!=FLUID_OK)break;
+ delete_fluid_file_renderer(renderer);
+ finished=1;
+}
+void CMidiPlayer::rendererDeinit()
+{
+ delete_fluid_player(player);
+ delete_fluid_synth(synth);
+ delete_fluid_settings(settings);
+ player=NULL;synth=NULL;settings=NULL;
+}
+
+void CMidiPlayer::sendSysX(bool send){sendSysEx=send;}
uint32_t CMidiPlayer::getStamp(int id){return stamps[id];}
uint32_t CMidiPlayer::getTCeptr(){return tceptr;}
void CMidiPlayer::setTCeptr(uint32_t ep,uint32_t st)
@@ -230,7 +261,7 @@ void CMidiPlayer::setMaxPolyphone(int p){if(synth)fluid_synth_set_polyphony(synt
void CMidiPlayer::getChannelPreset(int ch,int *b,int *p,char *name)
{
- if(!synth)return;
+ if(!synth)return(void)(b=0,p=0,strcpy(name,""));
fluid_synth_channel_info_t info;
fluid_synth_get_channel_info(synth,ch,&info);
*b=info.bank;*p=info.program;
diff --git a/qmpmidiplay.hpp b/qmpmidiplay.hpp
index 7937c21..514a825 100644
--- a/qmpmidiplay.hpp
+++ b/qmpmidiplay.hpp
@@ -56,9 +56,11 @@ class CMidiPlayer
uint32_t ccstamps[101][16][132],ccc[16][132];//0..127:cc 128:pc 129:cp 130:pb 131:tempo
uint16_t mute,solo;
double ftime;
+ bool sendSysEx;
fluid_settings_t* settings;
fluid_synth_t* synth;
fluid_audio_driver_t* adriver;
+ fluid_player_t* player;
uint32_t ctempo,ctsn,ctsd,dpt,divs,cks;
//raw tempo, timesig num., timesig den., delay per tick, division, keysig
//thread control
@@ -82,6 +84,11 @@ class CMidiPlayer
void playerThread();
void playerPanic();
+ void rendererLoadFile(const char* ofn);
+ void rendererInit(const char *fn);
+ void rendererThread();
+ void rendererDeinit();
+
//playing control methods
uint32_t getStamp(int id);
uint32_t getTCeptr();
@@ -101,6 +108,7 @@ class CMidiPlayer
const char* getCopyright();
void setGain(double gain);
+ void sendSysX(bool send);
int getPolyphone();
int getMaxPolyphone();
void setMaxPolyphone(int p);
diff --git a/qmpplistwindow.cpp b/qmpplistwindow.cpp
index e0c52db..695afa0 100644
--- a/qmpplistwindow.cpp
+++ b/qmpplistwindow.cpp
@@ -1,6 +1,7 @@
#include <cstdlib>
#include <ctime>
#include <QFileDialog>
+#include <QSettings>
#include "qmpplistwindow.hpp"
#include "ui_qmpplistwindow.h"
#include "qmpmainwindow.hpp"
@@ -13,6 +14,44 @@ qmpPlistWindow::qmpPlistWindow(QWidget *parent) :
connect(this,SIGNAL(dialogClosing()),parent,SLOT(dialogClosed()));
connect(this,SIGNAL(selectionChanging()),parent,SLOT(selectionChanged()));
repeat=0;shuffle=0;
+ if(qmpSettingsWindow::getSettingsIntf()->value("Behavior/RestorePlaylist","").toInt())
+ {
+ QSettings* plist=new QSettings(QString(getenv("HOME"))+QString("/.config/qmpplist"),
+ QSettings::IniFormat);
+ int fc=plist->value("Playlist/FileCount",0).toInt();
+ ui->lwFiles->clear();for(int i=1;i<=fc;++i)
+ ui->lwFiles->addItem(plist->value("Playlist/File"+QString("%1").arg(i,5,10,QChar('0')),"").toString());
+ repeat=plist->value("Playlist/Repeat",0).toInt();
+ shuffle=plist->value("Playlist/Shuffle",0).toInt();
+ switch(shuffle)
+ {
+ case 1:
+ ui->pbShuffle->setIcon(QIcon(":/img/shuffle.png"));
+ ui->pbShuffle->setText("Shuffle On");
+ break;
+ case 0:
+ default:
+ ui->pbShuffle->setIcon(QIcon(":/img/shuffle-off.png"));
+ ui->pbShuffle->setText("Shuffle Off");
+ break;
+ }
+ switch(repeat)
+ {
+ case 0:
+ ui->pbRepeat->setIcon(QIcon(":/img/repeat-non.png"));
+ ui->pbRepeat->setText("Repeat Off");
+ break;
+ case 1:
+ ui->pbRepeat->setIcon(QIcon(":/img/repeat-one.png"));
+ ui->pbRepeat->setText("Repeat One");
+ break;
+ case 2:
+ ui->pbRepeat->setIcon(QIcon(":/img/repeat-all.png"));
+ ui->pbRepeat->setText("Repeat All");
+ break;
+ }
+ delete plist;
+ }
}
qmpPlistWindow::~qmpPlistWindow()
@@ -20,13 +59,46 @@ qmpPlistWindow::~qmpPlistWindow()
delete ui;
}
+void qmpPlistWindow::showEvent(QShowEvent *event)
+{
+ if(qmpSettingsWindow::getSettingsIntf()->value("Behavior/DialogStatus","").toInt())
+ {
+ qmpSettingsWindow::getSettingsIntf()->setValue("DialogStatus/PListWShown",1);
+ }
+ event->accept();
+}
+
void qmpPlistWindow::closeEvent(QCloseEvent *event)
{
setVisible(false);
+ if(!qmpMainWindow::getInstance()->isFinalizing()&&qmpSettingsWindow::getSettingsIntf()->value("Behavior/DialogStatus","").toInt())
+ {
+ qmpSettingsWindow::getSettingsIntf()->setValue("DialogStatus/PListWShown",0);
+ }
+ if(qmpMainWindow::getInstance()->isFinalizing()&&qmpSettingsWindow::getSettingsIntf()->value("Behavior/RestorePlaylist","").toInt())
+ {
+ QSettings* plist=new QSettings(QString(getenv("HOME"))+QString("/.config/qmpplist"),
+ QSettings::IniFormat);
+ plist->setValue("Playlist/FileCount",ui->lwFiles->count());
+ for(int i=0;i<ui->lwFiles->count();++i)
+ plist->setValue("Playlist/File"+QString("%1").arg(i+1,5,10,QChar('0')),ui->lwFiles->item(i)->text());
+ plist->setValue("Playlist/Repeat",repeat);
+ plist->setValue("Playlist/Shuffle",shuffle);
+ plist->sync();
+ delete plist;
+ }
emit dialogClosing();
event->accept();
}
+void qmpPlistWindow::moveEvent(QMoveEvent *event)
+{
+ if(qmpSettingsWindow::getSettingsIntf()->value("Behavior/DialogStatus","").toInt())
+ {
+ qmpSettingsWindow::getSettingsIntf()->setValue("DialogStatus/PListW",event->pos());
+ }
+}
+
void qmpPlistWindow::on_pbAdd_clicked()
{
QStringList sl=QFileDialog::getOpenFileNames(this,"Add File","","Midi files (*.mid *.midi)");
@@ -137,3 +209,56 @@ void qmpPlistWindow::on_lwFiles_itemDoubleClicked()
{
emit selectionChanging();
}
+
+void qmpPlistWindow::on_pbSave_clicked()
+{
+ QSettings* plist=new QSettings(QFileDialog::getSaveFileName(this,"Save playlist",""),
+ QSettings::IniFormat);
+ plist->setValue("Playlist/FileCount",ui->lwFiles->count());
+ for(int i=0;i<ui->lwFiles->count();++i)
+ plist->setValue("Playlist/File"+QString("%1").arg(i+1,5,10,QChar('0')),ui->lwFiles->item(i)->text());
+ plist->setValue("Playlist/Repeat",repeat);
+ plist->setValue("Playlist/Shuffle",shuffle);
+ plist->sync();
+ delete plist;
+}
+
+void qmpPlistWindow::on_pbLoad_clicked()
+{
+ QSettings* plist=new QSettings(QFileDialog::getOpenFileName(this,"Load playlist",""),
+ QSettings::IniFormat);
+ int fc=plist->value("Playlist/FileCount",0).toInt();
+ if(!fc)return;
+ ui->lwFiles->clear();for(int i=1;i<=fc;++i)
+ ui->lwFiles->addItem(plist->value("Playlist/File"+QString("%1").arg(i,5,10,QChar('0')),"").toString());
+ repeat=plist->value("Playlist/Repeat",0).toInt();
+ shuffle=plist->value("Playlist/Shuffle",0).toInt();
+ switch(shuffle)
+ {
+ case 1:
+ ui->pbShuffle->setIcon(QIcon(":/img/shuffle.png"));
+ ui->pbShuffle->setText("Shuffle On");
+ break;
+ case 0:
+ default:
+ ui->pbShuffle->setIcon(QIcon(":/img/shuffle-off.png"));
+ ui->pbShuffle->setText("Shuffle Off");
+ break;
+ }
+ switch(repeat)
+ {
+ case 0:
+ ui->pbRepeat->setIcon(QIcon(":/img/repeat-non.png"));
+ ui->pbRepeat->setText("Repeat Off");
+ break;
+ case 1:
+ ui->pbRepeat->setIcon(QIcon(":/img/repeat-one.png"));
+ ui->pbRepeat->setText("Repeat One");
+ break;
+ case 2:
+ ui->pbRepeat->setIcon(QIcon(":/img/repeat-all.png"));
+ ui->pbRepeat->setText("Repeat All");
+ break;
+ }
+ delete plist;
+}
diff --git a/qmpplistwindow.hpp b/qmpplistwindow.hpp
index 17d7420..4c67009 100644
--- a/qmpplistwindow.hpp
+++ b/qmpplistwindow.hpp
@@ -2,7 +2,9 @@
#define QMPPLISTWINDOW_H
#include <QDialog>
+#include <QShowEvent>
#include <QCloseEvent>
+#include <QMoveEvent>
#include <QListWidgetItem>
namespace Ui {
@@ -16,7 +18,9 @@ class qmpPlistWindow : public QDialog
public:
explicit qmpPlistWindow(QWidget *parent=0);
~qmpPlistWindow();
+ void showEvent(QShowEvent *event);
void closeEvent(QCloseEvent *event);
+ void moveEvent(QMoveEvent *event);
int getRepeat();
QString getFirstItem();
QString getNextItem();
@@ -43,6 +47,10 @@ class qmpPlistWindow : public QDialog
void on_lwFiles_itemDoubleClicked();
+ void on_pbSave_clicked();
+
+ void on_pbLoad_clicked();
+
private:
Ui::qmpPlistWindow *ui;
int shuffle,repeat;//rep 0=off 1=one 2=all
diff --git a/qmppresetselect.cpp b/qmppresetselect.cpp
index 46c0e6d..d4dd38a 100644
--- a/qmppresetselect.cpp
+++ b/qmppresetselect.cpp
@@ -20,7 +20,7 @@ void qmpPresetSelector::showEvent(QShowEvent *e)
e->accept();memset(presets,0,sizeof(presets));
CMidiPlayer *plyr=qmpMainWindow::getInstance()->getPlayer();
int sfc=plyr->getSFCount();
- for(int i=0;i<sfc;++i)
+ for(int i=sfc-1;i>=0;--i)
{
fluid_sfont_t* psf=plyr->getSFPtr(i);
fluid_preset_t preset;
diff --git a/qmpsettingswindow.cpp b/qmpsettingswindow.cpp
index 1bb7da9..07fcca6 100644
--- a/qmpsettingswindow.cpp
+++ b/qmpsettingswindow.cpp
@@ -23,7 +23,6 @@ qmpSettingsWindow::qmpSettingsWindow(QWidget *parent) :
qmpSettingsWindow::~qmpSettingsWindow()
{
- settings->sync();
delete settings;
delete ui;
}
@@ -31,6 +30,7 @@ qmpSettingsWindow::~qmpSettingsWindow()
void qmpSettingsWindow::closeEvent(QCloseEvent *event)
{
setVisible(false);
+ settings->sync();
emit dialogClosing();
event->accept();
}
@@ -189,8 +189,33 @@ void qmpSettingsWindow::settingsUpdate()
settings->setValue("Behavior/LoadFolder",ui->cbLoadFolder->isChecked()?1:0);
settings->setValue("Behavior/DialogStatus",ui->cbDialogStatus->isChecked()?1:0);
+ if(!ui->cbDialogStatus->isChecked())
+ {
+ settings->remove("DialogStatus/MainW");
+ settings->remove("DialogStatus/PListW");
+ settings->remove("DialogStatus/PListWShown");
+ settings->remove("DialogStatus/ChnlW");
+ settings->remove("DialogStatus/ChnlWShown");
+ settings->remove("DialogStatus/EfxW");
+ settings->remove("DialogStatus/EfxWShown");
+ }
settings->setValue("Behavior/SaveEfxParam",ui->cbSaveEfxParam->isChecked()?1:0);
+ if(!ui->cbSaveEfxParam->isChecked())
+ {
+ settings->remove("Effects/ChorusEnabled");
+ settings->remove("Effects/ReverbEnabled");
+ settings->remove("Effects/ReverbRoom");
+ settings->remove("Effects/ReverbDamp");
+ settings->remove("Effects/ReverbWidth");
+ settings->remove("Effects/ReverbLevel");
+
+ settings->remove("Effects/ChorusFeedbk");
+ settings->remove("Effects/ChorusLevel");
+ settings->remove("Effects/ChorusRate");
+ settings->remove("Effects/ChorusDepth");
+ settings->remove("Effects/ChorusType");
+ }
settings->sync();
}
diff --git a/qmpsettingswindow.hpp b/qmpsettingswindow.hpp
index ef9dbab..c506de4 100644
--- a/qmpsettingswindow.hpp
+++ b/qmpsettingswindow.hpp
@@ -41,7 +41,7 @@ class qmpSettingsWindow:public QDialog
Ui::qmpSettingsWindow *ui;
void settingsUpdate();
static QSettings *settings;
- public: static const QSettings* getSettingsIntf(){return settings;}
+ public: static QSettings* getSettingsIntf(){return settings;}
};
#endif // QMPSETTINGSWINDOW_H
diff --git a/qmpsettingswindow.ui b/qmpsettingswindow.ui
index c415782..92895bb 100644
--- a/qmpsettingswindow.ui
+++ b/qmpsettingswindow.ui
@@ -387,7 +387,7 @@
<item>
<widget class="QListWidget" name="lwSoundfont">
<property name="dragDropMode">
- <enum>QAbstractItemView::DragDrop</enum>
+ <enum>QAbstractItemView::InternalMove</enum>
</property>
</widget>
</item>