aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Chris Xiong <chirs241097@gmail.com> 2019-09-10 23:55:48 +0800
committerGravatar Chris Xiong <chirs241097@gmail.com> 2019-09-10 23:55:48 +0800
commitaec5e972e8968255e8843eb22314b96a8f23b041 (patch)
tree55990275b78a10188f7ec08436e748cc01461a91
parent1e0c10a001c61d27b210ae87652be849cbd5bcfe (diff)
downloadQMidiPlayer-aec5e972e8968255e8843eb22314b96a8f23b041.tar.xz
We refactorin', eh? Hell yeah.
(Almost) Completely rewritten qmpChannelsWindow, one of the oldest component, now with a dedicated data model. Removed dumb design (CMidiPlayer::getChstates). Now QMidiPlayer requires C++14 to build. More refactoring like this coming up soon.
-rw-r--r--ChangeLog9
-rw-r--r--INSTALL.md2
-rw-r--r--core/qmpmidiplay.cpp6
-rw-r--r--core/qmpmidiplay.hpp5
-rw-r--r--qmidiplayer-desktop/qmidiplayer-desktop.pro2
-rw-r--r--qmidiplayer-desktop/qmpchannelswindow.cpp387
-rw-r--r--qmidiplayer-desktop/qmpchannelswindow.hpp50
-rw-r--r--qmidiplayer-desktop/qmpchannelswindow.ui75
-rw-r--r--qmidiplayer-desktop/qmpmainwindow.cpp5
9 files changed, 299 insertions, 242 deletions
diff --git a/ChangeLog b/ChangeLog
index f567985..d22e5b6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2019-09-10 0.8.7 indev
+We refactorin', eh? Hell yeah.
+
+(Almost) Completely rewritten qmpChannelsWindow, one of the oldest
+component, now with a dedicated data model.
+Removed dumb design (CMidiPlayer::getChstates).
+Now QMidiPlayer requires C++14 to build.
+More refactoring like this coming up soon.
+
2019-07-01 0.8.7 indev
Actually send initialization sequence to external devices.
diff --git a/INSTALL.md b/INSTALL.md
index 37995d3..fedeba9 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -5,7 +5,7 @@ Dependencies:
> libfluidsynth 2.x, Qt5, Qt quick controls(lite version) and RtMidi.
-C++11 is _required_ to build the project.
+C++14 is _required_ to build the project.
To build the default visualization plugin, you need the latest SMELT library
(along with all its dependencies), which can be found
diff --git a/core/qmpmidiplay.cpp b/core/qmpmidiplay.cpp
index 6ff465f..46a2dae 100644
--- a/core/qmpmidiplay.cpp
+++ b/core/qmpmidiplay.cpp
@@ -22,6 +22,8 @@ bool CMidiPlayer::processEvent(const SEvent *e)
for(auto i=event_handlers.begin();i!=event_handlers.end();++i)
i->second.first((void*)e,i->second.second);
uint8_t ch=e->type&0x0F;
+ if((e->type&0xF0)<0xF0)
+ levtt[ch]=std::chrono::system_clock::now();
switch(e->type&0xF0)
{
case 0x80://Note off
@@ -29,7 +31,6 @@ bool CMidiPlayer::processEvent(const SEvent *e)
case 0x90://Note on
if((mute>>ch)&1&&e->p2)return false;//muted
if(solo&&!((solo>>ch)&1)&&e->p2)return false;//excluded by solo flags
- if(e->p2)chstate[ch]=1;
return true;
case 0xB0://CC
if(e->p1==100)rpnid[ch]=e->p2;
@@ -505,7 +506,8 @@ void CMidiPlayer::setChannelOutput(int ch,int outid)
dold.dev->onUnmapped(ch,--dold.refcnt);
}
}
-uint8_t* CMidiPlayer::getChstates(){return chstate;}
+const std::chrono::system_clock::time_point* CMidiPlayer::getLastEventTS()
+{return levtt;}
int CMidiPlayer::setEventHandlerCB(ICallBack *cb,void *userdata)
{
for(int i=0;i<16;++i)
diff --git a/core/qmpmidiplay.hpp b/core/qmpmidiplay.hpp
index da9e9ef..4d950fa 100644
--- a/core/qmpmidiplay.hpp
+++ b/core/qmpmidiplay.hpp
@@ -64,7 +64,7 @@ class CMidiPlayer
uint16_t mute,solo;
double ftime;
bool sendSysEx,waitvoice;
- uint8_t chstate[16],chstatus[16][130];//0..127: cc 128: pc
+ uint8_t chstatus[16][130];//0..127: cc 128: pc
qmpMidiOutFluid* internalFluid;
uint32_t ctempo,ctsn,ctsd,divs,cks;
double dpt;//time per tick
@@ -76,6 +76,7 @@ class CMidiPlayer
//playback correction
uint32_t ttick;
std::chrono::high_resolution_clock::time_point ttime;
+ std::chrono::system_clock::time_point levtt[16];
struct SMidiDev
{
std::string name;
@@ -155,7 +156,7 @@ class CMidiPlayer
int getChannelOutput(int ch);
qmpMidiOutDevice* getChannelOutputDevice(int ch);
void setChannelOutput(int ch,int outid);
- uint8_t* getChstates();
+ const std::chrono::system_clock::time_point* getLastEventTS();
int setEventHandlerCB(ICallBack *cb,void *userdata);
void unsetEventHandlerCB(int id);
int setEventReaderCB(ICallBack *cb,void *userdata);
diff --git a/qmidiplayer-desktop/qmidiplayer-desktop.pro b/qmidiplayer-desktop/qmidiplayer-desktop.pro
index 3d127bb..193c0e5 100644
--- a/qmidiplayer-desktop/qmidiplayer-desktop.pro
+++ b/qmidiplayer-desktop/qmidiplayer-desktop.pro
@@ -11,7 +11,7 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = qmidiplayer
TEMPLATE = app
-CONFIG += c++11
+CONFIG += c++14
SOURCES += main.cpp\
qmpmainwindow.cpp \
diff --git a/qmidiplayer-desktop/qmpchannelswindow.cpp b/qmidiplayer-desktop/qmpchannelswindow.cpp
index b029e3e..0c34239 100644
--- a/qmidiplayer-desktop/qmpchannelswindow.cpp
+++ b/qmidiplayer-desktop/qmpchannelswindow.cpp
@@ -1,20 +1,252 @@
#include <cstdio>
+#include <functional>
#include <QCheckBox>
#include <QPushButton>
#include <QComboBox>
+#include <QTimer>
#include "qmpchannelswindow.hpp"
#include "ui_qmpchannelswindow.h"
#include "qmpmainwindow.hpp"
+qmpChannelsModel::qmpChannelsModel(QObject*parent):QAbstractTableModel(parent)
+{
+ evh=qmpMainWindow::getInstance()->getPlayer()->registerEventHandler(
+ [this](const void* _e,void*){
+ if(!updatequeued)
+ {
+ updatequeued=true;
+ const SEvent *e=(const SEvent*)(_e);
+ if((e->p1&0xF0)==0xC0)
+ emit dataChanged(index(e->p1&0xF0,4),index(e->p1&0xF0,4),{Qt::ItemDataRole::DisplayRole});
+ QMetaObject::invokeMethod(this, &qmpChannelsModel::updateChannelActivity, Qt::ConnectionType::QueuedConnection);
+ }
+ }
+ ,nullptr);
+ QTimer*t=new QTimer(this);
+ t->setInterval(500);
+ t->setSingleShot(false);
+ connect(t,&QTimer::timeout,[this](){emit this->dataChanged(this->index(0,4),this->index(15,4),{Qt::ItemDataRole::DisplayRole});});
+ memset(mute,0,sizeof(mute));
+ memset(solo,0,sizeof(solo));
+}
+int qmpChannelsModel::columnCount(const QModelIndex&parent)const
+{return parent.isValid()?0:6;}
+int qmpChannelsModel::rowCount(const QModelIndex&parent)const
+{return parent.isValid()?0:16;}
+QModelIndex qmpChannelsModel::parent(const QModelIndex&child)const
+{
+ Q_UNUSED(child)
+ return QModelIndex();
+}
+QVariant qmpChannelsModel::data(const QModelIndex&index,int role)const
+{
+ switch(index.column())
+ {
+ case 0:
+ if(role==Qt::ItemDataRole::DecorationRole)
+ {
+ using namespace std::chrono_literals;
+ bool lit=(std::chrono::system_clock::now()-qmpMainWindow::getInstance()->getPlayer()->getLastEventTS()[index.row()])<50ms;
+ return lit?QIcon(":/img/ledon.svg"):QIcon(":/img/ledoff.svg");
+ }
+ break;
+ case 1:
+ if(role==Qt::ItemDataRole::CheckStateRole)
+ return mute[index.row()]?Qt::CheckState::Checked:Qt::CheckState::Unchecked;
+ break;
+ case 2:
+ if(role==Qt::ItemDataRole::CheckStateRole)
+ return solo[index.row()]?Qt::CheckState::Checked:Qt::CheckState::Unchecked;
+ break;
+ case 3:
+ if(role==Qt::ItemDataRole::DisplayRole)
+ {
+ std::vector<std::string> devs=qmpMainWindow::getInstance()->getPlayer()->getMidiOutDevices();
+ return QString::fromStdString(devs[qmpMainWindow::getInstance()->getPlayer()->getChannelOutput(index.row())]);
+ }
+ break;
+ case 4:
+ {
+ if(role==Qt::ItemDataRole::DisplayRole)
+ {
+ int ch=index.row();
+ uint16_t b;uint8_t p;
+ std::string nm;
+ char data[256];
+ CMidiPlayer *plyr=qmpMainWindow::getInstance()->getPlayer();
+ bool r=plyr->getChannelOutputDevice(ch)->getChannelPreset(ch,&b,&p,nm);
+ sprintf(data,"%03d:%03d %s",b,p,nm.c_str());
+ if(!r)
+ {
+ nm=plyr->getChannelOutputDevice(ch)->getPresetName(plyr->getCC(ch,0)<<7|plyr->getCC(ch,32),plyr->getCC(ch,128));
+ sprintf(data,"%03d:%03d:%03d %s",plyr->getCC(ch,0),plyr->getCC(ch,32),plyr->getCC(ch,128),nm.c_str());
+ }
+ return QString(data);
+ }
+ }
+ break;
+ case 5:
+ if(role==Qt::ItemDataRole::DisplayRole)
+ return "...";
+ if(role==Qt::ItemDataRole::TextAlignmentRole)
+ return Qt::AlignmentFlag::AlignCenter;
+ break;
+ }
+ return QVariant();
+}
+QVariant qmpChannelsModel::headerData(int section,Qt::Orientation orientation,int role)const
+{
+ if(role!=Qt::ItemDataRole::DisplayRole)return QVariant();
+ if(orientation==Qt::Orientation::Vertical)
+ return section+1;
+ switch(section)
+ {
+ case 0:return QString("A");
+ case 1:return QString("M");
+ case 2:return QString("S");
+ case 3:return QString("Device");
+ case 4:return QString("Preset");
+ case 5:return QString("...");
+ }
+ return QString();
+}
+Qt::ItemFlags qmpChannelsModel::flags(const QModelIndex&idx)const
+{
+ Qt::ItemFlags ret=Qt::ItemFlag::ItemIsEnabled|Qt::ItemFlag::ItemIsSelectable;
+ if(idx.column()==1||idx.column()==2)
+ ret|=Qt::ItemFlag::ItemIsUserCheckable;
+ if(idx.column()==3)
+ ret|=Qt::ItemFlag::ItemIsEditable;
+ return ret;
+}
+void qmpChannelsModel::updateChannelActivity()
+{
+ emit dataChanged(index(0,0),index(15,0),{Qt::ItemDataRole::DecorationRole});
+ updatequeued=false;
+}
+void qmpChannelsModel::channelMSClicked(const QModelIndex&idx)
+{
+ bool*x[3]={nullptr,mute,solo};
+ if(x[idx.column()][idx.row()]^=1)
+ x[3-idx.column()][idx.row()]=0;
+ qmpMainWindow::getInstance()->getPlayer()->setMute(idx.row(),mute[idx.row()]);
+ qmpMainWindow::getInstance()->getPlayer()->setSolo(idx.row(),solo[idx.row()]);
+ emit dataChanged(index(idx.row(),1),index(idx.row(),2),{Qt::ItemDataRole::CheckStateRole});
+}
+void qmpChannelsModel::channelMSClearAll(int type)
+{
+ if(type==1)
+ {
+ memset(mute,0,sizeof(mute));
+ for(int i=0;i<16;++i)
+ qmpMainWindow::getInstance()->getPlayer()->setMute(i,0);
+ emit dataChanged(index(0,1),index(15,1),{Qt::ItemDataRole::CheckStateRole});
+ }
+ if(type==2)
+ {
+ memset(solo,0,sizeof(solo));
+ for(int i=0;i<16;++i)
+ qmpMainWindow::getInstance()->getPlayer()->setSolo(i,0);
+ emit dataChanged(index(0,2),index(15,2),{Qt::ItemDataRole::CheckStateRole});
+ }
+}
+
+qmpDeviceItemDelegate::qmpDeviceItemDelegate(QWidget*parent):QStyledItemDelegate(parent),par(parent)
+{}
+void qmpDeviceItemDelegate::paint(QPainter*painter,const QStyleOptionViewItem&option,const QModelIndex&index)const
+{
+ QStyleOptionViewItem opt;
+ initStyleOption(&opt,index);
+ QStyleOptionComboBox socb;
+ socb.currentText=opt.text;
+ socb.editable=false;
+ socb.rect=option.rect;
+ par->style()->drawComplexControl(QStyle::ComplexControl::CC_ComboBox,&socb,painter);
+ par->style()->drawControl(QStyle::CE_ComboBoxLabel,&socb,painter);
+}
+QSize qmpDeviceItemDelegate::sizeHint(const QStyleOptionViewItem&option,const QModelIndex&index)const
+{
+ QStyleOptionViewItem opt;
+ initStyleOption(&opt,index);
+ QStyleOptionComboBox socb;
+ socb.currentText=opt.text;
+ socb.editable=false;
+ socb.rect=option.rect;
+ QSize sz=par->fontMetrics().size(Qt::TextFlag::TextSingleLine,socb.currentText);
+ return par->style()->sizeFromContents(QStyle::ContentsType::CT_ComboBox,&socb,sz);
+}
+QWidget* qmpDeviceItemDelegate::createEditor(QWidget*parent,const QStyleOptionViewItem&option,const QModelIndex&index)const
+{
+ Q_UNUSED(option)
+ Q_UNUSED(index)
+ QComboBox *cb=new QComboBox(parent);
+ cb->setEditable(false);
+ return cb;
+}
+void qmpDeviceItemDelegate::setEditorData(QWidget*widget,const QModelIndex&index)const
+{
+ /*
+ * We want to quit editing as soon as the popup of the combobox is closed.
+ * Unfortunately QTableView does not do that. And I don't feel like sub-classing
+ * it. So here are some dirty tricks to make it work that way.
+ */
+ QComboBox *cb=qobject_cast<QComboBox*>(widget);
+ QSignalBlocker sblk(cb);
+ cb->clear();
+ std::vector<std::string> devs=qmpMainWindow::getInstance()->getPlayer()->getMidiOutDevices();
+ for(auto s:devs)
+ cb->addItem(QString::fromStdString(s));
+ cb->setCurrentIndex(qmpMainWindow::getInstance()->getPlayer()->getChannelOutput(index.row()));
+ cb->showPopup();
+ connect(cb,static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),[this,index,cb](int id){
+ QTableView*pv=qobject_cast<QTableView*>(this->parent());
+ qmpMainWindow::getInstance()->getPlayer()->setChannelOutput(index.row(),id);
+ emit pv->model()->dataChanged(index,index,{Qt::DisplayRole});
+ cb->hidePopup();
+ });
+}
+void qmpDeviceItemDelegate::setModelData(QWidget*editor,QAbstractItemModel*model,const QModelIndex&index)const
+{
+ QComboBox *cb=qobject_cast<QComboBox*>(editor);
+ qmpMainWindow::getInstance()->getPlayer()->setChannelOutput(index.row(),cb->currentIndex());
+ emit model->dataChanged(index,index,{Qt::DisplayRole});
+}
+void qmpDeviceItemDelegate::updateEditorGeometry(QWidget*editor,const QStyleOptionViewItem&option,const QModelIndex&index)const
+{
+ Q_UNUSED(index)
+ editor->setGeometry(option.rect);
+}
+
qmpChannelsWindow::qmpChannelsWindow(QWidget *parent) :
QWidget(parent,Qt::Dialog),
ui(new Ui::qmpChannelsWindow)
{
ui->setupUi(this);
+ ui->tvChannels->setHorizontalHeader(new QHeaderView(Qt::Orientation::Horizontal));
+ ui->tvChannels->setModel(chmodel=new qmpChannelsModel);
+ ui->tvChannels->setItemDelegateForColumn(3,new qmpDeviceItemDelegate(ui->tvChannels));
+ ui->tvChannels->setAlternatingRowColors(true);
+ ui->tvChannels->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection);
+ ui->tvChannels->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeMode::ResizeToContents);
+ ui->tvChannels->horizontalHeader()->setSectionResizeMode(4, QHeaderView::ResizeMode::Stretch);
+ connect(ui->tvChannels,&QTableView::clicked,[this](const QModelIndex&idx){
+ if(idx.column()==1||idx.column()==2)
+ this->chmodel->channelMSClicked(idx);
+ if(idx.column()==3)
+ this->ui->tvChannels->edit(idx);
+ if(idx.column()==5)
+ this->showChannelEditorWindow(idx.row());
+ });
+ connect(ui->tvChannels,&QTableView::activated,[this](const QModelIndex&idx){
+ if(idx.column()==4)
+ {
+ pselectw->show();
+ pselectw->setupWindow(idx.row());
+ }
+ });
pselectw=new qmpPresetSelector(this);
ceditw=new qmpChannelEditor(this);
cha=new QIcon(":/img/ledon.svg");chi=new QIcon(":/img/ledoff.svg");
- fused=callbacksc=cbcnt=0;
eh=qmpMainWindow::getInstance()->getPlayer()->registerEventHandler(
[this](const void *ee,void*){
const SEvent *e=(const SEvent*)ee;
@@ -22,7 +254,6 @@ qmpChannelsWindow::qmpChannelsWindow(QWidget *parent) :
emit this->noteOn();
}
,nullptr);
- connect(this,&qmpChannelsWindow::noteOn,this,&qmpChannelsWindow::updateChannelActivity);
std::vector<std::string> devs=qmpMainWindow::getInstance()->getPlayer()->getMidiOutDevices();
size_t devc=devs.size();
//We setup default output here...
@@ -34,50 +265,18 @@ qmpChannelsWindow::qmpChannelsWindow(QWidget *parent) :
value("Midi/DefaultOutput","Internal FluidSynth").toString()))
qmpSettingsWindow::getDefaultOutWidget()->setCurrentIndex(i);
}
- qmpSettingsWindow::getSettingsIntf()->setValue("Midi/DefaultOutput",
- qmpSettingsWindow::getDefaultOutWidget()->currentText());
- qmpSettingsWindow::getSettingsIntf();
- for(int i=0;i<16;++i)
+ for(int ch=0;ch<16;++ch)
{
- ui->twChannels->setItem(i,0,new QTableWidgetItem());
- ui->twChannels->item(i,0)->setIcon(*chi);
- ui->twChannels->item(i,0)->setFlags(ui->twChannels->item(i,0)->flags()^Qt::ItemIsEditable);
- ui->twChannels->setCellWidget(i,1,new QCheckBox(""));
- connect(ui->twChannels->cellWidget(i,1),SIGNAL(stateChanged(int)),this,SLOT(channelMSChanged()));
- ui->twChannels->setCellWidget(i,2,new QCheckBox(""));
- connect(ui->twChannels->cellWidget(i,2),SIGNAL(stateChanged(int)),this,SLOT(channelMSChanged()));
- ui->twChannels->setCellWidget(i,3,new QDCComboBox());
- QDCComboBox *cb=(QDCComboBox*)ui->twChannels->cellWidget(i,3);
- cb->setID(i);
- cb->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Fixed);
for(size_t j=0;j<devc;++j)
{
- cb->addItem(devs[j].c_str());
if(!qmpSettingsWindow::getSettingsIntf()->
value("Midi/DefaultOutput","Internal FluidSynth").toString().compare(
QString(devs[j].c_str())))
- {
- cb->setCurrentIndex(j);
- changeMidiMapping(i,j);
- }
+ qmpMainWindow::getInstance()->getPlayer()->setChannelOutput(ch,j);
}
- if(qmpSettingsWindow::getSettingsIntf()->value("Midi/DisableMapping",0).toInt())
- cb->setEnabled(false);
- connect(cb,SIGNAL(onChange(int,int)),this,SLOT(changeMidiMapping(int,int)));
- ui->twChannels->setItem(i,4,new QTableWidgetItem(""));
- ui->twChannels->item(i,4)->setFlags(Qt::ItemIsEnabled);
- ui->twChannels->setCellWidget(i,5,new QDCPushButton("..."));
- ((QDCPushButton*)ui->twChannels->cellWidget(i,5))->setID(i);
- connect(ui->twChannels->cellWidget(i,5),SIGNAL(onClick(int)),this,SLOT(showChannelEditorWindow(int)));
}
- connect(ui->twChannels,SIGNAL(cellDoubleClicked(int,int)),this,SLOT(showPresetWindow(int,int)));
- ui->twChannels->setColumnWidth(0,24);
- ui->twChannels->setColumnWidth(1,24);
- ui->twChannels->setColumnWidth(2,24);
- ui->twChannels->setColumnWidth(3,192);
- ui->twChannels->setColumnWidth(4,208);
- ui->twChannels->setColumnWidth(5,32);
- ui->twChannels->installEventFilter(this);
+ qmpSettingsWindow::getSettingsIntf()->setValue("Midi/DefaultOutput",
+ qmpSettingsWindow::getDefaultOutWidget()->currentText());
qmpMainWindow::getInstance()->registerFunctionality(
chnlf=new qmpChannelFunc(this),
std::string("Channel"),
@@ -118,82 +317,6 @@ void qmpChannelsWindow::closeEvent(QCloseEvent *event)
event->accept();
}
-void qmpChannelsWindow::resetAcitivity()
-{
- for(int i=0;i<16;++i)ui->twChannels->item(i,0)->setIcon(*chi);
-}
-
-void qmpChannelsWindow::updateChannelActivity()
-{
- ++callbacksc;
- for(int i=0;i<16;++i)
- ui->twChannels->item(i,0)->setIcon(
- qmpMainWindow::getInstance()->getPlayer()->getChstates()[i]?*cha:*chi);
-}
-
-void qmpChannelsWindow::channelWindowsUpdate()
-{
- if(qmpMainWindow::getInstance()->getPlayer()->isFinished())
- {
- for(int i=0;i<16;++i)
- ui->twChannels->item(i,4)->setText("");
- connect(this,&qmpChannelsWindow::noteOn,this,&qmpChannelsWindow::updateChannelActivity);
- fused=0;return;
- }
- ++cbcnt;
- if(cbcnt>15)
- {
- if(callbacksc>8192)
- {
- disconnect(this,&qmpChannelsWindow::noteOn,this,&qmpChannelsWindow::updateChannelActivity);
- fprintf(stderr,"Fuse!\n");fused=1;
- }
- cbcnt=0;
- callbacksc=0;
- }
- for(int i=0;i<16;++i)
- {
- char data[128];
- std::string nm;
- uint16_t b;uint8_t p;
- CMidiPlayer *plyr=qmpMainWindow::getInstance()->getPlayer();
- bool r=plyr->getChannelOutputDevice(i)->getChannelPreset(i,&b,&p,nm);
- sprintf(data,"%03d:%03d %s",b,p,nm.c_str());
- if(!r)
- {
- nm=plyr->getChannelOutputDevice(i)->getPresetName(plyr->getCC(i,0)<<7|plyr->getCC(i,32),plyr->getCC(i,128));
- sprintf(data,"%03d:%03d:%03d %s",plyr->getCC(i,0),plyr->getCC(i,32),plyr->getCC(i,128),nm.c_str());
- }
- if(fused)
- {
- if(strcmp((ui->twChannels->item(i,4))->
- text().toStdString().c_str(),data))
- {
- connect(this,&qmpChannelsWindow::noteOn,this,&qmpChannelsWindow::updateChannelActivity);
- fused=0;
- }
- }
- ui->twChannels->item(i,4)->setText(data);
- ui->twChannels->item(i,0)->setIcon(
- qmpMainWindow::getInstance()->getPlayer()->getChstates()[i]?*cha:*chi);
- if(qmpMainWindow::getInstance()->getPlayer()->getChstates()[i])
- qmpMainWindow::getInstance()->getPlayer()->getChstates()[i]=0;
- }
-}
-
-void qmpChannelsWindow::channelMSChanged()
-{
- for(int i=0;i<16;++i)
- {
- QCheckBox *m,*s;
- m=(QCheckBox*)ui->twChannels->cellWidget(i,1);
- s=(QCheckBox*)ui->twChannels->cellWidget(i,2);
- if(m->isChecked()&&s->isChecked())s->setChecked(false);
- qmpMainWindow::getInstance()->getPlayer()->setMute(i,m->isChecked());
- qmpMainWindow::getInstance()->getPlayer()->setSolo(i,s->isChecked());
- }
-}
-
qmpChannelsWindow::~qmpChannelsWindow()
{
qmpMainWindow::getInstance()->unregisterFunctionality("Channel");
@@ -205,27 +328,12 @@ qmpChannelsWindow::~qmpChannelsWindow()
void qmpChannelsWindow::on_pbUnmute_clicked()
{
- for(int i=0;i<16;++i)
- {
- ((QCheckBox*)ui->twChannels->cellWidget(i,1))->setChecked(false);
- qmpMainWindow::getInstance()->getPlayer()->setMute(i,false);
- }
+ chmodel->channelMSClearAll(1);
}
void qmpChannelsWindow::on_pbUnsolo_clicked()
{
- for(int i=0;i<16;++i)
- {
- ((QCheckBox*)ui->twChannels->cellWidget(i,2))->setChecked(false);
- qmpMainWindow::getInstance()->getPlayer()->setSolo(i,false);
- }
-}
-
-void qmpChannelsWindow::showPresetWindow(int chid,int col)
-{
- if(col!=4)return;
- pselectw->show();
- pselectw->setupWindow(chid);
+ chmodel->channelMSClearAll(2);
}
void qmpChannelsWindow::showChannelEditorWindow(int chid)
@@ -234,23 +342,6 @@ void qmpChannelsWindow::showChannelEditorWindow(int chid)
ceditw->setupWindow(chid);
}
-void qmpChannelsWindow::changeMidiMapping(int chid,int idx)
-{
- qmpMainWindow::getInstance()->getPlayer()->setChannelOutput(chid,idx);
-}
-
-bool qmpChannelsWindow::eventFilter(QObject *o,QEvent *e)
-{
- if(e->type()==QEvent::KeyPress&&ui->twChannels->currentColumn()==4)
- {
- QKeyEvent *ke=static_cast<QKeyEvent*>(e);
- if(ke->key()!=Qt::Key_Enter&&ke->key()!=Qt::Key_Return)return false;
- showPresetWindow(ui->twChannels->currentRow(),4);
- return true;
- }
- return false;
-}
-
qmpChannelFunc::qmpChannelFunc(qmpChannelsWindow *par)
{p=par;}
void qmpChannelFunc::show()
diff --git a/qmidiplayer-desktop/qmpchannelswindow.hpp b/qmidiplayer-desktop/qmpchannelswindow.hpp
index 207ee8d..ab3227f 100644
--- a/qmidiplayer-desktop/qmpchannelswindow.hpp
+++ b/qmidiplayer-desktop/qmpchannelswindow.hpp
@@ -8,6 +8,8 @@
#include <QShowEvent>
#include <QCloseEvent>
#include <QMoveEvent>
+#include <QAbstractTableModel>
+#include <QStyledItemDelegate>
#include "qmppresetselect.hpp"
#include "qmpchanneleditor.hpp"
#include "../core/qmpmidiplay.hpp"
@@ -60,6 +62,42 @@ class qmpChannelFunc:public qmpFuncBaseIntf
void close();
};
+class qmpChannelsModel:public QAbstractTableModel
+{
+ Q_OBJECT
+ public:
+ explicit qmpChannelsModel(QObject*parent=nullptr);
+ int columnCount(const QModelIndex&parent=QModelIndex())const override;
+ int rowCount(const QModelIndex&parent=QModelIndex())const override;
+ QModelIndex parent(const QModelIndex&child)const override;
+ QVariant data(const QModelIndex&index,int role=Qt::ItemDataRole::DisplayRole)const override;
+ QVariant headerData(int section,Qt::Orientation orientation,int role=Qt::ItemDataRole::DisplayRole)const override;
+ Qt::ItemFlags flags(const QModelIndex&idx)const override;
+ public slots:
+ void updateChannelActivity();
+ void channelMSClicked(const QModelIndex&idx);
+ void channelMSClearAll(int type);
+ private:
+ int evh;
+ bool updatequeued;
+ bool mute[16],solo[16];
+};
+
+class qmpDeviceItemDelegate:public QStyledItemDelegate
+{
+ Q_OBJECT
+ public:
+ explicit qmpDeviceItemDelegate(QWidget*parent=nullptr);
+ void paint(QPainter*painter,const QStyleOptionViewItem&option,const QModelIndex&index)const override;
+ QSize sizeHint(const QStyleOptionViewItem&option,const QModelIndex&index)const override;
+ QWidget* createEditor(QWidget*parent,const QStyleOptionViewItem&option,const QModelIndex&index)const override;
+ void setEditorData(QWidget*editor,const QModelIndex&index)const override;
+ void setModelData(QWidget*editor,QAbstractItemModel*model,const QModelIndex&index)const override;
+ void updateEditorGeometry(QWidget*editor,const QStyleOptionViewItem&option,const QModelIndex&index)const override;
+ private:
+ QWidget *par;
+};
+
class qmpChannelsWindow:public QWidget
{
Q_OBJECT
@@ -69,32 +107,22 @@ class qmpChannelsWindow:public QWidget
~qmpChannelsWindow();
void showEvent(QShowEvent *event);
void closeEvent(QCloseEvent *event);
- void resetAcitivity();
public slots:
- void channelWindowsUpdate();
- void updateChannelActivity();
- void channelMSChanged();
- void showPresetWindow(int chid,int col);
void showChannelEditorWindow(int chid);
- void changeMidiMapping(int chid,int idx);
void on_pbUnmute_clicked();
void on_pbUnsolo_clicked();
signals:
void noteOn();
- protected:
- bool eventFilter(QObject *o,QEvent *e);
-
private:
Ui::qmpChannelsWindow *ui;
qmpPresetSelector *pselectw;
qmpChannelEditor *ceditw;
+ qmpChannelsModel *chmodel;
QIcon *cha,*chi;
qmpChannelFunc *chnlf;
int eh;
- //callback fuse... (avoid black midi blocking the main thread)
- int callbacksc,cbcnt,fused;
};
#endif // QMPCHANNELSWINDOW_H
diff --git a/qmidiplayer-desktop/qmpchannelswindow.ui b/qmidiplayer-desktop/qmpchannelswindow.ui
index 2a63d21..2f96395 100644
--- a/qmidiplayer-desktop/qmpchannelswindow.ui
+++ b/qmidiplayer-desktop/qmpchannelswindow.ui
@@ -29,80 +29,7 @@
<item>
<layout class="QVBoxLayout" name="verticalLayout_1">
<item>
- <widget class="QTableWidget" name="twChannels">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="alternatingRowColors">
- <bool>true</bool>
- </property>
- <property name="selectionMode">
- <enum>QAbstractItemView::NoSelection</enum>
- </property>
- <property name="cornerButtonEnabled">
- <bool>false</bool>
- </property>
- <property name="rowCount">
- <number>16</number>
- </property>
- <property name="columnCount">
- <number>6</number>
- </property>
- <row/>
- <row/>
- <row/>
- <row/>
- <row/>
- <row/>
- <row/>
- <row/>
- <row/>
- <row/>
- <row/>
- <row/>
- <row/>
- <row/>
- <row/>
- <row/>
- <column>
- <property name="text">
- <string>A</string>
- </property>
- </column>
- <column>
- <property name="text">
- <string>M</string>
- </property>
- </column>
- <column>
- <property name="text">
- <string>S</string>
- </property>
- </column>
- <column>
- <property name="text">
- <string>Device</string>
- </property>
- </column>
- <column>
- <property name="text">
- <string>Preset</string>
- </property>
- </column>
- <column>
- <property name="text">
- <string>...</string>
- </property>
- </column>
- <item row="0" column="1">
- <property name="text">
- <string/>
- </property>
- </item>
- </widget>
+ <widget class="QTableView" name="tvChannels"/>
</item>
</layout>
</item>
diff --git a/qmidiplayer-desktop/qmpmainwindow.cpp b/qmidiplayer-desktop/qmpmainwindow.cpp
index e037c45..95b2da3 100644
--- a/qmidiplayer-desktop/qmpmainwindow.cpp
+++ b/qmidiplayer-desktop/qmpmainwindow.cpp
@@ -219,7 +219,6 @@ void qmpMainWindow::updateWidgets()
timer->stop();stopped=true;playing=false;
invokeCallback("main.stop",nullptr);
setFuncEnabled("Render",stopped);setFuncEnabled("ReloadSynth",stopped);
- chnlw->resetAcitivity();
player->playerDeinit();playerTh->join();
delete playerTh;playerTh=nullptr;
player->playerPanic(true);
@@ -408,7 +407,7 @@ void qmpMainWindow::on_pbPlayPause_clicked()
{
if(!playing)
{
- player->playerPanic();chnlw->resetAcitivity();
+ player->playerPanic();
offset=ui->hsTimer->value()/100.*player->getFtime();
}
else
@@ -487,7 +486,7 @@ void qmpMainWindow::on_pbStop_clicked()
invokeCallback("main.stop",nullptr);
player->playerDeinit();
setFuncEnabled("Render",stopped);setFuncEnabled("ReloadSynth",stopped);
- player->playerPanic(true);chnlw->resetAcitivity();
+ player->playerPanic(true);
if(playerTh){playerTh->join();delete playerTh;playerTh=nullptr;}
chnlw->on_pbUnmute_clicked();chnlw->on_pbUnsolo_clicked();
ui->pbPlayPause->setIcon(QIcon(getThemedIcon(":/img/play.svg")));