From 84634010422f578b27105bbbaf6b8ee4c1232e86 Mon Sep 17 00:00:00 2001 From: Chris Xiong Date: Sun, 3 Jan 2016 23:15:41 +0800 Subject: Bad Apple. (WTF) --- ChangeLog | 6 +++ README.md | 10 ++-- main.cpp | 4 -- qmpchannelswindow.cpp | 21 +++++++++ qmpchannelswindow.hpp | 4 ++ qmpefxwindow.cpp | 62 ++++++++++++++++++++++--- qmpefxwindow.hpp | 4 +- qmpinfowindow.cpp | 2 +- qmpmainwindow.cpp | 118 ++++++++++++++++++++++++++++++++++++++++++----- qmpmainwindow.hpp | 9 +++- qmpmidiplay.cpp | 49 ++++++++++++++++---- qmpmidiplay.hpp | 8 ++++ qmpplistwindow.cpp | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++ qmpplistwindow.hpp | 8 ++++ qmppresetselect.cpp | 2 +- qmpsettingswindow.cpp | 27 ++++++++++- qmpsettingswindow.hpp | 2 +- qmpsettingswindow.ui | 2 +- 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 #include -#include 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 #include #include +#include #include +#include #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 #include #include +#include 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 #include +#include #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 #include #include +#include #include #include #include @@ -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;tceptrgetEventCount();) { while(tcpaused)std::this_thread::sleep_for(std::chrono::milliseconds(100)); - while(!tcstop&&tceptrgetEventCount()&&ct==midiFile->getEvent(tceptr)->time) + while(!tcstop&&midiFile&&tceptrgetEventCount()&&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 #include #include +#include #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;ilwFiles->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;ilwFiles->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 +#include #include +#include #include 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=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 @@ - QAbstractItemView::DragDrop + QAbstractItemView::InternalMove -- cgit v1.2.3