/[svn]/qsampler/trunk/src/qsamplerChannelFxForm.cpp
ViewVC logotype

Annotation of /qsampler/trunk/src/qsamplerChannelFxForm.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3849 - (hide annotations) (download)
Thu Jan 7 16:18:02 2021 UTC (3 years, 2 months ago) by capela
File size: 11751 byte(s)
- Use <cmath> instead of <math.h> et al.
1 schoenebeck 1667 // qsamplerChannelFxForm.cpp
2     //
3     /****************************************************************************
4 capela 3849 Copyright (C) 2010-2021, rncbc aka Rui Nuno Capela. All rights reserved.
5 schoenebeck 1667 Copyright (C) 2008, Christian Schoenebeck
6    
7     This program is free software; you can redistribute it and/or
8     modify it under the terms of the GNU General Public License
9     as published by the Free Software Foundation; either version 2
10     of the License, or (at your option) any later version.
11    
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     GNU General Public License for more details.
16    
17 capela 2459 You should have received a copy of the GNU General Public License along
18     with this program; if not, write to the Free Software Foundation, Inc.,
19     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 schoenebeck 1667
21     *****************************************************************************/
22    
23     #include "qsamplerAbout.h"
24     #include "qsamplerChannelFxForm.h"
25     #include "qsamplerFxSendsModel.h"
26    
27 schoenebeck 1668 // let's not reinvent the wheel for audio routing
28     #include "qsamplerChannel.h"
29    
30 capela 3849 #include <cmath>
31 schoenebeck 1668
32 schoenebeck 1667 #include <QAbstractButton>
33 schoenebeck 1668 #include <QLineEdit>
34     #include <QHeaderView>
35     #include <QMap>
36 schoenebeck 1667
37 schoenebeck 1668 namespace { // private namespace
38    
39     static const char* _midiControllerName(int iMidiCtrl) {
40     switch (iMidiCtrl) {
41     case 0: return "Bank select MSB";
42     case 1: return "Modulation MSB";
43     case 2: return "Breath Controller";
44     case 4: return "Foot Controller MSB";
45     case 5: return "Portamento Time MSB";
46     case 6: return "(N)RPN Data Byte";
47     case 7: return "Main Volume";
48     case 8: return "Balance";
49     case 10: return "Panorama";
50     case 11: return "Expression";
51     case 12: return "Effect Control 1";
52     case 13: return "Effect Control 2";
53     case 16: return "General Purpose Controller 1";
54     case 17: return "General Purpose Controller 2";
55     case 18: return "General Purpose Controller 3";
56     case 19: return "General Purpose Controller 4";
57     case 32: return "Bank select LSB";
58     case 63: return "LSB for Controllers 0?31";
59     case 64: return "Hold 1";
60     case 65: return "Portamento";
61     case 66: return "Sostenuto";
62     case 67: return "Soft Pedal";
63     case 68: return "Legato Footswitch";
64     case 69: return "Hold 2";
65     case 70: return "Sound Controller 1 (Sound Variation)";
66     case 71: return "Sound Controller 2 (Harmonic Content)";
67     case 72: return "Sound Controller 3 (Release Time)";
68     case 73: return "Sound Controller 4 (Attack Time)";
69     case 74: return "Sound Controller 5 (Brightness)";
70     case 75: return "Sound Controller 6";
71     case 76: return "Sound Controller 7";
72     case 77: return "Sound Controller 8";
73     case 78: return "Sound Controller 9";
74     case 79: return "Sound Controller 10";
75     case 80: return "General Purpose 5";
76     case 81: return "General Purpose 6";
77     case 82: return "General Purpose 7";
78     case 83: return "General Purpose 8";
79     case 84: return "Portamento Control";
80     case 91: return "Effects 1 Depth";
81     case 92: return "Effects 2 Depth";
82     case 93: return "Effects 3 Depth";
83     case 94: return "Effects 4 Depth";
84     case 95: return "Effects 5 Depth";
85     case 96: return "Data Increment (N)RPN";
86     case 97: return "Data Decrement (N)RPN";
87     case 98: return "NRPN LSB";
88     case 99: return "NRPN MSB";
89     case 100: return "RPN LSB";
90     case 101: return "RPN MSB";
91     case 120: return "All Sounds Off";
92     case 121: return "Controller Reset";
93     case 122: return "Local Control on/off";
94     case 123: return "All Notes Off";
95     case 124: return "Omni Off";
96     case 125: return "Omni On";
97     case 126: return "Mono On / Poly Off";
98     case 127: return "Poly On / Mono Off";
99     default: return "";
100     }
101     }
102    
103     } // private namespace
104    
105    
106 schoenebeck 1667 namespace QSampler {
107    
108 capela 3758 ChannelFxForm::ChannelFxForm ( Channel *pSamplerChannel, QWidget *pParent )
109     : QDialog(pParent)
110 schoenebeck 1667 {
111     m_ui.setupUi(this);
112    
113 schoenebeck 1668 m_pSamplerChannel = pSamplerChannel;
114 schoenebeck 1667
115 capela 3555 m_pAudioDevice = nullptr;
116 schoenebeck 1668
117 schoenebeck 1667 FxSendsModel* pModel =
118 schoenebeck 1668 new FxSendsModel(m_pSamplerChannel->channelID(), m_ui.SendsListView);
119 schoenebeck 1667 m_ui.SendsListView->setModel(pModel);
120 capela 1706 m_ui.SendsListView->setSelectionRectVisible(true);
121 schoenebeck 1667
122 schoenebeck 1668 const int iRowHeight = m_ui.audioRoutingTable->fontMetrics().height() + 4;
123     m_ui.audioRoutingTable->verticalHeader()->setDefaultSectionSize(iRowHeight);
124     m_ui.audioRoutingTable->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft);
125     ChannelRoutingModel* pRoutingModel =
126     new ChannelRoutingModel(m_ui.audioRoutingTable);
127     m_ui.audioRoutingTable->setModel(pRoutingModel);
128     ChannelRoutingDelegate* pRoutingDelegate =
129     new ChannelRoutingDelegate(m_ui.audioRoutingTable);
130     m_ui.audioRoutingTable->setItemDelegate(pRoutingDelegate);
131 capela 3520 #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
132 capela 2388 m_ui.audioRoutingTable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
133     #else
134 schoenebeck 1668 m_ui.audioRoutingTable->horizontalHeader()->setResizeMode(0, QHeaderView::Stretch);
135 capela 2387 #endif
136 schoenebeck 1668 // m_ui.audioRoutingTable->verticalHeader()->hide();
137    
138 schoenebeck 1667 QAbstractButton* pApplyButton =
139     m_ui.buttonBox->button(QDialogButtonBox::Apply);
140     pApplyButton->setEnabled(false);
141 capela 2074 pApplyButton->setIcon(QIcon(":/images/formEdit.png"));
142 schoenebeck 1667
143     QAbstractButton* pCancelButton =
144     m_ui.buttonBox->button(QDialogButtonBox::Cancel);
145 capela 2074 pCancelButton->setIcon(QIcon(":/images/formRemove.png"));
146 schoenebeck 1667
147     QAbstractButton* pOkButton =
148     m_ui.buttonBox->button(QDialogButtonBox::Ok);
149 capela 2074 pOkButton->setIcon(QIcon(":/images/formAccept.png"));
150 schoenebeck 1667
151     QAbstractButton* pResetButton =
152     m_ui.buttonBox->button(QDialogButtonBox::Reset);
153     pResetButton->setEnabled(false);
154 schoenebeck 1668 pResetButton->setToolTip("Revert all changes.");
155 schoenebeck 1667
156     m_ui.destroyPushButton->setEnabled(false);
157    
158 schoenebeck 1668 m_ui.mainParametersGroupBox->setEnabled(false);
159     m_ui.audioRoutingGroupBox->setEnabled(false);
160    
161     for (int i = 0; i < 128; ++i) {
162     m_ui.depthCtrlComboBox->addItem(
163     QString("[") + QString::number(i) + "] " + _midiControllerName(i)
164     );
165     }
166    
167 schoenebeck 1667 connect(
168     m_ui.buttonBox, SIGNAL(clicked(QAbstractButton*)),
169     this, SLOT(onButtonClicked(QAbstractButton*))
170     );
171     connect(
172     m_ui.createPushButton, SIGNAL(clicked()),
173     this, SLOT(onCreateFxSend())
174     );
175     connect(
176     m_ui.destroyPushButton, SIGNAL(clicked()),
177     this, SLOT(onDestroyFxSend())
178     );
179     connect(
180     pModel, SIGNAL(fxSendsDirtyChanged(bool)),
181     pApplyButton, SLOT(setEnabled(bool))
182     );
183     connect(
184     pModel, SIGNAL(fxSendsDirtyChanged(bool)),
185     pResetButton, SLOT(setEnabled(bool))
186     );
187     connect(
188     m_ui.SendsListView, SIGNAL(clicked(const QModelIndex&)),
189     this, SLOT(onFxSendSelection(const QModelIndex&))
190     );
191 schoenebeck 1668 connect(
192     m_ui.depthCtrlComboBox, SIGNAL(activated(int)),
193     this, SLOT(onDepthCtrlChanged(int))
194     );
195     connect(
196     m_ui.depthSpinBox, SIGNAL(valueChanged(int)),
197     this, SLOT(onCurrentSendDepthChanged(int))
198     );
199     connect(
200     pRoutingModel, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)),
201     this, SLOT(updateTableCellRenderers(const QModelIndex&, const QModelIndex&))
202     );
203     connect(
204     pRoutingModel, SIGNAL(modelReset()),
205     this, SLOT(updateTableCellRenderers())
206     );
207     connect(
208     pRoutingModel, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)),
209     this, SLOT(onRoutingTableChanged())
210     );
211 schoenebeck 1667 }
212    
213     ChannelFxForm::~ChannelFxForm() {
214 schoenebeck 1668 if (m_pAudioDevice) delete m_pAudioDevice;
215 schoenebeck 1667 }
216    
217     void ChannelFxForm::onButtonClicked(QAbstractButton* button) {
218     FxSendsModel* pModel = (FxSendsModel*) m_ui.SendsListView->model();
219     switch (m_ui.buttonBox->buttonRole(button)) {
220     case QDialogButtonBox::AcceptRole:
221     case QDialogButtonBox::ApplyRole:
222     pModel->applyToSampler();
223 schoenebeck 1668 // force a refresh of the parameter control elements
224     onFxSendSelection(m_ui.SendsListView->currentIndex());
225 schoenebeck 1667 break;
226     case QDialogButtonBox::ResetRole:
227     pModel->cleanRefresh();
228 schoenebeck 1668 // force a refresh of the parameter control elements
229     onFxSendSelection(m_ui.SendsListView->currentIndex());
230 schoenebeck 1667 break;
231     default: // to avoid gcc warnings
232     break;
233     }
234     }
235    
236     void ChannelFxForm::onFxSendSelection(const QModelIndex& index) {
237 schoenebeck 1668 const bool bValid = index.isValid();
238     m_ui.destroyPushButton->setEnabled(bValid);
239     m_ui.mainParametersGroupBox->setEnabled(bValid);
240     m_ui.audioRoutingGroupBox->setEnabled(bValid);
241    
242     FxSendsModel* pModel = (FxSendsModel*) m_ui.SendsListView->model();
243     FxSend* pFxSend = pModel->fxSend(index);
244    
245     // clear routing model
246     ChannelRoutingModel* pRoutingModel =
247     (ChannelRoutingModel*) m_ui.audioRoutingTable->model();
248 capela 3555 pRoutingModel->refresh(nullptr, ChannelRoutingMap());
249 schoenebeck 1668 pRoutingModel->routingMap().clear(); // Reset routing change map.
250     if (m_pAudioDevice) {
251     delete m_pAudioDevice;
252 capela 3555 m_pAudioDevice = nullptr;
253 schoenebeck 1668 }
254    
255     if (!pFxSend) return;
256    
257     // update routing model
258     if (m_pSamplerChannel->audioDevice() >= 0) {
259     m_pAudioDevice =
260     new Device(Device::Audio, m_pSamplerChannel->audioDevice());
261     pRoutingModel->refresh(m_pAudioDevice, pFxSend->audioRouting());
262     }
263    
264     m_ui.depthCtrlComboBox->setCurrentIndex(pFxSend->sendDepthMidiCtrl());
265     m_ui.depthSpinBox->setValue(
266 capela 1671 int(::round(pFxSend->currentDepth() * 100.0))
267 schoenebeck 1668 );
268 schoenebeck 1667 }
269    
270     void ChannelFxForm::onCreateFxSend() {
271     FxSendsModel* pModel = (FxSendsModel*) m_ui.SendsListView->model();
272     pModel->addFxSend();
273     }
274    
275     void ChannelFxForm::onDestroyFxSend() {
276     FxSendsModel* pModel = (FxSendsModel*) m_ui.SendsListView->model();
277     pModel->removeFxSend(m_ui.SendsListView->currentIndex());
278     }
279    
280 schoenebeck 1668 void ChannelFxForm::onDepthCtrlChanged(int iMidiCtrl) {
281     FxSendsModel* pModel = (FxSendsModel*) m_ui.SendsListView->model();
282     const QModelIndex index = m_ui.SendsListView->currentIndex();
283     FxSend* pFxSend = pModel->fxSend(index);
284     if (!pFxSend) return;
285    
286     pFxSend->setSendDepthMidiCtrl(iMidiCtrl);
287     pModel->onExternalModifiication(index);
288     }
289    
290     void ChannelFxForm::onCurrentSendDepthChanged(int depthPercent) {
291     FxSendsModel* pModel = (FxSendsModel*) m_ui.SendsListView->model();
292     const QModelIndex index = m_ui.SendsListView->currentIndex();
293     FxSend* pFxSend = pModel->fxSend(index);
294     if (!pFxSend) return;
295    
296     if (depthPercent == int( ::round(pFxSend->currentDepth() * 100.0) ))
297     return; // nothing changed actually
298    
299     pFxSend->setCurrentDepth(double(depthPercent) / 100.0);
300     pModel->onExternalModifiication(index);
301     }
302    
303     void ChannelFxForm::onRoutingTableChanged() {
304     ChannelRoutingModel* pRoutingModel =
305     (ChannelRoutingModel*) m_ui.audioRoutingTable->model();
306     if (pRoutingModel->routingMap().size() <= 0)
307     return; // no changes
308    
309     FxSendsModel* pModel = (FxSendsModel*) m_ui.SendsListView->model();
310     const QModelIndex index = m_ui.SendsListView->currentIndex();
311     FxSend* pFxSend = pModel->fxSend(index);
312     if (!pFxSend) {
313     pRoutingModel->routingMap().clear(); // reset routing change map
314     return;
315     }
316    
317     ChannelRoutingMap routingMap = pRoutingModel->routingMap();
318     for (
319     ChannelRoutingMap::iterator iter = routingMap.begin();
320     iter != routingMap.end(); ++iter
321     ) pFxSend->setAudioChannel(iter.key(), iter.value());
322    
323     pRoutingModel->routingMap().clear(); // reset routing change map
324    
325     pModel->onExternalModifiication(index);
326     }
327    
328     void ChannelFxForm::updateTableCellRenderers() {
329     ChannelRoutingModel* pRoutingModel =
330     (ChannelRoutingModel*) m_ui.audioRoutingTable->model();
331     const int rows = pRoutingModel->rowCount();
332     const int cols = pRoutingModel->columnCount();
333     updateTableCellRenderers(
334     pRoutingModel->index(0, 0),
335     pRoutingModel->index(rows - 1, cols - 1)
336     );
337     }
338    
339     void ChannelFxForm::updateTableCellRenderers (
340     const QModelIndex& topLeft, const QModelIndex& bottomRight )
341     {
342     ChannelRoutingModel* pRoutingModel =
343     (ChannelRoutingModel*) m_ui.audioRoutingTable->model();
344     for (int r = topLeft.row(); r <= bottomRight.row(); r++) {
345     for (int c = topLeft.column(); c <= bottomRight.column(); c++) {
346     const QModelIndex index = pRoutingModel->index(r, c);
347     m_ui.audioRoutingTable->openPersistentEditor(index);
348     }
349     }
350     }
351    
352 schoenebeck 1667 } // namespace QSampler
353    
354     // end of qsamplerChannelFxForm.cpp

  ViewVC Help
Powered by ViewVC