1 /*
2 MIDI Virtual Piano Keyboard
3 Copyright (C) 2008-2021, Pedro Lopez-Cabanillas <plcl@users.sf.net>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <QDebug>
20 #include <QDesktopServices>
21 #include <QInputDialog>
22 #include <QFileDialog>
23 #include <QDir>
24 #include <QMessageBox>
25 #include <QApplication>
26 #include <QCloseEvent>
27 #include <QComboBox>
28 #include <QSlider>
29 #include <QSpinBox>
30 #include <QDial>
31 #include <QToolButton>
32 #include <QToolTip>
33 #include <QVBoxLayout>
34 #include <QTextBrowser>
35 #include <QDialogButtonBox>
36 #include <QDialog>
37 #include <QUrl>
38 #include <QString>
39 #include <QTranslator>
40 #include <QMapIterator>
41 #include <QShortcut>
42 #include <QActionGroup>
43 #include <QStandardPaths>
44
45 #include <drumstick/backendmanager.h>
46 #include <drumstick/rtmidiinput.h>
47 #include <drumstick/rtmidioutput.h>
48 #include <drumstick/pianokeybd.h>
49 #include <drumstick/settingsfactory.h>
50
51 #include "vpiano.h"
52 #include "instrument.h"
53 #include "mididefs.h"
54 #include "constants.h"
55 #include "riffimportdlg.h"
56 #include "extracontrols.h"
57 #include "about.h"
58 #include "preferences.h"
59 #include "midisetup.h"
60 #include "colordialog.h"
61 #include "vpianosettings.h"
62
63 #if !defined(SMALL_SCREEN)
64 #include "kmapdialog.h"
65 #include "shortcutdialog.h"
66 #endif
67
68 #if defined(ENABLE_DBUS)
69 #include "vmpk_adaptor.h"
70 #include <QtDBus/QDBusConnection>
71 #endif
72
73 using namespace drumstick::rt;
74 using namespace drumstick::widgets;
75
VPiano(QWidget * parent,Qt::WindowFlags flags)76 VPiano::VPiano( QWidget * parent, Qt::WindowFlags flags )
77 : QMainWindow(parent, flags),
78 m_midiout(nullptr),
79 m_midiin(nullptr),
80 m_backendManager(nullptr),
81 m_initialized(false),
82 m_filter(nullptr)
83 {
84 #if defined(ENABLE_DBUS)
85 new VmpkAdaptor(this);
86 QDBusConnection dbus = QDBusConnection::sessionBus();
87 dbus.registerObject("/", this);
88 dbus.registerService("net.sourceforge.vmpk");
89 #endif
90 m_trq = new QTranslator(this);
91 m_trp = new QTranslator(this);
92 m_trl = new QTranslator(this);
93 QString lang = VPianoSettings::instance()->language();
94 if (!m_trq->load(QSTR_QTPX + lang, VPianoSettings::systemLocales()) && !lang.startsWith("en")) {
95 qWarning() << "Failure loading Qt5 system translations for" << lang
96 << "from" << VPianoSettings::systemLocales();
97 }
98 if (!m_trp->load(QSTR_VMPKPX + lang, VPianoSettings::localeDirectory()) && !lang.startsWith("en")) {
99 qWarning() << "Failure loading VMPK application translations for" << lang
100 << "from" << VPianoSettings::localeDirectory();
101 }
102 if (!m_trl->load(QSTR_DRUMSTICKPX + lang, VPianoSettings::drumstickLocales()) && !lang.startsWith("en")) {
103 qWarning() << "Failure loading widgets library translations for" << lang
104 << "from" << VPianoSettings::drumstickLocales();
105 }
106 QCoreApplication::installTranslator(m_trq);
107 QCoreApplication::installTranslator(m_trp);
108 QCoreApplication::installTranslator(m_trl);
109 VPianoSettings::instance()->retranslatePalettes();
110 ui.setupUi(this);
111 initLanguages();
112
113 QActionGroup* nameVisibilityGroup = new QActionGroup(this);
114 nameVisibilityGroup->setExclusive(true);
115 nameVisibilityGroup->addAction(ui.actionNever);
116 nameVisibilityGroup->addAction(ui.actionMinimal);
117 nameVisibilityGroup->addAction(ui.actionWhen_Activated);
118 nameVisibilityGroup->addAction(ui.actionAlways);
119 connect(nameVisibilityGroup, &QActionGroup::triggered, this, &VPiano::slotNameVisibility);
120
121 QActionGroup* blackKeysGroup = new QActionGroup(this);
122 blackKeysGroup->setExclusive(true);
123 blackKeysGroup->addAction(ui.actionFlats);
124 blackKeysGroup->addAction(ui.actionSharps);
125 blackKeysGroup->addAction(ui.actionNothing);
126 connect(blackKeysGroup, &QActionGroup::triggered, this, &VPiano::slotNameVariant);
127
128 QActionGroup* orientationGroup = new QActionGroup(this);
129 orientationGroup->setExclusive(true);
130 orientationGroup->addAction(ui.actionHorizontal);
131 orientationGroup->addAction(ui.actionVertical);
132 orientationGroup->addAction(ui.actionAutomatic);
133 connect(orientationGroup, &QActionGroup::triggered, this, &VPiano::slotNameOrientation);
134
135 connect(ui.pianokeybd, &PianoKeybd::signalName, this, &VPiano::slotNoteName);
136 connect(ui.actionAbout, SIGNAL(triggered()), SLOT(slotAbout()));
137 connect(ui.actionAboutQt, SIGNAL(triggered()), SLOT(slotAboutQt()));
138 connect(ui.actionAboutTranslation, SIGNAL(triggered()), SLOT(slotAboutTranslation()));
139 connect(ui.actionConnections, SIGNAL(triggered()), SLOT(slotConnections()));
140 connect(ui.actionPreferences, SIGNAL(triggered()), SLOT(slotPreferences()));
141 connect(ui.actionEditKM, SIGNAL(triggered()), SLOT(slotEditKeyboardMap()));
142 connect(ui.actionContents, SIGNAL(triggered()), SLOT(slotHelpContents()));
143 connect(ui.actionWebSite, SIGNAL(triggered()), SLOT(slotOpenWebSite()));
144 connect(ui.actionImportSoundFont, SIGNAL(triggered()), SLOT(slotImportSF()));
145 connect(ui.actionEditExtraControls, SIGNAL(triggered()), SLOT(slotEditExtraControls()));
146 connect(ui.actionShortcuts, SIGNAL(triggered()), SLOT(slotShortcuts()));
147 connect(ui.actionKeyboardInput, SIGNAL(toggled(bool)), SLOT(slotKeyboardInput(bool)));
148 connect(ui.actionMouseInput, SIGNAL(toggled(bool)), SLOT(slotMouseInput(bool)));
149 connect(ui.actionTouchScreenInput, SIGNAL(toggled(bool)), SLOT(slotTouchScreenInput(bool)));
150 connect(ui.actionColorPalette, SIGNAL(triggered()), SLOT(slotColorPolicy()));
151 connect(ui.actionColorScale, SIGNAL(toggled(bool)), SLOT(slotColorScale(bool)));
152 connect(ui.actionWindowFrame, SIGNAL(toggled(bool)), SLOT(toggleWindowFrame(bool)));
153 connect(ui.actionLoad_Configuration, &QAction::triggered, this, &VPiano::slotLoadConfiguration);
154 connect(ui.actionSave_Configuration, &QAction::triggered, this, &VPiano::slotSaveConfiguration);
155 // Toolbars actions: toggle view
156 connect(ui.toolBarNotes->toggleViewAction(), SIGNAL(toggled(bool)),
157 ui.actionNotes, SLOT(setChecked(bool)));
158 connect(ui.toolBarControllers->toggleViewAction(), SIGNAL(toggled(bool)),
159 ui.actionControllers, SLOT(setChecked(bool)));
160 connect(ui.toolBarBender->toggleViewAction(), SIGNAL(toggled(bool)),
161 ui.actionBender, SLOT(setChecked(bool)));
162 connect(ui.toolBarPrograms->toggleViewAction(), SIGNAL(toggled(bool)),
163 ui.actionPrograms, SLOT(setChecked(bool)));
164 connect(ui.toolBarExtra->toggleViewAction(), SIGNAL(toggled(bool)),
165 ui.actionExtraControls, SLOT(setChecked(bool)));
166 #if defined(SMALL_SCREEN)
167 ui.toolBarControllers->hide();
168 ui.toolBarBender->hide();
169 ui.toolBarExtra->hide();
170 //ui.toolBarNotes->hide();
171 //ui.toolBarPrograms->hide();
172 ui.actionEditKM->setVisible(false);
173 ui.actionShortcuts->setVisible(false);
174 ui.actionStatusBar->setVisible(false);
175 setWindowTitle("VMPK " + PGM_VERSION);
176 #endif
177 #if defined (Q_OS_MACX)
178 //ui.actionEnterFullScreen->setShortcut(QKeySequence::FullScreen);
179 //ui.actionExitFullScreen->setShortcut(QKeySequence::FullScreen);
180 #endif
181 ui.pianokeybd->setPianoHandler(this);
182 #if defined(RAWKBD_SUPPORT)
183 m_filter = new NativeFilter;
184 m_filter->setRawKbdHandler(ui.pianokeybd);
185 qApp->installNativeEventFilter(m_filter);
186 #endif
187 initialization();
188 }
189
~VPiano()190 VPiano::~VPiano()
191 {
192 #if defined(RAWKBD_SUPPORT)
193 m_filter->setRawKbdEnabled(false);
194 qApp->removeNativeEventFilter(m_filter);
195 delete m_filter;
196 #endif
197 delete m_backendManager;
198 }
199
initialization()200 void VPiano::initialization()
201 {
202 readSettings();
203 if ((m_initialized = initMidi())) {
204 readMidiControllerSettings();
205 createLanguageMenu();
206 initToolBars();
207 applyPreferences();
208 applyInitialSettings();
209 initExtraControllers();
210 enforceMIDIChannelState();
211 activateWindow();
212 } else {
213 qWarning() << "Unable to initialize all MIDI drivers. Terminating.";
214 }
215 }
216
initMidi()217 bool VPiano::initMidi()
218 {
219 m_backendManager = new BackendManager();
220 m_backendManager->refresh(VPianoSettings::instance()->settingsMap());
221
222 m_midiin = m_backendManager->findInput(VPianoSettings::instance()->lastInputBackend());
223 if (m_midiin == nullptr) {
224 qWarning() << "MIDI IN driver not available";
225 }
226
227 m_midiout = m_backendManager->findOutput(VPianoSettings::instance()->lastOutputBackend());
228 if (m_midiout == nullptr) {
229 qWarning() << "MIDI OUT driver not available";
230 }
231
232 SettingsFactory settings;
233
234 if (m_midiin != nullptr) {
235 connectMidiInSignals();
236 m_midiin->initialize(settings.getQSettings());
237 MIDIConnection conn;
238 auto connections = m_midiin->connections(VPianoSettings::instance()->advanced());
239 auto lastConn = VPianoSettings::instance()->lastInputConnection();
240 auto itr = std::find_if(connections.constBegin(), connections.constEnd(), [lastConn](const MIDIConnection& c){return c.first == lastConn;});
241 if (itr == connections.constEnd()) {
242 if (!connections.isEmpty()) {
243 conn = connections.first();
244 }
245 } else {
246 conn = (*itr);
247 }
248 m_midiin->open(conn);
249 auto metaObj = m_midiin->metaObject();
250 if ((metaObj->indexOfProperty("status") != -1) &&
251 (metaObj->indexOfProperty("diagnostics") != -1)) {
252 auto status = m_midiin->property("status");
253 if (status.isValid() && !status.toBool()) {
254 auto diagnostics = m_midiin->property("diagnostics");
255 if (diagnostics.isValid()) {
256 auto text = diagnostics.toStringList().join(QChar::LineFeed).trimmed();
257 qWarning() << "MIDI Input" << text;
258 }
259 }
260 }
261 }
262
263 if (m_midiout != nullptr) {
264 m_midiout->initialize(settings.getQSettings());
265 MIDIConnection conn;
266 auto connections = m_midiout->connections(VPianoSettings::instance()->advanced());
267 auto lastConn = VPianoSettings::instance()->lastOutputConnection();
268 auto itr = std::find_if(connections.constBegin(), connections.constEnd(), [lastConn](const MIDIConnection& c){return c.first == lastConn;});
269 if (itr == connections.constEnd()) {
270 if (!connections.isEmpty()) {
271 conn = connections.first();
272 }
273 } else {
274 conn = (*itr);
275 }
276 m_midiout->open(conn);
277 auto metaObj = m_midiout->metaObject();
278 if ((metaObj->indexOfProperty("status") != -1) &&
279 (metaObj->indexOfProperty("diagnostics") != -1)) {
280 auto status = m_midiout->property("status");
281 if (status.isValid() && !status.toBool()) {
282 auto diagnostics = m_midiout->property("diagnostics");
283 if (diagnostics.isValid()) {
284 auto text = diagnostics.toStringList().join(QChar::LineFeed).trimmed();
285 qWarning() << "MIDI Output" << text;
286 }
287 }
288 }
289 if (m_midiin != nullptr) {
290 m_midiin->setMIDIThruDevice(m_midiout);
291 m_midiin->enableMIDIThru(VPianoSettings::instance()->midiThru());
292 }
293 }
294
295 return (m_midiout != nullptr);
296 }
297
initToolBars()298 void VPiano::initToolBars()
299 {
300 // Notes tool bar
301 QWidget *w = ui.toolBarNotes->widgetForAction(ui.actionPanic);
302 w->setMaximumWidth(120);
303 m_lblChannel = new QLabel(this);
304 ui.toolBarNotes->addWidget(m_lblChannel);
305 m_lblChannel->setMargin(TOOLBARLABELMARGIN);
306 m_sboxChannel = new QSpinBox(this);
307 m_sboxChannel->setMinimum(1);
308 m_sboxChannel->setMaximum(MIDICHANNELS);
309 m_sboxChannel->setValue(VPianoSettings::instance()->channel() + 1);
310 m_sboxChannel->setFocusPolicy(Qt::NoFocus);
311 ui.toolBarNotes->addWidget(m_sboxChannel);
312 m_lblBaseOctave = new QLabel(this);
313 ui.toolBarNotes->addWidget(m_lblBaseOctave);
314 m_lblBaseOctave->setMargin(TOOLBARLABELMARGIN);
315 m_sboxOctave = new QSpinBox(this);
316 m_sboxOctave->setMinimum(0);
317 m_sboxOctave->setMaximum(9);
318 m_sboxOctave->setValue(VPianoSettings::instance()->baseOctave());
319 m_sboxOctave->setFocusPolicy(Qt::NoFocus);
320 ui.toolBarNotes->addWidget(m_sboxOctave);
321 m_lblTranspose = new QLabel(this);
322 ui.toolBarNotes->addWidget(m_lblTranspose);
323 m_lblTranspose->setMargin(TOOLBARLABELMARGIN);
324 m_sboxTranspose = new QSpinBox(this);
325 m_sboxTranspose->setMinimum(-11);
326 m_sboxTranspose->setMaximum(11);
327 m_sboxTranspose->setValue(VPianoSettings::instance()->transpose());
328 m_sboxTranspose->setFocusPolicy(Qt::NoFocus);
329 ui.toolBarNotes->addWidget(m_sboxTranspose);
330 m_lblVelocity = new QLabel(this);
331 ui.toolBarNotes->addWidget(m_lblVelocity);
332 m_lblVelocity->setMargin(TOOLBARLABELMARGIN);
333 m_Velocity = new QDial(this);
334 m_Velocity->setFixedSize(32, 32);
335 m_Velocity->setMinimum(0);
336 m_Velocity->setMaximum(127);
337 m_Velocity->setValue(VPianoSettings::instance()->velocity());
338 m_Velocity->setToolTip(QString::number(VPianoSettings::instance()->velocity()));
339 m_Velocity->setFocusPolicy(Qt::NoFocus);
340 ui.toolBarNotes->addWidget(m_Velocity);
341 connect( m_sboxChannel, SIGNAL(valueChanged(int)),
342 SLOT(slotChannelValueChanged(int)));
343 connect( m_sboxOctave, SIGNAL(valueChanged(int)),
344 SLOT(slotBaseOctaveValueChanged(int)) );
345 connect( m_sboxTranspose, SIGNAL(valueChanged(int)),
346 SLOT(slotTransposeValueChanged(int)) );
347 connect( m_Velocity, SIGNAL(valueChanged(int)),
348 SLOT(slotVelocityValueChanged(int)) );
349 connect( ui.actionChannelUp, SIGNAL(triggered()),
350 m_sboxChannel, SLOT(stepUp()) );
351 connect( ui.actionChannelDown, SIGNAL(triggered()),
352 m_sboxChannel, SLOT(stepDown()) );
353 connect( ui.actionOctaveUp, SIGNAL(triggered()),
354 m_sboxOctave, SLOT(stepUp()) );
355 connect( ui.actionOctaveDown, SIGNAL(triggered()),
356 m_sboxOctave, SLOT(stepDown()) );
357 connect( ui.actionTransposeUp, SIGNAL(triggered()),
358 m_sboxTranspose, SLOT(stepUp()) );
359 connect( ui.actionTransposeDown, SIGNAL(triggered()),
360 m_sboxTranspose, SLOT(stepDown()) );
361 connect( ui.actionVelocityUp, SIGNAL(triggered()),
362 SLOT(slotVelocityUp()) );
363 connect( ui.actionVelocityDown, SIGNAL(triggered()),
364 SLOT(slotVelocityDown()) );
365 // Controllers tool bar
366 m_lblControl = new QLabel(this);
367 ui.toolBarControllers->addWidget(m_lblControl);
368 m_lblControl ->setMargin(TOOLBARLABELMARGIN);
369 m_comboControl = new QComboBox(this);
370 m_comboControl->setObjectName("cboControl");
371 //m_comboControl->setStyleSheet("combobox-popup: 0;");
372 m_comboControl->setSizeAdjustPolicy(QComboBox::AdjustToContents);
373 m_comboControl->setFocusPolicy(Qt::NoFocus);
374 ui.toolBarControllers->addWidget(m_comboControl);
375 m_lblValue = new QLabel(this);
376 ui.toolBarControllers->addWidget(m_lblValue);
377 m_lblValue->setMargin(TOOLBARLABELMARGIN);
378 m_Control= new QDial(this);
379 m_Control->setFixedSize(32, 32);
380 m_Control->setMinimum(0);
381 m_Control->setMaximum(127);
382 m_Control->setValue(0);
383 m_Control->setToolTip("0");
384 m_Control->setFocusPolicy(Qt::NoFocus);
385 ui.toolBarControllers->addWidget(m_Control);
386 connect( m_comboControl, SIGNAL(currentIndexChanged(int)),
387 SLOT(slotComboControlCurrentIndexChanged(int)) );
388 connect( m_Control, SIGNAL(sliderMoved(int)),
389 SLOT(slotControlSliderMoved(int)) );
390 // Pitch bender tool bar
391 m_lblBender = new QLabel(this);
392 ui.toolBarBender->addWidget(m_lblBender);
393 m_lblBender->setMargin(TOOLBARLABELMARGIN);
394 m_bender = new QSlider(this);
395 m_bender->setOrientation(Qt::Horizontal);
396 m_bender->setMaximumWidth(200);
397 m_bender->setMinimum(BENDER_MIN);
398 m_bender->setMaximum(BENDER_MAX);
399 m_bender->setValue(0);
400 m_bender->setToolTip("0");
401 m_bender->setFocusPolicy(Qt::NoFocus);
402 ui.toolBarBender->addWidget(m_bender);
403 connect( m_bender, SIGNAL(sliderMoved(int)),
404 SLOT(slotBenderSliderMoved(int)) );
405 connect( m_bender, SIGNAL(sliderReleased()),
406 SLOT(slotBenderSliderReleased()) );
407 // Programs tool bar
408 m_lblBank = new QLabel(this);
409 ui.toolBarPrograms->addWidget(m_lblBank);
410 m_lblBank->setMargin(TOOLBARLABELMARGIN);
411 m_comboBank = new QComboBox(this);
412 m_comboBank->setObjectName("cboBank");
413 m_comboBank->setSizeAdjustPolicy(QComboBox::AdjustToContents);
414 //m_comboBank->setStyleSheet("combobox-popup: 0;");
415 m_comboBank->setFocusPolicy(Qt::NoFocus);
416 ui.toolBarPrograms->addWidget(m_comboBank);
417 m_lblProgram = new QLabel(this);
418 ui.toolBarPrograms->addWidget(m_lblProgram);
419 m_lblProgram->setMargin(TOOLBARLABELMARGIN);
420 m_comboProg = new QComboBox(this);
421 m_comboProg->setObjectName("cboProg");
422 m_comboProg->setStyleSheet("combobox-popup: 0;");
423 m_comboProg->setSizeAdjustPolicy(QComboBox::AdjustToContents);
424 m_comboProg->setFocusPolicy(Qt::NoFocus);
425 ui.toolBarPrograms->addWidget(m_comboProg);
426 connect( m_comboBank, SIGNAL(activated(int)),
427 SLOT(slotComboBankActivated(int)) );
428 connect( m_comboProg, SIGNAL(activated(int)),
429 SLOT(slotComboProgActivated(int)) );
430 // Toolbars actions: buttons
431 connect( ui.actionPanic, SIGNAL(triggered()),
432 SLOT(slotPanic()));
433 connect( ui.actionResetAll, SIGNAL(triggered()),
434 SLOT(slotResetAllControllers()));
435 connect( ui.actionReset, SIGNAL(triggered()),
436 SLOT(slotResetBender()));
437 connect( ui.actionEditExtra, SIGNAL(triggered()),
438 SLOT(slotEditExtraControls()));
439 // Tools actions
440 connect( ui.actionNextBank, SIGNAL(triggered()),
441 SLOT(slotBankNext()) );
442 connect( ui.actionPreviousBank, SIGNAL(triggered()),
443 SLOT(slotBankPrev()) );
444 connect( ui.actionNextProgram, SIGNAL(triggered()),
445 SLOT(slotProgramNext()) );
446 connect( ui.actionPreviousProgram, SIGNAL(triggered()),
447 SLOT(slotProgramPrev()) );
448 connect( ui.actionNextController, SIGNAL(triggered()),
449 SLOT(slotControllerNext()) );
450 connect( ui.actionPreviousController, SIGNAL(triggered()),
451 SLOT(slotControllerPrev()) );
452 connect( ui.actionControllerDown, SIGNAL(triggered()),
453 SLOT(slotControllerDown()) );
454 connect( ui.actionControllerUp, SIGNAL(triggered()),
455 SLOT(slotControllerUp()) );
456 /* connect( ui.actionEditPrograms, SIGNAL(triggered()),
457 SLOT(slotEditPrograms())); */
458 retranslateToolbars();
459 }
460
461 //void VPiano::slotDebugDestroyed(QObject *obj)
462 //{
463 // qDebug() << Q_FUNC_INFO << obj->metaObject()->className();
464 //}
465
clearExtraControllers()466 void VPiano::clearExtraControllers()
467 {
468 QList<QAction*> allActs = ui.toolBarExtra->actions();
469 foreach(QAction* a, allActs) {
470 if (a != ui.actionEditExtra) {
471 ui.toolBarExtra->removeAction(a);
472 delete a;
473 }
474 }
475 ui.toolBarExtra->clear();
476 ui.toolBarExtra->addAction(ui.actionEditExtra);
477 ui.toolBarExtra->addSeparator();
478 }
479
readSysexDataFile(const QString & fileName)480 QByteArray VPiano::readSysexDataFile(const QString& fileName)
481 {
482 QFile file(fileName);
483 file.open(QIODevice::ReadOnly);
484 QByteArray res = file.readAll();
485 file.close();
486 return res;
487 }
488
initExtraControllers()489 void VPiano::initExtraControllers()
490 {
491 QWidget *w = nullptr;
492 QCheckBox *chkbox = nullptr;
493 QDial *knob = nullptr;
494 QSpinBox *spin = nullptr;
495 QSlider *slider = nullptr;
496 QToolButton *button = nullptr;
497 foreach(const QString& s, m_extraControls) {
498 QString lbl;
499 int control = 0;
500 int type = 0;
501 int minValue = 0;
502 int maxValue = 127;
503 int defValue = 0;
504 int value = 0;
505 int size = 100;
506 int channel = VPianoSettings::instance()->channel();
507 QString fileName;
508 QString keySequence;
509 ExtraControl::decodeString( s, lbl, control, type,
510 minValue, maxValue, defValue,
511 size, fileName, keySequence );
512 if (m_ctlState[channel].contains(control))
513 value = m_ctlState[channel][control];
514 else
515 value = defValue;
516 switch(type) {
517 case ExtraControl::ControlType::SwitchControl:
518 chkbox = new QCheckBox(this);
519 chkbox->setStyleSheet(QSTR_CHKBOXSTYLE);
520 chkbox->setProperty(MIDICTLONVALUE, maxValue);
521 chkbox->setProperty(MIDICTLOFFVALUE, minValue);
522 chkbox->setChecked(bool(value));
523 connect(chkbox, SIGNAL(clicked(bool)), SLOT(slotControlClicked(bool)));
524 if (!keySequence.isEmpty()) {
525 QShortcut *s = new QShortcut(QKeySequence(keySequence), chkbox, SLOT(click()));
526 s->setAutoRepeat(false);
527 }
528 w = chkbox;
529 break;
530 case ExtraControl::ControlType::KnobControl:
531 knob = new QDial(this);
532 knob->setFixedSize(32, 32);
533 knob->setMinimum(minValue);
534 knob->setMaximum(maxValue);
535 knob->setValue(value);
536 knob->setToolTip(QString::number(value));
537 connect(knob, SIGNAL(sliderMoved(int)), SLOT(slotExtraController(int)));
538 w = knob;
539 break;
540 case ExtraControl::ControlType::SpinBoxControl:
541 spin = new QSpinBox(this);
542 spin->setMinimum(minValue);
543 spin->setMaximum(maxValue);
544 spin->setValue(value);
545 connect(spin, SIGNAL(valueChanged(int)), SLOT(slotExtraController(int)));
546 w = spin;
547 break;
548 case ExtraControl::ControlType::SliderControl:
549 slider = new QSlider(this);
550 slider->setOrientation(Qt::Horizontal);
551 slider->setFixedWidth(size);
552 slider->setMinimum(minValue);
553 slider->setMaximum(maxValue);
554 slider->setToolTip(QString::number(value));
555 slider->setValue(value);
556 connect(slider, SIGNAL(sliderMoved(int)), SLOT(slotExtraController(int)));
557 w = slider;
558 break;
559 case ExtraControl::ControlType::ButtonCtlControl:
560 button = new QToolButton(this);
561 button->setText(lbl);
562 button->setProperty(MIDICTLONVALUE, maxValue);
563 button->setProperty(MIDICTLOFFVALUE, minValue);
564 connect(button, SIGNAL(clicked(bool)), SLOT(slotControlClicked(bool)));
565 if (!keySequence.isEmpty()) {
566 QShortcut *s = new QShortcut(QKeySequence(keySequence), button, SLOT(animateClick()));
567 s->setAutoRepeat(false);
568 }
569 w = button;
570 break;
571 case ExtraControl::ControlType::ButtonSyxControl:
572 control = 255;
573 button = new QToolButton(this);
574 button->setText(lbl);
575 button->setProperty(SYSEXFILENAME, fileName);
576 button->setProperty(SYSEXFILEDATA, readSysexDataFile(fileName));
577 connect(button, SIGNAL(clicked(bool)), SLOT(slotControlClicked(bool)));
578 if (!keySequence.isEmpty()) {
579 QShortcut *s = new QShortcut(QKeySequence(keySequence), button, SLOT(animateClick()));
580 s->setAutoRepeat(false);
581 }
582 w = button;
583 break;
584 default:
585 w = nullptr;
586 }
587 if (w != nullptr) {
588 if (!lbl.isEmpty() && type < 4) {
589 QLabel *qlbl = new QLabel(lbl, this);
590 qlbl->setMargin(TOOLBARLABELMARGIN);
591 ui.toolBarExtra->addWidget(qlbl);
592 //connect(qlbl, SIGNAL(destroyed(QObject*)), SLOT(slotDebugDestroyed(QObject*)));
593 }
594 w->setProperty(MIDICTLNUMBER, control);
595 w->setFocusPolicy(Qt::NoFocus);
596 ui.toolBarExtra->addWidget(w);
597 //connect(w, SIGNAL(destroyed(QObject*)), SLOT(slotDebugDestroyed(QObject*)));
598 }
599 }
600 }
601
readSettings()602 void VPiano::readSettings()
603 {
604 VPianoSettings::instance()->retranslatePalettes();
605
606 ui.actionStatusBar->setChecked(VPianoSettings::instance()->showStatusBar());
607 ui.statusBar->setVisible(VPianoSettings::instance()->showStatusBar());
608 ui.pianokeybd->setNumKeys(VPianoSettings::instance()->numKeys(), VPianoSettings::instance()->startingKey());
609 ui.pianokeybd->setVelocityTint(VPianoSettings::instance()->velocityColor());
610 ui.pianokeybd->setVelocity(VPianoSettings::instance()->velocity());
611 ui.pianokeybd->setTranspose(VPianoSettings::instance()->transpose());
612 ui.pianokeybd->setBaseOctave(VPianoSettings::instance()->baseOctave());
613 ui.pianokeybd->setKeyboardEnabled(VPianoSettings::instance()->enableKeyboard());
614 ui.pianokeybd->setMouseEnabled(VPianoSettings::instance()->enableMouse());
615 ui.pianokeybd->setTouchEnabled(VPianoSettings::instance()->enableTouch());
616 ui.pianokeybd->setChannel(VPianoSettings::instance()->channel());
617 ui.actionColorScale->setChecked(VPianoSettings::instance()->colorScale());
618 ui.pianokeybd->setFont(VPianoSettings::instance()->namesFont());
619
620 switch(VPianoSettings::instance()->namesVisibility()) {
621 case ShowNever:
622 ui.actionNever->setChecked(true);
623 break;
624 case ShowMinimum:
625 ui.actionMinimal->setChecked(true);
626 break;
627 case ShowActivated:
628 ui.actionWhen_Activated->setChecked(true);
629 break;
630 case ShowAlways:
631 ui.actionAlways->setChecked(true);
632 break;
633 }
634 ui.pianokeybd->setShowLabels(VPianoSettings::instance()->namesVisibility());
635
636 switch(VPianoSettings::instance()->alterations()) {
637 case ShowSharps:
638 ui.actionSharps->setChecked(true);
639 break;
640 case ShowFlats:
641 ui.actionFlats->setChecked(true);
642 break;
643 case ShowNothing:
644 ui.actionNothing->setChecked(true);
645 break;
646 }
647 ui.pianokeybd->setLabelAlterations(VPianoSettings::instance()->alterations());
648
649 switch(VPianoSettings::instance()->namesOrientation()) {
650 case HorizontalOrientation:
651 ui.actionHorizontal->setChecked(true);
652 break;
653 case VerticalOrientation:
654 ui.actionVertical->setChecked(true);
655 break;
656 case AutomaticOrientation:
657 ui.actionAutomatic->setChecked(true);
658 break;
659 }
660 ui.pianokeybd->setLabelOrientation(VPianoSettings::instance()->namesOrientation());
661 ui.pianokeybd->setLabelOctave(VPianoSettings::instance()->namesOctave());
662
663 bool savedShortcuts = VPianoSettings::instance()->savedShortcuts();
664 QList<QAction *> actions = findChildren<QAction *> ();
665 foreach(QAction* pAction, actions)
666 {
667 if (pAction->objectName().isEmpty())
668 continue;
669 const QString& sKey = pAction->objectName();
670 QList<QKeySequence> sShortcuts = pAction->shortcuts();
671 m_defaultShortcuts.insert(sKey, sShortcuts);
672 if (savedShortcuts)
673 {
674 const QString& sValue = VPianoSettings::instance()->getShortcut(sKey);
675 if (sValue.isEmpty())
676 {
677 if(sShortcuts.count() == 0)
678 {
679 continue;
680 }
681 else
682 {
683 pAction->setShortcuts(QList<QKeySequence>());
684 }
685 }
686 else
687 {
688 pAction->setShortcut(QKeySequence(sValue));
689 }
690 }
691 }
692
693 QString mapFile = VPianoSettings::instance()->getMapFile();
694 QString rawMapFile = VPianoSettings::instance()->getRawMapFile();
695 if (!mapFile.isEmpty() && mapFile != QSTR_DEFAULT) {
696 ui.pianokeybd->setKeyboardMap(VPianoSettings::instance()->getKeyboardMap());
697 }
698 if (!rawMapFile.isEmpty() && rawMapFile != QSTR_DEFAULT) {
699 ui.pianokeybd->setRawKeyboardMap(VPianoSettings::instance()->getRawKeyboardMap());
700 }
701 }
702
readMidiControllerSettings()703 void VPiano::readMidiControllerSettings()
704 {
705 SettingsFactory settings;
706 for (int chan=0; chan<MIDICHANNELS; ++chan) {
707 QString group = QSTR_INSTRUMENT + QString::number(chan);
708 settings->beginGroup(group);
709 m_lastBank[chan] = settings->value(QSTR_BANK, -1).toInt();
710 m_lastProg[chan] = settings->value(QSTR_PROGRAM, 0).toInt();
711 m_lastCtl[chan] = settings->value(QSTR_CONTROLLER, 1).toInt();
712 settings->endGroup();
713
714 group = QSTR_CONTROLLERS + QString::number(chan);
715 settings->beginGroup(group);
716 foreach(const QString& key, settings->allKeys()) {
717 int ctl = key.toInt();
718 int val = settings->value(key, 0).toInt();
719 m_ctlSettings[chan][ctl] = val;
720 }
721 settings->endGroup();
722 }
723
724 settings->beginGroup(QSTR_EXTRACONTROLLERS);
725 m_extraControls.clear();
726 QStringList keys = settings->allKeys();
727 keys.sort();
728 foreach(const QString& key, keys) {
729 m_extraControls << settings->value(key, QString()).toString();
730 }
731 settings->endGroup();
732 if (m_extraControls.isEmpty()) {
733 m_extraControls = QStringList{"Sustain,64,0,0,64,0,", "Sostenuto,66,0,0,64,0,", "Soft,67,0,0,64,0,"};
734 }
735 }
736
writeSettings()737 void VPiano::writeSettings()
738 {
739 VPianoSettings::instance()->setShowStatusBar(ui.actionStatusBar->isChecked());
740 VPianoSettings::instance()->setGeometry(saveGeometry());
741 VPianoSettings::instance()->setState(saveState());
742 VPianoSettings::instance()->SaveSettings();
743
744 SettingsFactory settings;
745
746 for (int chan=0; chan<MIDICHANNELS; ++chan) {
747 QString group = QSTR_CONTROLLERS + QString::number(chan);
748 settings->beginGroup(group);
749 settings->remove("");
750 QMap<int,int>::const_iterator it, end;
751 it = m_ctlState[chan].constBegin();
752 end = m_ctlState[chan].constEnd();
753 for (; it != end; ++it)
754 settings->setValue(QString::number(it.key()), it.value());
755 settings->endGroup();
756
757 group = QSTR_INSTRUMENT + QString::number(chan);
758 settings->beginGroup(group);
759 settings->setValue(QSTR_BANK, m_lastBank[chan]);
760 settings->setValue(QSTR_PROGRAM, m_lastProg[chan]);
761 settings->setValue(QSTR_CONTROLLER, m_lastCtl[chan]);
762 settings->endGroup();
763 }
764
765 settings->beginGroup(QSTR_EXTRACONTROLLERS);
766 settings->remove("");
767 int i = 0;
768 foreach(const QString& ctl, m_extraControls) {
769 QString key = QString("%1").arg(i++, 2, 10, QChar('0'));
770 settings->setValue(key, ctl);
771 }
772 settings->endGroup();
773
774 settings->beginGroup(QSTR_SHORTCUTS);
775 settings->remove("");
776 QList<QAction *> actions = findChildren<QAction *> ();
777 foreach(QAction *pAction, actions)
778 {
779 if (pAction->objectName().isEmpty())
780 continue;
781 const QString& sKey = '/' + pAction->objectName();
782 const QString& sValue = pAction->shortcut().toString();
783 QList<QKeySequence> defShortcuts = m_defaultShortcuts.value(sKey);
784 if (sValue.isEmpty() && defShortcuts.count() == 0)
785 {
786 if (settings->contains(sKey))
787 settings->remove(sKey);
788 }
789 else
790 {
791 settings->setValue(sKey, sValue);
792 }
793 }
794 settings->endGroup();
795 settings->sync();
796 }
797
closeEvent(QCloseEvent * event)798 void VPiano::closeEvent( QCloseEvent *event )
799 {
800 //qDebug() << Q_FUNC_INFO;
801 if (m_initialized) {
802 writeSettings();
803 }
804 event->accept();
805 }
806
getDegree(const int note) const807 int VPiano::getDegree(const int note) const
808 {
809 return note % 12;
810 }
811
getType(const int note) const812 int VPiano::getType(const int note) const
813 {
814 int g = getDegree(note);
815 if (g == 1 || g == 3 || g == 6 || g == 8 || g == 10)
816 return 1;
817 return 0;
818 }
819
getHighlightColorFromPolicy(const int chan,const int note,const int vel)820 QColor VPiano::getHighlightColorFromPolicy(const int chan, const int note, const int vel)
821 {
822 Q_UNUSED(vel)
823 PianoPalette palette = VPianoSettings::instance()->getPalette(VPianoSettings::instance()->highlightPaletteId());
824 switch (palette.paletteId()) {
825 case PAL_SINGLE:
826 return palette.getColor(0);
827 case PAL_DOUBLE:
828 return palette.getColor(getType(note));
829 case PAL_CHANNELS:
830 return palette.getColor(chan);
831 case PAL_HISCALE:
832 return palette.getColor(getDegree(note));
833 default:
834 break;
835 }
836 return QColor();
837 }
838
slotNoteOn(const int chan,const int note,const int vel)839 void VPiano::slotNoteOn(const int chan, const int note, const int vel)
840 {
841 if (VPianoSettings::instance()->channel() == chan || VPianoSettings::instance()->omniMode()) {
842 if (vel == 0) {
843 slotNoteOff(chan, note, vel);
844 } else {
845 QColor c = getHighlightColorFromPolicy(chan, note, vel);
846 int v = (VPianoSettings::instance()->velocityColor() ? vel : MIDIVELOCITY );
847 ui.pianokeybd->showNoteOn(note, c, v);
848 #ifdef ENABLE_DBUS
849 emit event_noteon(note);
850 #endif
851 }
852 }
853 }
854
slotNoteOff(const int chan,const int note,const int vel)855 void VPiano::slotNoteOff(const int chan, const int note, const int vel)
856 {
857 Q_UNUSED(vel)
858 if (VPianoSettings::instance()->channel() == chan || VPianoSettings::instance()->omniMode()) {
859 ui.pianokeybd->showNoteOff(note);
860 #ifdef ENABLE_DBUS
861 emit event_noteoff(note);
862 #endif
863 }
864 }
865
slotKeyPressure(const int chan,const int note,const int value)866 void VPiano::slotKeyPressure(const int chan, const int note, const int value)
867 {
868 #ifdef ENABLE_DBUS
869 int channel = VPianoSettings::instance()->channel();
870 if (channel == chan) {
871 emit event_polykeypress(note, value);
872 }
873 #else
874 Q_UNUSED(chan)
875 Q_UNUSED(note)
876 Q_UNUSED(value)
877 #endif
878 }
879
slotController(const int chan,const int control,const int value)880 void VPiano::slotController(const int chan, const int control, const int value)
881 {
882 int channel = VPianoSettings::instance()->channel();
883 if (channel == chan) {
884 switch (control) {
885 case CTL_ALL_SOUND_OFF:
886 case CTL_ALL_NOTES_OFF:
887 ui.pianokeybd->allKeysOff();
888 break;
889 case CTL_RESET_ALL_CTL:
890 initializeAllControllers();
891 break;
892 default:
893 updateController(control, value);
894 updateExtraController(control, value);
895 }
896 #ifdef ENABLE_DBUS
897 emit event_controlchange(control, value);
898 #endif
899 }
900 }
901
slotProgram(const int chan,const int program)902 void VPiano::slotProgram(const int chan, const int program)
903 {
904 int channel = VPianoSettings::instance()->channel();
905 if (channel == chan) {
906 updateProgramChange(program);
907 #ifdef ENABLE_DBUS
908 emit event_programchange(program);
909 #endif
910 }
911 }
912
slotChannelPressure(const int chan,const int value)913 void VPiano::slotChannelPressure(const int chan, const int value)
914 {
915 int channel = VPianoSettings::instance()->channel();
916 if (channel == chan) {
917 #ifdef ENABLE_DBUS
918 emit event_chankeypress(value);
919 #else
920 Q_UNUSED(value)
921 #endif
922 }
923 }
924
slotPitchBend(const int chan,const int value)925 void VPiano::slotPitchBend(const int chan, const int value)
926 {
927 int channel = VPianoSettings::instance()->channel();
928 if (channel == chan) {
929 m_bender->setValue(value);
930 m_bender->setToolTip(QString::number(value));
931 #ifdef ENABLE_DBUS
932 emit event_pitchwheel(value);
933 #endif
934 }
935 }
936
showEvent(QShowEvent * event)937 void VPiano::showEvent ( QShowEvent *event )
938 {
939 static bool firstTime{true};
940 //qDebug() << Q_FUNC_INFO << firstTime;
941 if (firstTime) {
942 if (!restoreGeometry(VPianoSettings::instance()->geometry())) {
943 qWarning() << "restoreGeometry() failed!";
944 }
945 if (!restoreState(VPianoSettings::instance()->state())) {
946 qWarning() << "restoreState() failed!";
947 }
948 firstTime = false;
949 }
950 QMainWindow::showEvent(event);
951 #if !defined(SMALL_SCREEN)
952 if (m_initialized) {
953 ui.pianokeybd->setFocus();
954 grabKb();
955 }
956 #endif
957 }
958
hideEvent(QHideEvent * event)959 void VPiano::hideEvent( QHideEvent *event )
960 {
961 //qDebug() << "hideEvent:" << event->type();
962 //#if !defined(SMALL_SCREEN)
963 //releaseKb();
964 //#endif
965 QMainWindow::hideEvent(event);
966 }
967
sendNoteOn(const int midiNote,const int vel)968 void VPiano::sendNoteOn(const int midiNote, const int vel)
969 {
970 if ((midiNote & MASK_SAFETY) == midiNote) {
971 int channel = VPianoSettings::instance()->channel();
972 m_midiout->sendNoteOn( channel, midiNote, vel );
973 }
974 }
975
noteOn(const int midiNote,const int vel)976 void VPiano::noteOn(const int midiNote, const int vel)
977 {
978 sendNoteOn(midiNote, vel);
979 #ifdef ENABLE_DBUS
980 emit event_noteon(midiNote);
981 #endif
982 }
983
sendNoteOff(const int midiNote,const int vel)984 void VPiano::sendNoteOff(const int midiNote, const int vel)
985 {
986 if ((midiNote & MASK_SAFETY) == midiNote) {
987 int channel = VPianoSettings::instance()->channel();
988 m_midiout->sendNoteOff( channel, midiNote, vel );
989 }
990 }
991
noteOff(const int midiNote,const int vel)992 void VPiano::noteOff(const int midiNote, const int vel)
993 {
994 sendNoteOff(midiNote, vel);
995 #ifdef ENABLE_DBUS
996 emit event_noteoff(midiNote);
997 #endif
998 }
999
sendController(const int controller,const int value)1000 void VPiano::sendController(const int controller, const int value)
1001 {
1002 int channel = VPianoSettings::instance()->channel();
1003 m_midiout->sendController( channel, controller, value );
1004 }
1005
resetAllControllers()1006 void VPiano::resetAllControllers()
1007 {
1008 sendController(CTL_RESET_ALL_CTL, 0);
1009 initializeAllControllers();
1010 }
1011
initializeAllControllers()1012 void VPiano::initializeAllControllers()
1013 {
1014 int channel = VPianoSettings::instance()->channel();
1015 int index = m_comboControl->currentIndex();
1016 int ctl = m_comboControl->itemData(index).toInt();
1017 int val = m_ctlState[channel][ctl];
1018 initControllers(channel);
1019 m_comboControl->setCurrentIndex(index);
1020 m_Control->setValue(val);
1021 m_Control->setToolTip(QString::number(val));
1022 // extra controllers
1023 QList<QWidget *> allWidgets = ui.toolBarExtra->findChildren<QWidget *>();
1024 foreach(QWidget *w, allWidgets) {
1025 QVariant c = w->property(MIDICTLNUMBER);
1026 if (c.isValid()) {
1027 ctl = c.toInt();
1028 if (m_ctlState[channel].contains(ctl)) {
1029 val = m_ctlState[channel][ctl];
1030 QVariant p = w->property("value");
1031 if (p.isValid()) {
1032 w->setProperty("value", val);
1033 w->setToolTip(QString::number(val));
1034 continue;
1035 }
1036 p = w->property("checked");
1037 if (p.isValid()) {
1038 QVariant on = w->property(MIDICTLONVALUE);
1039 w->setProperty("checked", (val >= on.toInt()));
1040 }
1041 }
1042 }
1043 }
1044 }
1045
allNotesOff()1046 void VPiano::allNotesOff()
1047 {
1048 sendController(CTL_ALL_NOTES_OFF, 0);
1049 ui.pianokeybd->allKeysOff();
1050 }
1051
sendProgramChange(const int program)1052 void VPiano::sendProgramChange(const int program)
1053 {
1054 int channel = VPianoSettings::instance()->channel();
1055 m_midiout->sendProgram( channel, program );
1056 }
1057
sendBankChange(const int bank)1058 void VPiano::sendBankChange(const int bank)
1059 {
1060 int channel = VPianoSettings::instance()->channel();
1061 int method = (m_ins != nullptr) ? m_ins->bankSelMethod() : 0;
1062 int lsb, msb;
1063 switch (method) {
1064 case 0:
1065 lsb = CALC_LSB(bank);
1066 msb = CALC_MSB(bank);
1067 sendController(CTL_MSB, msb);
1068 sendController(CTL_LSB, lsb);
1069 break;
1070 case 1:
1071 sendController(CTL_MSB, bank);
1072 break;
1073 case 2:
1074 sendController(CTL_LSB, bank);
1075 break;
1076 default: /* if method is 3 or above, do nothing */
1077 break;
1078 }
1079 m_lastBank[channel] = bank;
1080 }
1081
sendPolyKeyPress(const int note,const int value)1082 void VPiano::sendPolyKeyPress(const int note, const int value)
1083 {
1084 int channel = VPianoSettings::instance()->channel();
1085 m_midiout->sendKeyPressure( channel, note, value );
1086 }
1087
sendChanKeyPress(const int value)1088 void VPiano::sendChanKeyPress(const int value)
1089 {
1090 int channel = VPianoSettings::instance()->channel();
1091 m_midiout->sendChannelPressure( channel, value );
1092 }
1093
sendBender(const int value)1094 void VPiano::sendBender(const int value)
1095 {
1096 int channel = VPianoSettings::instance()->channel();
1097 m_midiout->sendPitchBend( channel, value );
1098 }
1099
slotPanic()1100 void VPiano::slotPanic()
1101 {
1102 allNotesOff();
1103 }
1104
slotResetAllControllers()1105 void VPiano::slotResetAllControllers()
1106 {
1107 resetAllControllers();
1108 }
1109
slotResetBender()1110 void VPiano::slotResetBender()
1111 {
1112 m_bender->setValue(0);
1113 sendBender(0);
1114 }
1115
sendSysex(const QByteArray & data)1116 void VPiano::sendSysex(const QByteArray& data)
1117 {
1118 m_midiout->sendSysex( data );
1119 }
1120
slotControlClicked(const bool boolValue)1121 void VPiano::slotControlClicked(const bool boolValue)
1122 {
1123 QObject *s = sender();
1124 QVariant p = s->property(MIDICTLNUMBER);
1125 if (p.isValid()) {
1126 int controller = p.toInt();
1127 if (controller < 128) {
1128 QVariant on = s->property(MIDICTLONVALUE);
1129 QVariant off = s->property(MIDICTLOFFVALUE);
1130 int value = boolValue ? on.toInt() : off.toInt();
1131 sendController( controller, value );
1132 updateController( controller, value );
1133 } else {
1134 QVariant data = s->property(SYSEXFILEDATA);
1135 sendSysex(data.toByteArray());
1136 }
1137 }
1138 }
1139
slotVelocityValueChanged(int value)1140 void VPiano::slotVelocityValueChanged(int value)
1141 {
1142 VPianoSettings::instance()->setVelocity(value);
1143 setWidgetTip(m_Velocity, value);
1144 ui.pianokeybd->setVelocity(value);
1145 }
1146
slotExtraController(const int value)1147 void VPiano::slotExtraController(const int value)
1148 {
1149 QWidget *w = static_cast<QWidget *>(sender());
1150 QVariant p = w->property(MIDICTLNUMBER);
1151 if (p.isValid()) {
1152 int controller = p.toInt();
1153 sendController( controller, value );
1154 updateController( controller, value );
1155 setWidgetTip(w, value);
1156 }
1157 }
1158
slotControlSliderMoved(const int value)1159 void VPiano::slotControlSliderMoved(const int value)
1160 {
1161 int index = m_comboControl->currentIndex();
1162 int controller = m_comboControl->itemData(index).toInt();
1163 int channel = VPianoSettings::instance()->channel();
1164 sendController( controller, value );
1165 updateExtraController( controller, value );
1166 m_ctlState[channel][controller] = value;
1167 setWidgetTip(m_Control, value);
1168 }
1169
slotBenderSliderMoved(const int pos)1170 void VPiano::slotBenderSliderMoved(const int pos)
1171 {
1172 sendBender(pos);
1173 setWidgetTip(m_bender, pos);
1174 }
1175
slotBenderSliderReleased()1176 void VPiano::slotBenderSliderReleased()
1177 {
1178 m_bender->setValue(0);
1179 sendBender(0);
1180 setWidgetTip(m_bender, 0);
1181 }
1182
slotAbout()1183 void VPiano::slotAbout()
1184 {
1185 releaseKb();
1186 QPointer<About> dlgAbout = new About(this);
1187 dlgAbout->exec();
1188 grabKb();
1189 delete dlgAbout;
1190 }
1191
slotAboutQt()1192 void VPiano::slotAboutQt()
1193 {
1194 releaseKb();
1195 QApplication::aboutQt();
1196 grabKb();
1197 }
1198
connectMidiInSignals()1199 void VPiano::connectMidiInSignals()
1200 {
1201 if (m_midiin != nullptr) {
1202 connect(m_midiin, &MIDIInput::midiNoteOn, this, &VPiano::slotNoteOn, Qt::QueuedConnection);
1203 connect(m_midiin, &MIDIInput::midiNoteOff, this, &VPiano::slotNoteOff, Qt::QueuedConnection);
1204 connect(m_midiin, &MIDIInput::midiKeyPressure, this, &VPiano::slotKeyPressure, Qt::QueuedConnection);
1205 connect(m_midiin, &MIDIInput::midiChannelPressure, this, &VPiano::slotChannelPressure, Qt::QueuedConnection);
1206 connect(m_midiin, &MIDIInput::midiController, this, &VPiano::slotController, Qt::QueuedConnection);
1207 connect(m_midiin, &MIDIInput::midiProgram, this, &VPiano::slotProgram, Qt::QueuedConnection);
1208 connect(m_midiin, &MIDIInput::midiPitchBend, this, &VPiano::slotPitchBend, Qt::QueuedConnection);
1209 }
1210 }
1211
slotConnections()1212 void VPiano::slotConnections()
1213 {
1214 QPointer<MidiSetup> dlgMidiSetup = new MidiSetup(this);
1215 dlgMidiSetup->setInputs(m_backendManager->availableInputs());
1216 dlgMidiSetup->setOutputs(m_backendManager->availableOutputs());
1217 dlgMidiSetup->setInput(m_midiin);
1218 dlgMidiSetup->setOutput(m_midiout);
1219 releaseKb();
1220 if (dlgMidiSetup->exec() == QDialog::Accepted) {
1221 if (m_midiin != nullptr) {
1222 m_midiin->disconnect();
1223 }
1224 if (m_midiout != nullptr) {
1225 m_midiout->disconnect();
1226 }
1227 m_midiin = dlgMidiSetup->getInput();
1228 m_midiout = dlgMidiSetup->getOutput();
1229 connectMidiInSignals();
1230 enforceMIDIChannelState();
1231 }
1232 grabKb();
1233 delete dlgMidiSetup;
1234 }
1235
initControllers(int channel)1236 void VPiano::initControllers(int channel)
1237 {
1238 if (m_ins != nullptr) {
1239 InstrumentData controls = m_ins->control();
1240 InstrumentData::ConstIterator it, end;
1241 it = controls.constBegin();
1242 end = controls.constEnd();
1243 for( ; it != end; ++it ) {
1244 int ctl = it.key();
1245 switch (ctl) {
1246 case CTL_VOLUME:
1247 m_ctlState[channel][CTL_VOLUME] = MIDIVOLUME;
1248 break;
1249 case CTL_PAN:
1250 m_ctlState[channel][CTL_PAN] = MIDIPAN;
1251 break;
1252 case CTL_EXPRESSION:
1253 m_ctlState[channel][CTL_EXPRESSION] = MIDIMAXVALUE;
1254 break;
1255 case CTL_REVERB_SEND:
1256 m_ctlState[channel][CTL_REVERB_SEND] = MIDIMAXVALUE;
1257 break;
1258 default:
1259 m_ctlState[channel][ctl] = 0;
1260 }
1261 }
1262 }
1263 }
1264
populateControllers()1265 void VPiano::populateControllers()
1266 {
1267 m_comboControl->blockSignals(true);
1268 m_comboControl->clear();
1269 if (m_ins != nullptr) {
1270 InstrumentData controls = m_ins->control();
1271 InstrumentData::ConstIterator it, end = controls.constEnd();
1272 for( it = controls.constBegin(); it != end; ++it )
1273 m_comboControl->addItem(it.value(), it.key());
1274 }
1275 m_comboControl->blockSignals(false);
1276 }
1277
applyPreferences()1278 void VPiano::applyPreferences()
1279 {
1280 static QPalette defaultPalette = qApp->palette();
1281 static QPalette darkPalette(QColor(0x30,0x30,0x30));
1282
1283 ui.pianokeybd->allKeysOff();
1284 ui.pianokeybd->setFont(VPianoSettings::instance()->namesFont());
1285 ui.pianokeybd->setLabelOctave(VPianoSettings::instance()->namesOctave());
1286 if ( ui.pianokeybd->numKeys() != VPianoSettings::instance()->numKeys() ||
1287 ui.pianokeybd->startKey() != VPianoSettings::instance()->startingKey() )
1288 {
1289 ui.pianokeybd->setNumKeys(VPianoSettings::instance()->numKeys(), VPianoSettings::instance()->startingKey());
1290 }
1291 #if defined(RAWKBD_SUPPORT)
1292 m_filter->setRawKbdEnabled(VPianoSettings::instance()->rawKeyboard());
1293 #endif
1294 ui.pianokeybd->setRawKeyboardMode(VPianoSettings::instance()->rawKeyboard());
1295 ui.pianokeybd->setVelocityTint(VPianoSettings::instance()->velocityColor());
1296 ui.pianokeybd->setVelocity(VPianoSettings::instance()->velocity());
1297 bool enableKeyboard = VPianoSettings::instance()->enableKeyboard();
1298 bool enableMouse = VPianoSettings::instance()->enableMouse();
1299 bool enableTouch = VPianoSettings::instance()->enableTouch();
1300 ui.pianokeybd->setKeyboardEnabled(enableKeyboard);
1301 ui.pianokeybd->setMouseEnabled(enableMouse);
1302 ui.pianokeybd->setTouchEnabled(enableTouch);
1303 ui.actionKeyboardInput->setChecked(enableKeyboard);
1304 ui.actionMouseInput->setChecked(enableMouse);
1305 ui.actionTouchScreenInput->setChecked(enableTouch);
1306
1307 #if defined(Q_OS_WINDOWS)
1308 m_snapper.SetEnabled(VPianoSettings::instance()->getWinSnap());
1309 #endif
1310 qApp->setPalette( VPianoSettings::instance()->getDarkMode() ? darkPalette : defaultPalette );
1311 qApp->setStyle( VPianoSettings::instance()->getStyle() );
1312
1313 VMPKKeyboardMap* map = VPianoSettings::instance()->getKeyboardMap();
1314 if (!map->getFileName().isEmpty() && map->getFileName() != QSTR_DEFAULT )
1315 ui.pianokeybd->setKeyboardMap(map);
1316 else
1317 ui.pianokeybd->resetKeyboardMap();
1318
1319 map = VPianoSettings::instance()->getRawKeyboardMap();
1320 if (!map->getFileName().isEmpty() && map->getFileName() != QSTR_DEFAULT )
1321 ui.pianokeybd->setRawKeyboardMap(map);
1322 else
1323 ui.pianokeybd->resetRawKeyboardMap();
1324
1325 PianoPalette highlight = VPianoSettings::instance()->getPalette(VPianoSettings::instance()->highlightPaletteId());
1326 ui.pianokeybd->setHighlightPalette(highlight);
1327 PianoPalette background = VPianoSettings::instance()->getPalette(VPianoSettings::instance()->colorScale() ? PAL_SCALE : PAL_KEYS);
1328 ui.pianokeybd->setBackgroundPalette(background);
1329 ui.pianokeybd->setForegroundPalette(VPianoSettings::instance()->getPalette(PAL_FONT));
1330 ui.pianokeybd->setShowColorScale(VPianoSettings::instance()->colorScale());
1331
1332 populateInstruments();
1333 populateControllers();
1334
1335 QPoint wpos = pos();
1336 Qt::WindowFlags flags = windowFlags();
1337 if (VPianoSettings::instance()->alwaysOnTop())
1338 flags |= Qt::WindowStaysOnTopHint;
1339 else
1340 flags &= ~Qt::WindowStaysOnTopHint;
1341 setWindowFlags( flags );
1342 move(wpos);
1343 }
1344
populateInstruments()1345 void VPiano::populateInstruments()
1346 {
1347 m_ins = nullptr;
1348 m_comboBank->clear();
1349 m_comboProg->clear();
1350 int channel = VPianoSettings::instance()->channel();
1351 //qDebug() << Q_FUNC_INFO << VPianoSettings::instance()->insFileName();
1352 if (!VPianoSettings::instance()->insFileName().isEmpty() &&
1353 VPianoSettings::instance()->insFileName() != QSTR_DEFAULT) {
1354 if (channel == VPianoSettings::instance()->drumsChannel())
1355 m_ins = VPianoSettings::instance()->getDrumsInstrument();
1356 else
1357 m_ins = VPianoSettings::instance()->getInstrument();
1358 if (m_ins != nullptr) {
1359 //qDebug() << "Instrument Name:" << m_ins->instrumentName();
1360 //qDebug() << "Bank Selection method: " << m_ins->bankSelMethod();
1361 InstrumentPatches patches = m_ins->patches();
1362 InstrumentPatches::ConstIterator j;
1363 for( j = patches.constBegin(); j != patches.constEnd(); ++j ) {
1364 //if (j.key() < 0) continue;
1365 InstrumentData patch = j.value();
1366 m_comboBank->addItem(patch.name(), j.key());
1367 //qDebug() << "---- Bank[" << j.key() << "]=" << patch.name();
1368 }
1369 updateBankChange(m_lastBank[channel]);
1370 }
1371 }
1372 }
1373
applyInitialSettings()1374 void VPiano::applyInitialSettings()
1375 {
1376 int idx, ctl, channel;
1377 for ( int ch=0; ch<MIDICHANNELS; ++ch) {
1378 initControllers(ch);
1379 QMap<int,int>::Iterator i, j, end;
1380 i = m_ctlSettings[ch].begin();
1381 end = m_ctlSettings[ch].end();
1382 for (; i != end; ++i) {
1383 j = m_ctlState[ch].find(i.key());
1384 if (j != m_ctlState[ch].end())
1385 m_ctlState[ch][i.key()] = i.value();
1386 }
1387 }
1388 channel = VPianoSettings::instance()->channel();
1389 ctl = m_lastCtl[channel];
1390 idx = m_comboControl->findData(ctl);
1391 if (idx != -1)
1392 m_comboControl->setCurrentIndex(idx);
1393 updateBankChange(m_lastBank[channel]);
1394 idx = m_comboProg->findData(m_lastProg[channel]);
1395 m_comboProg->setCurrentIndex(idx);
1396 }
1397
slotPreferences()1398 void VPiano::slotPreferences()
1399 {
1400 QPointer<Preferences> dlgPreferences = new Preferences(this);
1401 dlgPreferences->setNoteNames(ui.pianokeybd->standardNoteNames());
1402 releaseKb();
1403 if (dlgPreferences->exec() == QDialog::Accepted) {
1404 applyPreferences();
1405 }
1406 delete dlgPreferences;
1407 grabKb();
1408 }
1409
1410
slotEditKeyboardMap()1411 void VPiano::slotEditKeyboardMap()
1412 {
1413 #if !defined(SMALL_SCREEN)
1414 VMPKKeyboardMap* map = nullptr;
1415 if (VPianoSettings::instance()->rawKeyboard()) {
1416 map = VPianoSettings::instance()->getRawKeyboardMap();
1417 map->copyFrom(ui.pianokeybd->getRawKeyboardMap(), true);
1418 } else {
1419 map = VPianoSettings::instance()->getKeyboardMap();
1420 map->copyFrom(ui.pianokeybd->getKeyboardMap(), false);
1421 }
1422 QPointer<KMapDialog> dlgKeyMap = new KMapDialog(this);
1423 dlgKeyMap->displayMap(map);
1424 releaseKb();
1425 if (dlgKeyMap->exec() == QDialog::Accepted) {
1426 dlgKeyMap->getMap(map);
1427 if (VPianoSettings::instance()->rawKeyboard()) {
1428 ui.pianokeybd->setRawKeyboardMap(map);
1429 } else {
1430 ui.pianokeybd->setKeyboardMap(map);
1431 }
1432 }
1433 grabKb();
1434 delete dlgKeyMap;
1435 #endif
1436 }
1437
populatePrograms(int bank)1438 void VPiano::populatePrograms(int bank)
1439 {
1440 if (bank < 0)
1441 return;
1442 m_comboProg->clear();
1443 if (m_ins != nullptr) {
1444 InstrumentData patch = m_ins->patch(bank);
1445 InstrumentData::ConstIterator k;
1446 for( k = patch.constBegin(); k != patch.constEnd(); ++k )
1447 m_comboProg->addItem(k.value(), k.key());
1448 //qDebug() << "patch[" << k.key() << "]=" << k.value();
1449 }
1450 }
1451
slotComboBankActivated(const int index)1452 void VPiano::slotComboBankActivated(const int index)
1453 {
1454 int idx = index;
1455 if (idx < 0)
1456 m_comboBank->setCurrentIndex(idx = 0);
1457 int bank = m_comboBank->itemData(idx).toInt();
1458 populatePrograms(bank);
1459 slotComboProgActivated();
1460 }
1461
slotComboProgActivated(const int index)1462 void VPiano::slotComboProgActivated(const int index)
1463 {
1464 int idx = index;
1465 int channel = VPianoSettings::instance()->channel();
1466 if (idx < 0)
1467 m_comboProg->setCurrentIndex(idx = 0);
1468 int bankIdx = m_comboBank->currentIndex();
1469 int bank = m_comboBank->itemData(bankIdx).toInt();
1470 if (bank >= 0) {
1471 sendBankChange(bank);
1472 m_lastBank[channel] = bank;
1473 }
1474 int pgm = m_comboProg->itemData(idx).toInt();
1475 if (pgm >= 0) {
1476 sendProgramChange(pgm);
1477 m_lastProg[channel] = pgm;
1478 }
1479 updateNoteNames(channel == VPianoSettings::instance()->drumsChannel());
1480 }
1481
slotBaseOctaveValueChanged(const int octave)1482 void VPiano::slotBaseOctaveValueChanged(const int octave)
1483 {
1484 if (octave != VPianoSettings::instance()->baseOctave()) {
1485 allNotesOff();
1486 ui.pianokeybd->setBaseOctave(octave);
1487 VPianoSettings::instance()->setBaseOctave(octave);
1488 }
1489 }
1490
slotTransposeValueChanged(const int transpose)1491 void VPiano::slotTransposeValueChanged(const int transpose)
1492 {
1493 if (transpose != VPianoSettings::instance()->transpose()) {
1494 ui.pianokeybd->setTranspose(transpose);
1495 VPianoSettings::instance()->setTranspose(transpose);
1496 }
1497 }
1498
updateNoteNames(bool drums)1499 void VPiano::updateNoteNames(bool drums)
1500 {
1501 if (drums && (m_ins != nullptr)) {
1502 int channel = VPianoSettings::instance()->drumsChannel();
1503 int b = m_lastBank[channel];
1504 int p = m_lastProg[channel];
1505 const InstrumentData& notes = m_ins->notes(b, p);
1506 QStringList noteNames;
1507 for(int n=0; n<128; ++n) {
1508 if (notes.contains(n))
1509 noteNames << notes[n];
1510 else
1511 noteNames << QString();
1512 }
1513 ui.pianokeybd->useCustomNoteNames(noteNames);
1514 } else
1515 ui.pianokeybd->useStandardNoteNames();
1516 }
1517
slotChannelValueChanged(const int channel)1518 void VPiano::slotChannelValueChanged(const int channel)
1519 {
1520 int idx;
1521 int c = channel - 1;
1522 int baseChannel = VPianoSettings::instance()->channel();
1523 if (c != baseChannel) {
1524 int drms = VPianoSettings::instance()->drumsChannel();
1525 bool updDrums = ((c == drms) || (baseChannel == drms));
1526 baseChannel = c;
1527 allNotesOff();
1528 VPianoSettings::instance()->setChannel(c);
1529 ui.pianokeybd->setChannel(c);
1530 if (updDrums) {
1531 populateInstruments();
1532 populateControllers();
1533 updateNoteNames(c == drms);
1534 }
1535 idx = m_comboControl->findData(m_lastCtl[baseChannel]);
1536 if (idx != -1) {
1537 int ctl = m_lastCtl[baseChannel];
1538 m_comboControl->setCurrentIndex(idx);
1539 updateController(ctl, m_ctlState[baseChannel][ctl]);
1540 updateExtraController(ctl, m_ctlState[baseChannel][ctl]);
1541 }
1542 updateBankChange(m_lastBank[baseChannel]);
1543 updateProgramChange(m_lastProg[baseChannel]);
1544 enforceMIDIChannelState();
1545 }
1546 }
1547
updateController(int ctl,int val)1548 void VPiano::updateController(int ctl, int val)
1549 {
1550 int index = m_comboControl->currentIndex();
1551 int controller = m_comboControl->itemData(index).toInt();
1552 int channel = VPianoSettings::instance()->channel();
1553 if (controller == ctl) {
1554 m_Control->setValue(val);
1555 m_Control->setToolTip(QString::number(val));
1556 }
1557 m_ctlState[channel][ctl] = val;
1558 if ((ctl == CTL_MSB || ctl == CTL_LSB ) && m_ins != nullptr) {
1559 if (m_ins->bankSelMethod() == 0)
1560 m_lastBank[channel] = m_ctlState[channel][CTL_MSB] << 7 |
1561 m_ctlState[channel][CTL_LSB];
1562 else
1563 m_lastBank[channel] = val;
1564
1565 updateBankChange(m_lastBank[channel]);
1566 }
1567 }
1568
updateExtraController(int ctl,int val)1569 void VPiano::updateExtraController(int ctl, int val)
1570 {
1571 QList<QWidget *> allWidgets = ui.toolBarExtra->findChildren<QWidget *>();
1572 foreach(QWidget *w, allWidgets) {
1573 QVariant p = w->property(MIDICTLNUMBER);
1574 if (p.isValid() && p.toInt() == ctl) {
1575 QVariant v = w->property("value");
1576 if (v.isValid() && v.toInt() != val) {
1577 w->setProperty("value", val);
1578 w->setToolTip(QString::number(val));
1579 continue;
1580 }
1581 v = w->property("checked");
1582 if (v.isValid()) {
1583 QVariant on = w->property(MIDICTLONVALUE);
1584 bool checked = (val >= on.toInt());
1585 w->setProperty("checked", checked);
1586 }
1587 }
1588 }
1589 }
1590
updateBankChange(int bank)1591 void VPiano::updateBankChange(int bank)
1592 {
1593 int idx;
1594 int channel = VPianoSettings::instance()->channel();
1595 if (bank < 0) {
1596 m_comboBank->setCurrentIndex(idx = 0);
1597 bank = m_comboBank->itemData(idx).toInt();
1598 if (bank < 0)
1599 bank = 0;
1600 } else {
1601 idx = m_comboBank->findData(bank);
1602 if (idx != -1) {
1603 m_comboBank->setCurrentIndex(idx);
1604 m_lastBank[channel] = bank;
1605 }
1606 }
1607 populatePrograms(bank);
1608 updateProgramChange();
1609 }
1610
updateProgramChange(int program)1611 void VPiano::updateProgramChange(int program)
1612 {
1613 int idx;
1614 int channel = VPianoSettings::instance()->channel();
1615 if (program < 0) {
1616 m_comboProg->setCurrentIndex(idx = 0);
1617 program = m_comboProg->itemData(idx).toInt();
1618 } else {
1619 idx = m_comboProg->findData(program);
1620 if (idx != -1) {
1621 m_comboProg->setCurrentIndex(idx);
1622 m_lastProg[channel] = program;
1623 }
1624 }
1625 updateNoteNames(channel == VPianoSettings::instance()->drumsChannel());
1626 }
1627
slotComboControlCurrentIndexChanged(const int index)1628 void VPiano::slotComboControlCurrentIndexChanged(const int index)
1629 {
1630 int channel = VPianoSettings::instance()->channel();
1631 int ctl = m_comboControl->itemData(index).toInt();
1632 int val = m_ctlState[channel][ctl];
1633 m_Control->setValue(val);
1634 m_Control->setToolTip(QString::number(val));
1635 m_lastCtl[channel] = ctl;
1636 }
1637
grabKb()1638 void VPiano::grabKb()
1639 {
1640 #if defined(RAWKBD_SUPPORT)
1641 m_filter->setRawKbdEnabled(VPianoSettings::instance()->rawKeyboard());
1642 #endif
1643 }
1644
releaseKb()1645 void VPiano::releaseKb()
1646 {
1647 #if defined(RAWKBD_SUPPORT)
1648 m_filter->setRawKbdEnabled(false);
1649 #endif
1650 }
1651
1652 #if defined(SMALL_SCREEN)
1653 class HelpDialog : public QDialog
1654 {
1655 public:
HelpDialog(const QUrl & document,QWidget * parent=nullptr)1656 HelpDialog(const QUrl &document, QWidget *parent = nullptr) : QDialog(parent)
1657 {
1658 setWindowState(Qt::WindowMaximized | Qt::WindowActive);
1659 QVBoxLayout *layout = new QVBoxLayout(this);
1660 QTextBrowser *browser = new QTextBrowser(this);
1661 layout->addWidget(browser);
1662 QDialogButtonBox *buttonBox = new QDialogButtonBox(this);
1663 buttonBox->setOrientation(Qt::Horizontal);
1664 buttonBox->setStandardButtons(QDialogButtonBox::Ok);
1665 layout->addWidget(buttonBox);
1666 browser->setSource(document);
1667 connect(buttonBox, SIGNAL(accepted()), SLOT(close()));
1668 }
1669 };
1670 #endif
1671
slotHelpContents()1672 void VPiano::slotHelpContents()
1673 {
1674 QStringList hlps;
1675 QLocale loc(VPianoSettings::instance()->language());
1676 QStringList lc = loc.name().split("_");
1677 hlps += QSTR_HELPL.arg(loc.name());
1678 if (lc.count() > 1)
1679 hlps += QSTR_HELPL.arg(lc[0]);
1680 hlps += QSTR_HELP;
1681 QDir hlpDir(VPianoSettings::dataDirectory());
1682 foreach(const QString& hlp_name, hlps) {
1683 if (hlpDir.exists(hlp_name)) {
1684 QUrl url = QUrl::fromLocalFile(hlpDir.absoluteFilePath(hlp_name));
1685 #if defined(SMALL_SCREEN)
1686 HelpDialog hlpDlg(url, this);
1687 hlpDlg.exec();
1688 #else
1689 QDesktopServices::openUrl(url);
1690 #endif
1691 return;
1692 }
1693 }
1694 QMessageBox::critical(this, tr("Error"), tr("No help file found"));
1695 }
1696
slotOpenWebSite()1697 void VPiano::slotOpenWebSite()
1698 {
1699 QUrl url(QSTR_VMPKURL);
1700 QDesktopServices::openUrl(url);
1701 }
1702
slotImportSF()1703 void VPiano::slotImportSF()
1704 {
1705 QPointer<RiffImportDlg> dlgRiffImport = new RiffImportDlg(this);
1706 releaseKb();
1707 if ((dlgRiffImport->exec() == QDialog::Accepted) &&
1708 !dlgRiffImport->getOutput().isEmpty()) {
1709 dlgRiffImport->save();
1710 VPianoSettings::instance()->setInstruments(dlgRiffImport->getOutput(), dlgRiffImport->getName());
1711 applyPreferences();
1712 }
1713 grabKb();
1714 delete dlgRiffImport;
1715 }
1716
slotEditExtraControls()1717 void VPiano::slotEditExtraControls()
1718 {
1719 QPointer<DialogExtraControls> dlgExtra = new DialogExtraControls(this);
1720 dlgExtra->setControls(m_extraControls);
1721 releaseKb();
1722 if (dlgExtra->exec() == QDialog::Accepted) {
1723 m_extraControls = dlgExtra->getControls();
1724 clearExtraControllers();
1725 initExtraControllers();
1726 }
1727 grabKb();
1728 delete dlgExtra;
1729 }
1730
setWidgetTip(QWidget * w,int val)1731 void VPiano::setWidgetTip(QWidget* w, int val)
1732 {
1733 QString tip = QString::number(val);
1734 w->setToolTip(tip);
1735 QToolTip::showText(w->parentWidget()->mapToGlobal(w->pos()), tip);
1736 }
1737
1738 //void VPiano::slotEditPrograms()
1739 //{ }
1740
1741 #if defined(ENABLE_DBUS)
quit()1742 void VPiano::quit()
1743 {
1744 close();
1745 }
1746
panic()1747 void VPiano::panic()
1748 {
1749 allNotesOff();
1750 }
1751
reset_controllers()1752 void VPiano::reset_controllers()
1753 {
1754 resetAllControllers();
1755 }
1756
channel(int value)1757 void VPiano::channel(int value)
1758 {
1759 if (value >= 0 && value < MIDICHANNELS)
1760 m_sboxChannel->setValue(value + 1);
1761 }
1762
octave(int value)1763 void VPiano::octave(int value)
1764 {
1765 m_sboxOctave->setValue(value);
1766 }
1767
transpose(int value)1768 void VPiano::transpose(int value)
1769 {
1770 m_sboxTranspose->setValue(value);
1771 }
1772
velocity(int value)1773 void VPiano::velocity(int value)
1774 {
1775 m_Velocity->setValue(value);
1776 }
1777
connect_in(const QString & value)1778 void VPiano::connect_in(const QString &value)
1779 {
1780 if( m_midiin != nullptr) {
1781 m_midiin->close();
1782 if (!value.isEmpty()) {
1783 for(const MIDIConnection& conn : m_midiin->connections()) {
1784 if (conn.first == value) {
1785 m_midiin->open(conn);
1786 break;
1787 }
1788 }
1789 }
1790 }
1791 }
1792
connect_out(const QString & value)1793 void VPiano::connect_out(const QString &value)
1794 {
1795 if( m_midiout != nullptr) {
1796 m_midiout->close();
1797 if (!value.isEmpty()) {
1798 for(const MIDIConnection& conn : m_midiout->connections()) {
1799 if (conn.first == value) {
1800 m_midiout->open(conn);
1801 if (m_midiin != nullptr) {
1802 m_midiin->setMIDIThruDevice(m_midiout);
1803 m_midiin->enableMIDIThru(VPianoSettings::instance()->midiThru());
1804 }
1805 break;
1806 }
1807 }
1808 }
1809 }
1810 }
1811
connect_thru(bool value)1812 void VPiano::connect_thru(bool value)
1813 {
1814 if( m_midiin != nullptr && m_midiout != nullptr) {
1815 m_midiin->enableMIDIThru(value);
1816 m_midiin->setMIDIThruDevice(m_midiout);
1817 }
1818 }
1819
noteoff(int note)1820 void VPiano::noteoff(int note)
1821 {
1822 sendNoteOff(note, 0);
1823 }
1824
noteon(int note)1825 void VPiano::noteon(int note)
1826 {
1827 sendNoteOn(note, VPianoSettings::instance()->velocity());
1828 }
1829
polykeypress(int note,int value)1830 void VPiano::polykeypress(int note, int value)
1831 {
1832 sendPolyKeyPress(note, value);
1833 }
1834
controlchange(int control,int value)1835 void VPiano::controlchange(int control, int value)
1836 {
1837 sendController(control, value);
1838 }
1839
programchange(int value)1840 void VPiano::programchange(int value)
1841 {
1842 sendProgramChange(value);
1843 }
1844
programnamechange(const QString & value)1845 void VPiano::programnamechange(const QString &value)
1846 {
1847 int idx = m_comboProg->findText(value, Qt::MatchFixedString);
1848 if (idx != -1) {
1849 int prg = m_comboProg->itemData(idx).toInt();
1850 programchange(prg);
1851 }
1852 }
1853
chankeypress(int value)1854 void VPiano::chankeypress(int value)
1855 {
1856 sendChanKeyPress(value);
1857 }
1858
pitchwheel(int value)1859 void VPiano::pitchwheel(int value)
1860 {
1861 sendBender(value);
1862 }
1863
1864 #endif /* ENABLE_DBUS */
1865
slotShortcuts()1866 void VPiano::slotShortcuts()
1867 {
1868 #if !defined(SMALL_SCREEN)
1869 QPointer<ShortcutDialog> shcutDlg = new ShortcutDialog(findChildren<QAction*>(), this);
1870 releaseKb();
1871 shcutDlg->setDefaultShortcuts(m_defaultShortcuts);
1872 shcutDlg->exec();
1873 grabKb();
1874 delete shcutDlg;
1875 #endif
1876 }
1877
slotBankNext()1878 void VPiano::slotBankNext()
1879 {
1880 int index = m_comboBank->currentIndex();
1881 if (index < m_comboBank->count()-1) {
1882 m_comboBank->setCurrentIndex(++index);
1883 slotComboBankActivated(index);
1884 }
1885 }
1886
slotBankPrev()1887 void VPiano::slotBankPrev()
1888 {
1889 int index = m_comboBank->currentIndex();
1890 if (index > 0) {
1891 m_comboBank->setCurrentIndex(--index);
1892 slotComboBankActivated(index);
1893 }
1894 }
1895
slotProgramNext()1896 void VPiano::slotProgramNext()
1897 {
1898 int index = m_comboProg->currentIndex();
1899 if (index < m_comboProg->count()-1) {
1900 m_comboProg->setCurrentIndex(++index);
1901 slotComboProgActivated(index);
1902 }
1903 }
1904
slotProgramPrev()1905 void VPiano::slotProgramPrev()
1906 {
1907 int index = m_comboProg->currentIndex();
1908 if (index > 0) {
1909 m_comboProg->setCurrentIndex(--index);
1910 slotComboProgActivated(index);
1911 }
1912 }
1913
slotControllerNext()1914 void VPiano::slotControllerNext()
1915 {
1916 int index = m_comboControl->currentIndex();
1917 if (index < m_comboControl->count()-1)
1918 m_comboControl->setCurrentIndex(++index);
1919 }
1920
slotControllerPrev()1921 void VPiano::slotControllerPrev()
1922 {
1923 int index = m_comboControl->currentIndex();
1924 if (index > 0)
1925 m_comboControl->setCurrentIndex(--index);
1926 }
1927
slotVelocityUp()1928 void VPiano::slotVelocityUp()
1929 {
1930 m_Velocity->triggerAction(QDial::SliderPageStepAdd);
1931 }
1932
slotVelocityDown()1933 void VPiano::slotVelocityDown()
1934 {
1935 m_Velocity->triggerAction(QDial::SliderPageStepSub);
1936 }
1937
slotControllerUp()1938 void VPiano::slotControllerUp()
1939 {
1940 m_Control->triggerAction(QDial::SliderPageStepAdd);
1941 slotControlSliderMoved(m_Control->value());
1942 }
1943
slotControllerDown()1944 void VPiano::slotControllerDown()
1945 {
1946 m_Control->triggerAction(QDial::SliderPageStepSub);
1947 slotControlSliderMoved(m_Control->value());
1948 }
1949
slotSwitchLanguage(QAction * action)1950 void VPiano::slotSwitchLanguage(QAction *action)
1951 {
1952 QString lang = action->data().toString();
1953 bool result = QMessageBox::question (this, tr("Language Changed"),
1954 tr("The language for this application is going to change to %1. "
1955 "Do you want to continue?").arg(m_supportedLangs[lang]),
1956 QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes;
1957 if ( result )
1958 {
1959 VPianoSettings::instance()->setLanguage(lang);
1960 retranslateUi();
1961 } else {
1962 m_currentLang->setChecked(true);
1963 }
1964 }
1965
createLanguageMenu()1966 void VPiano::createLanguageMenu()
1967 {
1968 QString currentLang = VPianoSettings::instance()->language();
1969 QActionGroup *languageGroup = new QActionGroup(this);
1970 languageGroup->setExclusive(true);
1971 connect(languageGroup, &QActionGroup::triggered, this, &VPiano::slotSwitchLanguage, Qt::QueuedConnection);
1972 QDir dir(VPianoSettings::localeDirectory());
1973 QStringList fileNames = dir.entryList(QStringList(QSTR_VMPKPX + "*.qm"));
1974 QStringList locales;
1975 locales << "en";
1976 foreach (const QString& fileName, fileNames) {
1977 QString locale = fileName;
1978 locale.remove(0, locale.indexOf('_') + 1);
1979 locale.truncate(locale.lastIndexOf('.'));
1980 locales << locale;
1981 }
1982 locales.sort();
1983 foreach (const QString& loc, locales) {
1984 QAction *action = new QAction(m_supportedLangs.value(loc), this);
1985 action->setCheckable(true);
1986 action->setData(loc);
1987 ui.menuLanguage->addAction(action);
1988 languageGroup->addAction(action);
1989 if (currentLang.startsWith(loc)) {
1990 action->setChecked(true);
1991 m_currentLang = action;
1992 }
1993 }
1994 }
1995
slotAboutTranslation()1996 void VPiano::slotAboutTranslation()
1997 {
1998 QString common = tr("<p>VMPK is developed and translated thanks to the "
1999 "volunteer work of many people from around the world. If you want to "
2000 "join the team or have any question, please visit the forums at "
2001 "<a href='http://sourceforge.net/projects/vmpk/forums'>SourceForge</a>"
2002 "</p>");
2003 QString currentLang = VPianoSettings::instance()->language();
2004 bool supported(false);
2005 if (!currentLang.startsWith("en")) {
2006 QMapIterator<QString,QString> it(m_supportedLangs);
2007 while (it.hasNext()) {
2008 it.next();
2009 if (currentLang.startsWith(it.key())) {
2010 supported = true;
2011 break;
2012 }
2013 }
2014 }
2015 if (supported)
2016 QMessageBox::information(this, tr("Translation"),
2017 tr("<p>Translation by TRANSLATOR_NAME_AND_EMAIL</p>%1").arg(common));
2018 else
2019 QMessageBox::information(this, tr("Translation Information"), common);
2020 }
2021
retranslateUi()2022 void VPiano::retranslateUi()
2023 {
2024 m_trq->load(QSTR_QTPX + VPianoSettings::instance()->language(), VPianoSettings::systemLocales());
2025 m_trp->load(QSTR_VMPKPX + VPianoSettings::instance()->language(), VPianoSettings::localeDirectory());
2026 m_trl->load(QSTR_DRUMSTICKPX + VPianoSettings::instance()->language(), VPianoSettings::drumstickLocales());
2027 VPianoSettings::instance()->retranslatePalettes();
2028 ui.retranslateUi(this);
2029 ui.pianokeybd->retranslate();
2030 initLanguages();
2031 ui.menuLanguage->clear();
2032 createLanguageMenu();
2033 retranslateToolbars();
2034 }
2035
initLanguages()2036 void VPiano::initLanguages()
2037 {
2038 m_supportedLangs.clear();
2039 m_supportedLangs.insert(QLatin1String("cs"), tr("Czech"));
2040 m_supportedLangs.insert(QLatin1String("de"), tr("German"));
2041 m_supportedLangs.insert(QLatin1String("en"), tr("English"));
2042 m_supportedLangs.insert(QLatin1String("es"), tr("Spanish"));
2043 m_supportedLangs.insert(QLatin1String("fr"), tr("French"));
2044 m_supportedLangs.insert(QLatin1String("gl"), tr("Galician"));
2045 m_supportedLangs.insert(QLatin1String("nl"), tr("Dutch"));
2046 m_supportedLangs.insert(QLatin1String("ru"), tr("Russian"));
2047 m_supportedLangs.insert(QLatin1String("sr"), tr("Serbian"));
2048 m_supportedLangs.insert(QLatin1String("sv"), tr("Swedish"));
2049 m_supportedLangs.insert(QLatin1String("zh_CN"), tr("Chinese"));
2050 }
2051
retranslateToolbars()2052 void VPiano::retranslateToolbars()
2053 {
2054 m_lblChannel->setText(
2055 #if defined(SMALL_SCREEN)
2056 tr("Chan:")
2057 #else
2058 tr("Channel:")
2059 #endif
2060 );
2061 m_lblBaseOctave->setText(
2062 #if defined(SMALL_SCREEN)
2063 tr("Oct:")
2064 #else
2065 tr("Base Octave:")
2066 #endif
2067 );
2068 m_lblTranspose->setText(
2069 #if defined(SMALL_SCREEN)
2070 tr("Trans:")
2071 #else
2072 tr("Transpose:")
2073 #endif
2074 );
2075 m_lblVelocity->setText(
2076 #if defined(SMALL_SCREEN)
2077 tr("Vel:")
2078 #else
2079 tr("Velocity:")
2080 #endif
2081 );
2082 m_lblBank->setText(tr("Bank:"));
2083 m_lblBender->setText(tr("Bender:"));
2084 m_lblControl->setText(tr("Control:"));
2085 m_lblProgram->setText(tr("Program:"));
2086 m_lblValue->setText(tr("Value:"));
2087 }
2088
createPopupMenu()2089 QMenu * VPiano::createPopupMenu ()
2090 {
2091 #if defined(SMALL_SCREEN)
2092 return 0;
2093 #else
2094 return QMainWindow::createPopupMenu();
2095 #endif
2096 }
2097
enforceMIDIChannelState()2098 void VPiano::enforceMIDIChannelState()
2099 {
2100 if (VPianoSettings::instance()->enforceChannelState()) {
2101 int channel = VPianoSettings::instance()->channel();
2102 //qDebug() << Q_FUNC_INFO << "channel=" << m_channel << endl;
2103 QMap<int,int>::Iterator i, end;
2104 i = m_ctlSettings[channel].begin();
2105 end = m_ctlSettings[channel].end();
2106 for (; i != end; ++i) {
2107 //qDebug() << "ctl=" << i.key() << "val=" << i.value();
2108 sendController(i.key(), i.value());
2109 }
2110 //qDebug() << "bank=" << m_lastBank[m_channel];
2111 sendBankChange(m_lastBank[channel]);
2112 //qDebug() << "prog=" << m_lastProg[m_channel];
2113 sendProgramChange(m_lastProg[channel]);
2114 }
2115 }
2116
slotKeyboardInput(bool value)2117 void VPiano::slotKeyboardInput(bool value)
2118 {
2119 VPianoSettings::instance()->setEnableKeyboard(value);
2120 ui.pianokeybd->setKeyboardEnabled(value);
2121 }
2122
slotMouseInput(bool value)2123 void VPiano::slotMouseInput(bool value)
2124 {
2125 VPianoSettings::instance()->setEnableMouse(value);
2126 ui.pianokeybd->setMouseEnabled(value);
2127 }
2128
slotTouchScreenInput(bool value)2129 void VPiano::slotTouchScreenInput(bool value)
2130 {
2131 VPianoSettings::instance()->setEnableTouch(value);
2132 ui.pianokeybd->setTouchEnabled(value);
2133 }
2134
slotColorPolicy()2135 void VPiano::slotColorPolicy()
2136 {
2137 QPointer<ColorDialog> dlgColorPolicy = new ColorDialog(false, this);
2138 dlgColorPolicy->loadPalette(VPianoSettings::instance()->highlightPaletteId());
2139 if (dlgColorPolicy->exec() == QDialog::Accepted) {
2140 int pal = dlgColorPolicy->selectedPalette();
2141 PianoPalette editedPalette = VPianoSettings::instance()->getPalette(pal);
2142 if (editedPalette.isHighLight()) {
2143 VPianoSettings::instance()->setHighlightPaletteId(pal);
2144 ui.pianokeybd->setHighlightPalette(editedPalette);
2145 } else if (editedPalette.isBackground()) {
2146 if ((VPianoSettings::instance()->colorScale() && (editedPalette.paletteId() == PAL_SCALE)) ||
2147 (!VPianoSettings::instance()->colorScale() && (editedPalette.paletteId() == PAL_KEYS))) {
2148 ui.pianokeybd->setBackgroundPalette(editedPalette);
2149 }
2150 } else if (editedPalette.isForeground()) {
2151 ui.pianokeybd->setForegroundPalette(editedPalette);
2152 }
2153 }
2154 delete dlgColorPolicy;
2155 }
2156
slotColorScale(bool value)2157 void VPiano::slotColorScale(bool value)
2158 {
2159 if (value != VPianoSettings::instance()->colorScale()) {
2160 VPianoSettings::instance()->setColorScale(value);
2161 ui.pianokeybd->setBackgroundPalette(VPianoSettings::instance()->getPalette(value ? PAL_SCALE : PAL_KEYS));
2162 ui.pianokeybd->setShowColorScale(value);
2163 }
2164 }
2165
toggleWindowFrame(const bool state)2166 void VPiano::toggleWindowFrame(const bool state)
2167 {
2168 Qt::WindowFlags flags = windowFlags();
2169
2170 if (state)
2171 flags &= ~Qt::FramelessWindowHint;
2172 else
2173 flags |= Qt::FramelessWindowHint;
2174
2175 setWindowFlags(flags);
2176 show();
2177 }
2178
2179
slotNameOrientation(QAction * action)2180 void VPiano::slotNameOrientation(QAction* action)
2181 {
2182 if(action == ui.actionHorizontal) {
2183 VPianoSettings::instance()->setNamesOrientation(HorizontalOrientation);
2184 } else if(action == ui.actionVertical) {
2185 VPianoSettings::instance()->setNamesOrientation(VerticalOrientation);
2186 } else if(action == ui.actionAutomatic) {
2187 VPianoSettings::instance()->setNamesOrientation(AutomaticOrientation);
2188 }
2189 ui.pianokeybd->setLabelOrientation(VPianoSettings::instance()->namesOrientation());
2190 }
2191
slotNameVisibility(QAction * action)2192 void VPiano::slotNameVisibility(QAction* action)
2193 {
2194 if(action == ui.actionNever) {
2195 VPianoSettings::instance()->setNamesVisibility(ShowNever);
2196 } else if(action == ui.actionMinimal) {
2197 VPianoSettings::instance()->setNamesVisibility(ShowMinimum);
2198 } else if(action == ui.actionWhen_Activated) {
2199 VPianoSettings::instance()->setNamesVisibility(ShowActivated);
2200 } else if(action == ui.actionAlways) {
2201 VPianoSettings::instance()->setNamesVisibility(ShowAlways);
2202 }
2203 ui.pianokeybd->setShowLabels(VPianoSettings::instance()->namesVisibility());
2204 }
2205
slotNameVariant(QAction * action)2206 void VPiano::slotNameVariant(QAction* action)
2207 {
2208 if(action == ui.actionSharps) {
2209 VPianoSettings::instance()->setNamesAlterations(ShowSharps);
2210 } else if(action == ui.actionFlats) {
2211 VPianoSettings::instance()->setNamesAlterations(ShowFlats);
2212 } else if(action == ui.actionNothing) {
2213 VPianoSettings::instance()->setNamesAlterations(ShowNothing);
2214 }
2215 ui.pianokeybd->setLabelAlterations(VPianoSettings::instance()->alterations());
2216 }
2217
slotNoteName(const QString & name)2218 void VPiano::slotNoteName(const QString& name)
2219 {
2220 if (name.isEmpty()) {
2221 ui.statusBar->clearMessage();
2222 } else {
2223 ui.statusBar->showMessage(name);
2224 }
2225 }
2226
slotLoadConfiguration()2227 void VPiano::slotLoadConfiguration()
2228 {
2229 releaseKb();
2230 auto configDir = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation);
2231 QString fileName = QFileDialog::getOpenFileName(this, tr("Open Configuration File"),
2232 configDir, tr("Configuration files (*.conf *.ini)"));
2233 if (!fileName.isEmpty()) {
2234 VPianoSettings::instance()->ReadFromFile(fileName);
2235 qApp->exit(RESTART_VMPK);
2236 }
2237 grabKb();
2238 }
2239
slotSaveConfiguration()2240 void VPiano::slotSaveConfiguration()
2241 {
2242 releaseKb();
2243 auto configDir = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation);
2244 QFileDialog dlg(this);
2245 dlg.setNameFilter(tr("Configuration files (*.conf *.ini)"));
2246 dlg.setDirectory(configDir);
2247 dlg.setWindowTitle(tr("Save Configuration File"));
2248 dlg.setDefaultSuffix("conf");
2249 dlg.setFileMode(QFileDialog::AnyFile);
2250 dlg.setAcceptMode(QFileDialog::AcceptSave);
2251 if (dlg.exec() == QDialog::Accepted) {
2252 auto selected = dlg.selectedFiles();
2253 if (!selected.isEmpty()) {
2254 VPianoSettings::instance()->SaveToFile(selected.first());
2255 }
2256 }
2257 grabKb();
2258 }
2259
2260 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
nativeEvent(const QByteArray & eventType,void * message,long * result)2261 bool VPiano::nativeEvent(const QByteArray &eventType, void *message, long *result)
2262 #else
2263 bool VPiano::nativeEvent(const QByteArray &eventType, void *message, qintptr *result)
2264 #endif
2265 {
2266 #if defined(Q_OS_WINDOWS)
2267 if (VPianoSettings::instance()->getWinSnap() && m_snapper.HandleMessage(message)) {
2268 result = 0;
2269 return true;
2270 }
2271 #endif
2272 return QWidget::nativeEvent(eventType, message, result);
2273 }
2274
changeEvent(QEvent * event)2275 void VPiano::changeEvent(QEvent *event)
2276 {
2277 #if defined(Q_OS_WINDOWS)
2278 if (event->type() == QEvent::PaletteChange) {
2279 foreach(QToolBar *tb, findChildren<QToolBar*>()) {
2280 foreach(QComboBox *cb, tb->findChildren<QComboBox*>()) {
2281 cb->setPalette(qApp->palette());
2282 foreach(QWidget *w, cb->findChildren<QWidget*>()) {
2283 w->setPalette(qApp->palette());
2284 }
2285 //qDebug() << cb;
2286 }
2287 }
2288 }
2289 #endif
2290 QMainWindow::changeEvent(event);
2291 }
2292