drumstick 2.9.0
C++ MIDI libraries using Qt objects, idioms, and style.
pianoscene.cpp
Go to the documentation of this file.
1/*
2 Virtual Piano Widget for Qt
3 Copyright (C) 2008-2023, 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 <QApplication>
21#include <QDataStream>
22#include <QByteArray>
23#include <QGraphicsSceneMouseEvent>
24#include <QKeyEvent>
25#include <QPalette>
26#include <QPixmap>
27#include <QtMath>
28#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
29#include <QTouchDevice>
30#else
31#include <QInputDevice>
32#endif
34#include "pianoscene.h"
35
47namespace drumstick { namespace widgets {
48
49class PianoScene::PianoScenePrivate
50{
51public:
52 PianoScenePrivate ( const int baseOctave,
53 const int numKeys,
54 const int startKey ):
55 m_baseOctave( baseOctave ),
56 m_numKeys( numKeys ),
57 m_startKey( startKey ),
58 m_minNote( 0 ),
59 m_maxNote( 127 ),
60 m_transpose( 0 ),
61 m_showLabels( ShowNever ),
62 m_alterations( ShowSharps ),
63 m_octave( OctaveC4 ),
64 m_orientation( HorizontalOrientation ),
65 m_rawkbd( false ),
66 m_keyboardEnabled( true ),
67 m_mouseEnabled( true ),
68 m_touchEnabled( true ),
69 m_mousePressed( false ),
70 m_velocity( 100 ),
71 m_channel( 0 ),
72 m_velocityTint( true ),
73 m_handler( nullptr ),
74 m_keybdMap( nullptr ),
75 m_showColorScale( false ),
76 m_hilightPalette(PianoPalette(PAL_SINGLE)),
77 m_backgroundPalette(PianoPalette(PAL_KEYS)),
78 m_foregroundPalette(PianoPalette(PAL_FONT)),
79 m_useKeyPix( true ),
80 m_usingNativeFilter( false ),
81 m_octaveSubscript( true )
82 { }
83
84 void saveData(QByteArray& buffer)
85 {
86 QDataStream ds(&buffer, QIODevice::WriteOnly);
87 ds << m_minNote;
88 ds << m_maxNote;
89 ds << m_transpose;
90 ds << m_showLabels;
91 ds << m_alterations;
92 ds << m_octave;
93 ds << m_orientation;
94 ds << m_rawkbd;
95 ds << m_keyboardEnabled;
96 ds << m_mouseEnabled;
97 ds << m_touchEnabled;
98 ds << m_mousePressed;
99 ds << m_velocity;
100 ds << m_channel;
101 ds << m_velocityTint;
102 ds << m_noteNames;
103 ds << m_names_s;
104 ds << m_names_f;
105 ds << m_showColorScale;
106 ds << m_hilightPalette;
107 ds << m_backgroundPalette;
108 ds << m_foregroundPalette;
109 ds << m_useKeyPix;
110 ds << m_keyPix[0];
111 ds << m_keyPix[1];
112 ds << m_usingNativeFilter;
113 ds << m_octaveSubscript;
114 }
115
116 void loadData(QByteArray& buffer)
117 {
118 quint32 u;
119 QDataStream ds(&buffer, QIODevice::ReadOnly);
120 ds >> m_minNote;
121 ds >> m_maxNote;
122 ds >> m_transpose;
123 ds >> u; m_showLabels = LabelVisibility(u);
124 ds >> u; m_alterations = LabelAlteration(u);
125 ds >> u; m_octave = LabelCentralOctave(u);
126 ds >> u; m_orientation = LabelOrientation(u);
127 ds >> m_rawkbd;
128 ds >> m_keyboardEnabled;
129 ds >> m_mouseEnabled;
130 ds >> m_touchEnabled;
131 ds >> m_mousePressed;
132 ds >> m_velocity;
133 ds >> m_channel;
134 ds >> m_velocityTint;
135 ds >> m_noteNames;
136 ds >> m_names_s;
137 ds >> m_names_f;
138 ds >> m_showColorScale;
139 ds >> m_hilightPalette;
140 ds >> m_backgroundPalette;
141 ds >> m_foregroundPalette;
142 ds >> m_useKeyPix;
143 ds >> m_keyPix[0];
144 ds >> m_keyPix[1];
145 ds >> m_usingNativeFilter;
146 ds >> m_octaveSubscript;
147 }
148
149 QString noteName( PianoKey* key, bool richText )
150 {
151 Q_ASSERT(key != nullptr);
152 int note = key->getNote();
153 int num = (note + m_transpose + 12) % 12;
154 int adj = ((note + m_transpose < 0) ? 2 : 1) - m_octave + 1;
155 int oct = m_baseOctave + ((note + m_transpose) / 12) - adj;
156 QString nameMask = QLatin1String(richText && m_octaveSubscript ? "%1<sub>%2</sub>" : "%1%2");
157 if (m_noteNames.isEmpty()) {
158 QString name;
159 if (!m_names_f.isEmpty() && !m_names_s.isEmpty()) {
160 switch(m_alterations) {
161 case ShowFlats:
162 name = m_names_f.value(num);
163 break;
164 case ShowSharps:
165 name = m_names_s.value(num);
166 break;
167 case ShowNothing:
168 if (key->isBlack()) {
169 return QString();
170 }
171 name = m_names_s.value(num);
172 break;
173 default:
174 break;
175 }
176 }
177 if (m_octave==OctaveNothing) {
178 return name;
179 } else {
180 return nameMask.arg(name).arg(oct);
181 }
182 } else {
183 if (m_noteNames.length() == 128) {
184 int n = m_baseOctave*12 + note + m_transpose;
185 //qDebug() << Q_FUNC_INFO << n << note;
186 if (n >= 0 && n < m_noteNames.length()) {
187 return m_noteNames.value(n);
188 }
189 } else if (m_noteNames.length() >= 12) {
190 if (m_octave==OctaveNothing) {
191 return m_noteNames.value(num);
192 } else {
193 return nameMask.arg(m_noteNames.value(num)).arg(oct);
194 }
195 }
196 return QString();
197 }
198 }
199
200 int m_baseOctave;
201 int m_numKeys;
202 int m_startKey;
203 int m_minNote;
204 int m_maxNote;
205 int m_transpose;
206 LabelVisibility m_showLabels;
207 LabelAlteration m_alterations;
208 LabelCentralOctave m_octave;
209 LabelOrientation m_orientation;
210 bool m_rawkbd;
211 bool m_keyboardEnabled;
212 bool m_mouseEnabled;
213 bool m_touchEnabled;
214 bool m_mousePressed;
215 int m_velocity;
216 int m_channel;
217 bool m_velocityTint;
218 PianoHandler *m_handler;
219 KeyboardMap *m_keybdMap;
220 QHash<int, PianoKey *> m_keys;
221 QMap<int, KeyLabel *> m_labels;
222 QStringList m_noteNames;
223 QStringList m_names_s;
224 QStringList m_names_f;
225 bool m_showColorScale;
226 PianoPalette m_hilightPalette;
227 PianoPalette m_backgroundPalette;
228 PianoPalette m_foregroundPalette;
229 bool m_useKeyPix;
230 QPixmap m_keyPix[2];
231 bool m_usingNativeFilter;
232 bool m_octaveSubscript;
233 /* not serialized */
234 PianoKeybd* m_view;
235 QMap<int, PianoKey *> m_touched;
236};
237
238const int KEYWIDTH = 180;
239const int KEYHEIGHT = 720;
240
241static qreal sceneWidth(int keys) {
242 return KEYWIDTH * qCeil( keys * 7.0 / 12.0 );
243}
244
253PianoScene::PianoScene ( const int baseOctave,
254 const int numKeys,
255 const int startKey,
256 const QColor& keyPressedColor,
257 QObject * parent )
258 : QGraphicsScene( QRectF(0, 0, sceneWidth(numKeys), KEYHEIGHT), parent ),
259 d(new PianoScenePrivate(baseOctave, numKeys, startKey))
260{
261 if (keyPressedColor.isValid()) {
262 setKeyPressedColor(keyPressedColor);
263 }
264 QBrush hilightBrush(getKeyPressedColor());
265 d->m_view = dynamic_cast<PianoKeybd*>(parent);
266 if (d->m_view != nullptr) {
267 setFont(d->m_view->font());
268 }
269 int upperLimit = d->m_numKeys + d->m_startKey;
270 int adj = d->m_startKey % 12;
271 if (adj >= 5) adj++;
272 for(int i = d->m_startKey; i < upperLimit; ++i)
273 {
274 float x = 0;
275 PianoKey* key = nullptr;
276 KeyLabel* lbl = nullptr;
277 int ocs = i / 12 * 7;
278 int j = i % 12;
279 if (j >= 5) j++;
280 if ((j % 2) == 0) {
281 x = (ocs + qFloor((j-adj) / 2.0)) * KEYWIDTH;
282 key = new PianoKey( QRectF(x, 0, KEYWIDTH, KEYHEIGHT), false, i );
283 lbl = new KeyLabel(key);
284 lbl->setDefaultTextColor(d->m_foregroundPalette.getColor(0));
285 } else {
286 x = (ocs + qFloor((j-adj) / 2.0)) * KEYWIDTH + KEYWIDTH * 0.6 + 1;
287 key = new PianoKey( QRectF( x, 0, KEYWIDTH * 0.8 - 1, KEYHEIGHT * 0.6 ), true, i );
288 key->setZValue( 1 );
289 lbl = new KeyLabel(key);
290 lbl->setDefaultTextColor(d->m_foregroundPalette.getColor(1));
291 }
292 addItem( key );
293 lbl->setFont(font());
294 key->setAcceptTouchEvents(true);
295 key->setPressedBrush(hilightBrush);
296 d->m_keys.insert(i, key);
297 d->m_labels.insert(i, lbl);
298 }
300 retranslate();
301}
302
307{ }
308
314{
315 return {static_cast<int>(sceneWidth(d->m_numKeys)), KEYHEIGHT};
316}
317
323{
324 d->m_keybdMap = map;
325}
326
332{
333 return d->m_keybdMap;
334}
335
344{
345 return d->m_handler;
346}
347
357{
358 d->m_handler = handler;
359}
360
366{
367 return d->m_hilightPalette;
368}
369
374void PianoScene::displayKeyOn(PianoKey* key)
375{
376 key->setPressed(true);
377 int n = key->getNote() + d->m_baseOctave*12 + d->m_transpose;
378 QString s = QString("#%1 (%2)").arg(n).arg(d->noteName(key, false));
379 Q_EMIT signalName(s);
380 KeyLabel* lbl = dynamic_cast<KeyLabel*>(key->childItems().constFirst());
381 if (lbl != nullptr) {
382 lbl->setDefaultTextColor(d->m_foregroundPalette.getColor(key->isBlack() ? 3 : 2));
383 if (d->m_showLabels == ShowActivated) {
384 lbl->setVisible(true);
385 }
386 }
387}
388
395void PianoScene::showKeyOn( PianoKey* key, QColor color, int vel )
396{
397 //qDebug() << Q_FUNC_INFO << key->getNote() << vel << color << d->m_velocityTint;
398 if (d->m_velocityTint && (vel >= 0) && (vel < 128) && color.isValid() ) {
399 QBrush hilightBrush(color.lighter(200 - vel));
400 key->setPressedBrush(hilightBrush);
401 } else if (color.isValid()) {
402 key->setPressedBrush(color);
403 }
404 displayKeyOn(key);
405}
406
412void PianoScene::showKeyOn( PianoKey* key, int vel )
413{
415 displayKeyOn(key);
416}
417
423void PianoScene::showKeyOff( PianoKey* key, int vel)
424{
425 Q_UNUSED(vel)
426 key->setPressed(false);
427 Q_EMIT signalName(QString());
428 KeyLabel* lbl = dynamic_cast<KeyLabel*>(key->childItems().constFirst());
429 if (lbl != nullptr) {
430 lbl->restoreColor();
431 if (d->m_showLabels == ShowActivated) {
432 lbl->setVisible(false);
433 }
434 }
435}
436
443void PianoScene::showNoteOn( const int note, QColor color, int vel )
444{
445 //qDebug() << Q_FUNC_INFO << note << vel << color;
446 int n = note - d->m_baseOctave*12 - d->m_transpose;
447 if ((note >= d->m_minNote) && (note <= d->m_maxNote) && d->m_keys.contains(n) && color.isValid())
448 showKeyOn(d->m_keys.value(n), color, vel);
449}
450
456void PianoScene::showNoteOn( const int note, int vel )
457{
458 //qDebug() << Q_FUNC_INFO << note << vel;
459 int n = note - d->m_baseOctave*12 - d->m_transpose;
460 if ((note >= d->m_minNote) && (note <= d->m_maxNote) && d->m_keys.contains(n)) {
461 showKeyOn(d->m_keys.value(n), vel);
462 }
463}
464
470void PianoScene::showNoteOff( const int note, int vel )
471{
472 int n = note - d->m_baseOctave*12 - d->m_transpose;
473 if ((note >= d->m_minNote) && (note <= d->m_maxNote) && d->m_keys.contains(n)) {
474 showKeyOff(d->m_keys.value(n), vel);
475 }
476}
477
483int PianoScene::baseOctave() const { return d->m_baseOctave; }
484
492void PianoScene::triggerNoteOn( const int note, const int vel )
493{
494 int n = d->m_baseOctave*12 + note + d->m_transpose;
495 if ((n >= d->m_minNote) && (n <= d->m_maxNote)) {
496 if (d->m_handler != nullptr) {
497 d->m_handler->noteOn(n, vel);
498 } else {
499 Q_EMIT noteOn(n, vel);
500 }
501 }
502}
503
511void PianoScene::triggerNoteOff( const int note, const int vel )
512{
513 int n = d->m_baseOctave*12 + note + d->m_transpose;
514 if ((n >= d->m_minNote) && (n <= d->m_maxNote)) {
515 if (d->m_handler != nullptr) {
516 d->m_handler->noteOff(n, vel);
517 } else {
518 Q_EMIT noteOff(n, vel);
519 }
520 }
521}
522
529void PianoScene::setHighlightColorFromPolicy(PianoKey* key, int vel)
530{
531 QColor c;
532 //qDebug() << Q_FUNC_INFO << key->getNote() << vel << d->m_velocityTint;
533 switch (d->m_hilightPalette.paletteId()) {
534 case PAL_SINGLE:
535 c = d->m_hilightPalette.getColor(0);
536 break;
537 case PAL_DOUBLE:
538 c = d->m_hilightPalette.getColor(key->getType());
539 break;
540 case PAL_CHANNELS:
541 c = d->m_hilightPalette.getColor(d->m_channel);
542 break;
543 case PAL_HISCALE:
544 c = d->m_hilightPalette.getColor(key->getDegree());
545 break;
546 default:
547 return;
548 }
549 if (c.isValid()) {
550 if (d->m_velocityTint && (vel >= 0) && (vel < 128)) {
551 QBrush h(c.lighter(200 - vel));
552 key->setPressedBrush(h);
553 } else {
554 key->setPressedBrush(c);
555 }
556 }
557}
558
563void PianoScene::keyOn( PianoKey* key )
564{
565 triggerNoteOn(key->getNote(), d->m_velocity);
566 showKeyOn(key, d->m_velocity);
567}
568
573void PianoScene::keyOff( PianoKey* key )
574{
575 triggerNoteOff(key->getNote(), 0);
576 showKeyOff(key, 0);
577}
578
584void PianoScene::keyOn( PianoKey* key, qreal pressure )
585{
586 int vel = d->m_velocity * pressure;
587 triggerNoteOn(key->getNote(), vel);
588 showKeyOn(key, vel);
589}
590
596void PianoScene::keyOff( PianoKey* key, qreal pressure )
597{
598 int vel = d->m_velocity * pressure;
599 triggerNoteOff(key->getNote(), vel);
600 showKeyOff(key, vel);
601}
602
607void PianoScene::keyOn(const int note)
608{
609 if (d->m_keys.contains(note))
610 keyOn(d->m_keys.value(note));
611 else
612 triggerNoteOn(note, d->m_velocity);
613}
614
619void PianoScene::keyOff(const int note)
620{
621 if (d->m_keys.contains(note))
622 keyOff(d->m_keys.value(note));
623 else
624 triggerNoteOff(note, d->m_velocity);
625}
626
632{
633 return d->m_rawkbd;
634}
635
641PianoKey* PianoScene::getKeyForPos( const QPointF& p ) const
642{
643 PianoKey* key = nullptr;
644 QList<QGraphicsItem *> ptitems = this->items(p, Qt::IntersectsItemShape, Qt::DescendingOrder);
645 foreach(QGraphicsItem *itm, ptitems) {
646 key = dynamic_cast<PianoKey*>(itm);
647 if (key != nullptr)
648 break;
649 }
650 return key;
651}
652
657void PianoScene::mouseMoveEvent ( QGraphicsSceneMouseEvent * mouseEvent )
658{
659 if (d->m_mouseEnabled && (mouseEvent->source() == Qt::MouseEventNotSynthesized)) {
660 if (d->m_mousePressed) {
661 PianoKey* key = getKeyForPos(mouseEvent->scenePos());
662 PianoKey* lastkey = getKeyForPos(mouseEvent->lastScenePos());
663 if ((lastkey != nullptr) && (lastkey != key) && lastkey->isPressed()) {
664 keyOff(lastkey);
665 }
666 if ((key != nullptr) && !key->isPressed()) {
667 keyOn(key);
668 }
669 mouseEvent->accept();
670 return;
671 }
672 }
673}
674
679void PianoScene::mousePressEvent ( QGraphicsSceneMouseEvent * mouseEvent )
680{
681 if (d->m_mouseEnabled && (mouseEvent->source() == Qt::MouseEventNotSynthesized)) {
682 PianoKey* key = getKeyForPos(mouseEvent->scenePos());
683 if (key != nullptr && !key->isPressed()) {
684 keyOn(key);
685 d->m_mousePressed = true;
686 mouseEvent->accept();
687 return;
688 }
689 }
690}
691
696void PianoScene::mouseReleaseEvent ( QGraphicsSceneMouseEvent * mouseEvent )
697{
698 if (d->m_mouseEnabled && (mouseEvent->source() == Qt::MouseEventNotSynthesized)) {
699 d->m_mousePressed = false;
700 PianoKey* key = getKeyForPos(mouseEvent->scenePos());
701 if (key != nullptr && key->isPressed()) {
702 keyOff(key);
703 mouseEvent->accept();
704 return;
705 }
706 }
707}
708
714int PianoScene::getNoteFromKey( const int key ) const
715{
716 if (d->m_keybdMap != nullptr) {
717 KeyboardMap::ConstIterator it = d->m_keybdMap->constFind(key);
718 if ((it != d->m_keybdMap->constEnd()) && (it.key() == key)) {
719 int note = it.value();
720 return note;
721 }
722 }
723 return -1;
724}
725
731PianoKey* PianoScene::getPianoKey( const int key ) const
732{
733 int note = getNoteFromKey(key);
734 if (d->m_keys.contains(note))
735 return d->m_keys.value(note);
736 return nullptr;
737}
738
743void PianoScene::keyPressEvent ( QKeyEvent * keyEvent )
744{
745 if ( d->m_keyboardEnabled &&
746 !d->m_usingNativeFilter &&
747 !keyEvent->isAutoRepeat() ) // ignore auto-repeats
748 {
749 int keyid = d->m_rawkbd ?
750#if defined(Q_OS_MACOS)
751 keyEvent->nativeVirtualKey()
752#else
753 keyEvent->nativeScanCode()
754#endif
755 : keyEvent->key();
756 int note = getNoteFromKey( keyid );
757 if (note > -1) {
758 keyOn(note);
759 keyEvent->accept();
760 return;
761 }
762 }
763 keyEvent->ignore();
764}
765
770void PianoScene::keyReleaseEvent ( QKeyEvent * keyEvent )
771{
772 if ( d->m_keyboardEnabled &&
773 !d->m_usingNativeFilter &&
774 !keyEvent->isAutoRepeat() ) // ignore auto-repeats
775 {
776 int keyid = d->m_rawkbd ?
777#if defined(Q_OS_MACOS)
778 keyEvent->nativeVirtualKey()
779#else
780 keyEvent->nativeScanCode()
781#endif
782 : keyEvent->key();
783 int note = getNoteFromKey( keyid );
784 if (note > -1) {
785 keyOff(note);
786 keyEvent->accept();
787 return;
788 }
789 }
790 keyEvent->ignore();
791}
792
800{
801 return QGraphicsScene::event(event);
802}
803
808{
809 foreach(PianoKey* key, d->m_keys) {
810 key->setPressed(false);
811 }
812}
813
820void PianoScene::setKeyPressedColor(const QColor& color)
821{
822 if (color.isValid()) {
823 d->m_hilightPalette = PianoPalette(PAL_SINGLE);
824 d->m_hilightPalette.setColor(0, color);
825 QBrush hilightBrush(color);
826 for (PianoKey *key : std::as_const(d->m_keys)) {
827 key->setPressedBrush(hilightBrush);
828 }
829 }
830}
831
836{
837 d->m_hilightPalette.resetColors();
838 QBrush hilightBrush(getKeyPressedColor());
839 for (PianoKey *key : std::as_const(d->m_keys)) {
840 key->setPressedBrush(hilightBrush);
841 }
842}
843
849{
850 return d->m_minNote;
851}
852
857{
858 for (PianoKey *key : std::as_const(d->m_keys)) {
859 int n = d->m_baseOctave*12 + key->getNote() + d->m_transpose;
860 bool b = !(n > d->m_maxNote) && !(n < d->m_minNote);
861 key->setVisible(b);
862 }
863}
864
869void PianoScene::setMinNote(const int note)
870{
871 if (d->m_minNote != note) {
872 d->m_minNote = note;
874 }
875}
876
882{
883 return d->m_maxNote;
884}
885
890void PianoScene::setMaxNote(const int note)
891{
892 if (d->m_maxNote != note) {
893 d->m_maxNote = note;
895 }
896}
897
903{
904 return d->m_transpose;
905}
906
911void PianoScene::setBaseOctave(const int base)
912{
913 if (d->m_baseOctave != base) {
914 d->m_baseOctave = base;
917 }
918}
919
925{
926 return d->m_numKeys;
927}
928
934{
935 return d->m_startKey;
936}
937
943bool PianoScene::isOctaveStart(const int note)
944{
945 return (note + d->m_transpose + 12) % 12 == 0;
946}
947
953QString PianoScene::noteName( PianoKey* key )
954{
955 Q_ASSERT(key != nullptr);
956 return d->noteName(key, true);
957}
958
963{
964 for (KeyLabel *lbl : std::as_const(d->m_labels)) {
965 PianoKey* key = dynamic_cast<PianoKey*>(lbl->parentItem());
966 if (key != nullptr) {
967 lbl->setVisible(false);
968 lbl->setFont(font());
969 lbl->setDefaultTextColor(d->m_foregroundPalette.getColor(key->isBlack() ? 1 : 0));
970 lbl->setOrientation(d->m_orientation);
971 lbl->setHtml(d->noteName(key, true));
972 lbl->adjust();
973 lbl->setVisible((d->m_showLabels == ShowAlways) ||
974 (d->m_showLabels == ShowMinimum && isOctaveStart(key->getNote())));
975 }
976 }
977}
978
983{
984 for (PianoKey *key : std::as_const(d->m_keys)) {
985 if (d->m_showColorScale && (d->m_backgroundPalette.paletteId() == PAL_SCALE)) {
986 int degree = key->getNote() % 12;
987 key->setBrush(d->m_backgroundPalette.getColor(degree));
988 } else {
989 key->setBrush(d->m_backgroundPalette.getColor(key->isBlack() ? 1 : 0));
990 }
991 key->setPressed(false);
992 }
993}
994
1001{
1002 //qDebug() << Q_FUNC_INFO << show;
1003 if (d->m_showLabels != show) {
1004 d->m_showLabels = show;
1005 refreshLabels();
1006 }
1007}
1008
1015{
1016 return d->m_alterations;
1017}
1018
1025{
1026 if (d->m_alterations != use) {
1027 d->m_alterations = use;
1028 refreshLabels();
1029 }
1030}
1031
1037{
1038 return d->m_octave;
1039}
1040
1046{
1047 if (d->m_orientation != orientation) {
1048 d->m_orientation = orientation;
1049 refreshLabels();
1050 }
1051}
1052
1053bool PianoScene::isKeyboardEnabled() const
1054{
1055 return d->m_keyboardEnabled;
1056}
1057
1058void PianoScene::setOctave(const LabelCentralOctave octave)
1059{
1060 if (d->m_octave != octave) {
1061 d->m_octave = octave;
1062 refreshLabels();
1063 }
1064}
1065
1066LabelOrientation PianoScene::getOrientation() const
1067{
1068 return d->m_orientation;
1069}
1070
1075void PianoScene::setTranspose(const int transpose)
1076{
1077 if (d->m_transpose != transpose && transpose > -12 && transpose < 12) {
1078 d->m_transpose = transpose;
1080 refreshLabels();
1081 }
1082}
1083
1090{
1091 return d->m_showLabels;
1092}
1093
1099{
1100 if (d->m_rawkbd != b) {
1101 d->m_rawkbd = b;
1102 }
1103}
1104
1110{
1111 return d->m_noteNames;
1112}
1113
1119{
1120 return d->m_names_s;
1121}
1122
1128{
1129 return d->m_velocity;
1130}
1131
1136void PianoScene::setVelocity(const int velocity)
1137{
1138 d->m_velocity = velocity;
1139}
1140
1147{
1148 return d->m_channel;
1149}
1150
1156void PianoScene::setChannel(const int channel)
1157{
1158 d->m_channel = channel;
1159}
1160
1165void PianoScene::useCustomNoteNames(const QStringList& names)
1166{
1167 //qDebug() << Q_FUNC_INFO << names;
1168 d->m_noteNames = names;
1169 refreshLabels();
1170}
1171
1176{
1177 //qDebug() << Q_FUNC_INFO;
1178 d->m_noteNames.clear();
1179 refreshLabels();
1180}
1181
1186void PianoScene::setKeyboardEnabled(const bool enable)
1187{
1188 if (enable != d->m_keyboardEnabled) {
1189 d->m_keyboardEnabled = enable;
1190 }
1191}
1192
1198{
1199 return d->m_mouseEnabled;
1200}
1201
1206void PianoScene::setMouseEnabled(const bool enable)
1207{
1208 if (enable != d->m_mouseEnabled) {
1209 d->m_mouseEnabled = enable;
1210 }
1211}
1212
1218{
1219 return d->m_touchEnabled;
1220}
1221
1226void PianoScene::setTouchEnabled(const bool enable)
1227{
1228 if (enable != d->m_touchEnabled) {
1229 d->m_touchEnabled = enable;
1230 }
1231}
1232
1238{
1239 return d->m_velocityTint;
1240}
1241
1246void PianoScene::setVelocityTint(const bool enable)
1247{
1248 //qDebug() << Q_FUNC_INFO << enable;
1249 d->m_velocityTint = enable;
1250}
1251
1256{
1257 d->m_names_s = QStringList{
1258 tr("C"),
1259 tr("C♯"),
1260 tr("D"),
1261 tr("D♯"),
1262 tr("E"),
1263 tr("F"),
1264 tr("F♯"),
1265 tr("G"),
1266 tr("G♯"),
1267 tr("A"),
1268 tr("A♯"),
1269 tr("B")};
1270 d->m_names_f = QStringList{
1271 tr("C"),
1272 tr("Dâ™­"),
1273 tr("D"),
1274 tr("Eâ™­"),
1275 tr("E"),
1276 tr("F"),
1277 tr("Gâ™­"),
1278 tr("G"),
1279 tr("Aâ™­"),
1280 tr("A"),
1281 tr("Bâ™­"),
1282 tr("B")};
1283 refreshLabels();
1284}
1285
1291{
1292 if (d->m_showColorScale != show) {
1293 d->m_showColorScale = show;
1294 refreshKeys();
1295 invalidate();
1296 }
1297}
1298
1304{
1305 return d->m_hilightPalette.getColor(0);
1306}
1307
1313{
1314 if (d->m_hilightPalette != p) {
1315 d->m_hilightPalette = p;
1316 refreshKeys();
1317 invalidate();
1318 }
1319}
1320
1326{
1327 return d->m_backgroundPalette;
1328}
1329
1335{
1336 if (d->m_backgroundPalette != p) {
1337 d->m_backgroundPalette = p;
1338 refreshKeys();
1339 invalidate();
1340 }
1341}
1342
1348{
1349 return d->m_foregroundPalette;
1350}
1351
1357{
1358 if (d->m_foregroundPalette != p) {
1359 d->m_foregroundPalette = p;
1360 refreshLabels();
1361 invalidate();
1362 }
1363}
1364
1370{
1371 return d->m_showColorScale;
1372}
1373
1374void PianoScene::setKeyPicture(const bool natural, const QPixmap &pix)
1375{
1376 d->m_keyPix[int(natural)] = pix;
1377 for (PianoKey *key : std::as_const(d->m_keys)) {
1378 if (key->isBlack() == !natural) {
1379 key->setPixmap(pix);
1380 }
1381 }
1382}
1383
1384QPixmap PianoScene::getKeyPicture(const bool natural)
1385{
1386 return d->m_keyPix[int(natural)];
1387}
1388
1389void PianoScene::setUseKeyPictures(const bool enable)
1390{
1391 d->m_useKeyPix = enable;
1392 for (PianoKey *key : std::as_const(d->m_keys)) {
1393 key->setUsePixmap(enable);
1394 }
1395}
1396
1397bool PianoScene::getUseKeyPictures() const
1398{
1399 return d->m_useKeyPix;
1400}
1401
1402void PianoScene::saveData(QByteArray &ba)
1403{
1404 d->saveData(ba);
1405}
1406
1407void PianoScene::loadData(QByteArray &ba)
1408{
1409 d->loadData(ba);
1410}
1411
1417bool PianoScene::touchScreenEvent(QTouchEvent *touchEvent)
1418{
1419 switch(touchEvent->type()) {
1420 case QEvent::TouchEnd:
1421 case QEvent::TouchCancel:
1422 {
1423 foreach(PianoKey *key, d->m_touched) {
1424 //qDebug() << "key:" << key->getNote() << key->isPressed();
1425 if (key->isPressed()) {
1426 keyOff(key);
1427 }
1428 }
1429 d->m_touched.clear();
1430 touchEvent->accept();
1431 return true;
1432 } /* case (end and cancel touch events) */
1433 case QEvent::TouchBegin:
1434 case QEvent::TouchUpdate:
1435 {
1436 QList<QTouchEvent::TouchPoint> touchPoints =
1437 #if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
1438 touchEvent->touchPoints();
1439 #else
1440 touchEvent->points();
1441 #endif
1442 bool hasPressure =
1443 #if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
1444 touchEvent->device()->capabilities().testFlag(QTouchDevice::Pressure);
1445 #else
1446 touchEvent->device()->capabilities().testFlag(QInputDevice::Capability::Pressure);
1447 #endif
1448 foreach(const QTouchEvent::TouchPoint& touchPoint, touchPoints) {
1449 //qDebug() << touchPoint.id() << touchPoint.state();
1450 switch (touchPoint.state()) {
1451#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
1452 case Qt::TouchPointReleased:
1453#else
1454 case QEventPoint::Released:
1455#endif
1456 {
1457 PianoKey* key = d->m_touched.value(touchPoint.id());
1458 if (key != nullptr) {
1459 //qDebug() << "key:" << key->getNote() << key->isPressed();
1460 if (key->isPressed()) {
1461 if (hasPressure) {
1462 keyOff(key, touchPoint.pressure());
1463 } else {
1464 keyOff(key);
1465 }
1466 }
1467 d->m_touched.remove(touchPoint.id());
1468 }
1469 break;
1470 } /* case released state */
1471#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
1472 case Qt::TouchPointPressed:
1473#else
1474 case QEventPoint::Pressed:
1475#endif
1476 {
1477 PianoKey* key = getKeyForPos( d->m_view->mapToScene(
1478 #if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
1479 touchPoint.pos().toPoint()
1480 #else
1481 touchPoint.position().toPoint()
1482 #endif
1483 ));
1484 if (key != nullptr) {
1485 //qDebug() << "key:" << key->getNote() << key->isPressed();
1486 if (!key->isPressed()) {
1487 if (hasPressure) {
1488 keyOn(key, touchPoint.pressure());
1489 } else {
1490 keyOn(key);
1491 }
1492 key->ensureVisible();
1493 }
1494 d->m_touched[touchPoint.id()] = key;
1495 }
1496 break;
1497 } /* case pressed state */
1498#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
1499 case Qt::TouchPointMoved:
1500#else
1501 case QEventPoint::Updated:
1502#endif
1503 {
1504 PianoKey* key = getKeyForPos( d->m_view->mapToScene(
1505 #if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
1506 touchPoint.pos().toPoint()
1507 #else
1508 touchPoint.position().toPoint()
1509 #endif
1510 ));
1511 PianoKey* lastkey = d->m_touched.value(touchPoint.id());
1512 if ((lastkey != nullptr) && (lastkey != key)) {
1513 //qDebug() << "lastkey:" << lastkey->getNote() << lastkey->isPressed();
1514 if (lastkey->isPressed()) {
1515 if (hasPressure) {
1516 keyOff(lastkey, touchPoint.pressure());
1517 } else {
1518 keyOff(lastkey);
1519 }
1520 }
1521 d->m_touched.remove(touchPoint.id());
1522 }
1523 if (key != nullptr) {
1524 //qDebug() << "key:" << key->getNote() << key->isPressed();
1525 if (!key->isPressed()) {
1526 if (hasPressure) {
1527 keyOn(key, touchPoint.pressure());
1528 } else {
1529 keyOn(key);
1530 }
1531 }
1532 d->m_touched[touchPoint.id()] = key;
1533 }
1534 break;
1535 } /* case updated state */
1536 default:
1537 break;
1538 } /* switch touchpoint state */
1539 } /* foreach touchPoint */
1540 touchEvent->accept();
1541 return true;
1542 } /* case (begin and update touch events) */
1543 default:
1544 break;
1545 } /* switch touchEvent->type() */
1546 return false;
1547}
1548
1553void PianoScene::setUsingNativeFilter(const bool newState)
1554{
1555 if (newState != d->m_usingNativeFilter) {
1556 d->m_usingNativeFilter = newState;
1557 }
1558}
1559
1565{
1566 return d->m_usingNativeFilter;
1567}
1568
1573void PianoScene::setOctaveSubscript(const bool enable)
1574{
1575 if (d->m_octaveSubscript != enable) {
1576 d->m_octaveSubscript = enable;
1577 refreshLabels();
1578 }
1579}
1580
1586{
1587 return d->m_octaveSubscript;
1588}
1589
1590} // namespace widgets
1591} // namespace drumstick
The QEvent class is the base class of all event classes.
The QGraphicsScene class provides a surface for managing a large number of 2D graphical items.
The QObject class is the base class of all Qt objects.
The PianoHandler class callbacks.
Definition: pianokeybd.h:84
The PianoKeybd class.
Definition: pianokeybd.h:176
The PianoPalette class.
Definition: pianopalette.h:71
void allKeysOff()
Deactivates all keys.
Definition: pianoscene.cpp:807
void triggerNoteOn(const int note, const int vel)
Performs a Note On MIDI event for the given MIDI note number and velocity.
Definition: pianoscene.cpp:492
void resetKeyPressedColor()
Assigns the default highlight palette colors and assigns it to the scene.
Definition: pianoscene.cpp:835
void keyOff(const int note)
Produces a MIDI Note Off event and deactivates the corresponding key for the given MIDI note number.
Definition: pianoscene.cpp:619
bool octaveSubscript() const
Returns whether the subscript octave designation is enabled.
void showKeyOff(PianoKey *key, int vel)
Displays as deactivated a key.
Definition: pianoscene.cpp:423
void setBackgroundPalette(const PianoPalette &p)
Assigns the active background palette.
void setKeyPressedColor(const QColor &color)
Assigns a single color for key highlight.
Definition: pianoscene.cpp:820
void setRawKeyboardMode(const bool b)
Assigns the low level computer keyboard mode.
void keyOn(const int note)
Produces a MIDI Note On event and highlights the corresponding key for the given MIDI note number.
Definition: pianoscene.cpp:607
void useStandardNoteNames()
Assigns the standard note names, clearing the list of custom note names.
void hideOrShowKeys()
Hides or shows keys.
Definition: pianoscene.cpp:856
LabelCentralOctave getOctave() const
Returns the central octave name policy.
PianoScene(const int baseOctave, const int numKeys, const int startKey, const QColor &keyPressedColor=QColor(), QObject *parent=nullptr)
Constructor.
Definition: pianoscene.cpp:253
bool event(QEvent *event) override
This method overrides QGraphicsScene::event().
Definition: pianoscene.cpp:799
int baseOctave() const
Returns the base octave number.
Definition: pianoscene.cpp:483
PianoPalette getForegroundPalette()
Returns the active foreground palette.
void setHighlightPalette(const PianoPalette &p)
Assigns the active highlight palette.
void setShowColorScale(const bool show)
Enables or disables the color scale key background mode.
void setPianoHandler(PianoHandler *handler)
Assigns a PianoHandler pointer for processing note events.
Definition: pianoscene.cpp:356
void setKeyboardMap(KeyboardMap *map)
Assigns the computer keyboard note map.
Definition: pianoscene.cpp:322
void noteOff(int n, int v)
This signal is emitted for each Note Off MIDI event created using the computer keyboard,...
void setVelocity(const int velocity)
Assigns the MIDI note velocity parameter that is assigned to the MIDI OUT notes.
void setMinNote(const int note)
Assigns the minimum MIDI note number that will be displayed.
Definition: pianoscene.cpp:869
bool showColorScale() const
Returns whether the color scale mode is enabled.
void setBaseOctave(const int base)
Assigns the octave base number.
Definition: pianoscene.cpp:911
PianoKey * getKeyForPos(const QPointF &p) const
Returns the piano key for the given scene point coordenates.
Definition: pianoscene.cpp:641
void signalName(const QString &name)
signalName is emitted for each note created, and contains a string with the MIDI note number and the ...
int numKeys() const
Returns the number of keys that will be displayed.
Definition: pianoscene.cpp:924
PianoPalette getHighlightPalette()
Returns the palette used for highlighting the played keys.
Definition: pianoscene.cpp:365
void setKeyboardEnabled(const bool enable)
Enables or disables the computer keyboard note generation.
void mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent) override
This event handler, for event mouseEvent, is reimplemented to receive mouse move events for the scene...
Definition: pianoscene.cpp:657
bool isUsingNativeFilter() const
Returns whether the application is filtering native events.
void triggerNoteOff(const int note, const int vel)
Performs a Note Off MIDI event for the given MIDI note number and velocity.
Definition: pianoscene.cpp:511
PianoKey * getPianoKey(const int key) const
Returns the piano key object corresponding to the given computer keyboard key.
Definition: pianoscene.cpp:731
int getVelocity()
Returns the MIDI note velocity parameter that is assigned to the MIDI OUT notes.
int getChannel() const
Returns the MIDI channel that is assigned to the output events, or used to filter the input events (u...
void setForegroundPalette(const PianoPalette &p)
Assigns the active foreground palette.
void keyPressEvent(QKeyEvent *keyEvent) override
This event handler, for event keyEvent, is reimplemented to receive keypress events.
Definition: pianoscene.cpp:743
void setVelocityTint(const bool enable)
Enables or disables the velocity parameter of note events to influence the highlight key colors.
bool touchScreenEvent(QTouchEvent *touchEvent)
Process touch screen events, called by the view.
bool velocityTint() const
Returns whether the velocity parameter of note events is used to influence the highlight key colors.
void setUsingNativeFilter(const bool newState)
Enables or disables the application level usage of a native event filter.
QColor getKeyPressedColor() const
Returns the single highlight palette color.
int getNoteFromKey(const int key) const
Returns the note number for the given computer keyboard key code.
Definition: pianoscene.cpp:714
void refreshLabels()
Refresh the visibility and other attributes of the labels shown over the piano keys.
Definition: pianoscene.cpp:962
void showNoteOff(const int note, int vel=-1)
Displays deactivated the corresponding key for a given MIDI note, with MIDI velocity.
Definition: pianoscene.cpp:470
void setShowLabels(const LabelVisibility show)
Assigns the label visibility policy to the piano keys.
void refreshKeys()
Refresh the background colors of all the piano keys.
Definition: pianoscene.cpp:982
QSize sizeHint() const
Returns the calculated size of the scene.
Definition: pianoscene.cpp:313
bool isOctaveStart(const int note)
Returns whether the given note number is a octave startup note.
Definition: pianoscene.cpp:943
void setAlterations(const LabelAlteration use)
Assigns the alterations name policy.
PianoPalette getBackgroundPalette()
Returns the background palette.
QStringList standardNoteNames() const
Returns the standard note names list.
void mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent) override
This event handler, for event mouseEvent, is reimplemented to receive mouse press events for the scen...
Definition: pianoscene.cpp:679
void setTranspose(const int transpose)
Assigns the transpose amount in semitones.
int getMaxNote() const
Returns the maximum MIDI note number that will be displayed.
Definition: pianoscene.cpp:881
LabelAlteration alterations() const
Returns the alterations name policy.
void setHighlightColorFromPolicy(PianoKey *key, const int vel)
Assigns to the given key the highlight color from the active highlight palette and the given MIDI vel...
Definition: pianoscene.cpp:529
PianoHandler * getPianoHandler() const
Gets the PianoHandler pointer to the note receiver.
Definition: pianoscene.cpp:343
void showKeyOn(PianoKey *key, QColor color, int vel)
Displays highlighted the activated key with the supplied color and note velocity.
Definition: pianoscene.cpp:395
KeyboardMap * getKeyboardMap() const
Returns the computer keyboard note map.
Definition: pianoscene.cpp:331
bool isMouseEnabled() const
Returns whether the computer keyboard note generation is enabled.
bool getRawKeyboardMode() const
Returns whether the low level computer keyboard mode is enabled.
Definition: pianoscene.cpp:631
void noteOn(int n, int v)
This signal is emitted for each Note On MIDI event created using the computer keyboard,...
void showNoteOn(const int note, QColor color, int vel=-1)
Displays highlighted the corresponding key for a given MIDI note, with a color and MIDI velocity.
Definition: pianoscene.cpp:443
void keyReleaseEvent(QKeyEvent *keyEvent) override
This event handler, for event keyEvent, is reimplemented to receive key release events.
Definition: pianoscene.cpp:770
void setMaxNote(const int note)
Assigns the maximum MIDI note number that will be displayed.
Definition: pianoscene.cpp:890
void retranslate()
Retranslates the standard note names.
int startKey() const
Returns the first key number that will be displayed.
Definition: pianoscene.cpp:933
void mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent) override
This event handler, for event mouseEvent, is reimplemented to receive mouse release events for the sc...
Definition: pianoscene.cpp:696
void setTouchEnabled(const bool enable)
Enables or disables the touch screen note generation.
void displayKeyOn(PianoKey *key)
Displays the note label over a highligted key.
Definition: pianoscene.cpp:374
void useCustomNoteNames(const QStringList &names)
Assigns the list of custom note names, and enables this mode.
void setMouseEnabled(const bool enable)
Enables or disables the mouse note generation.
void setChannel(const int channel)
Assigns the MIDI channel that is included into the output events, or used to filter the input events ...
int getMinNote() const
Returns the minimum MIDI note number that will be displayed.
Definition: pianoscene.cpp:848
void setOrientation(const LabelOrientation orientation)
Assigns the label orientation policy.
QStringList customNoteNames() const
Returns the custom note names list.
LabelVisibility showLabels() const
Returns the label visibility policy (display note names over the piano keys).
void setOctaveSubscript(const bool enable)
Enables or disables the subscript octave designation.
bool isTouchEnabled() const
Returns whether the touch screen note generation is enabled.
int getTranspose() const
Returns the transpose amount in semitones.
Definition: pianoscene.cpp:902
QString noteName(PianoKey *key)
Returns the note name string that will be displayed over a given piano key.
Definition: pianoscene.cpp:953
LabelAlteration
Labels for Alterations.
Definition: pianokeybd.h:131
LabelCentralOctave
Labels Central Octave.
Definition: pianokeybd.h:161
LabelVisibility
Labels Visibility.
Definition: pianokeybd.h:120
LabelOrientation
Labels Orientation.
Definition: pianokeybd.h:141
QHash< int, int > KeyboardMap
KeyboardMap.
Definition: pianokeybd.h:108
@ ShowSharps
Show sharps on black keys.
Definition: pianokeybd.h:132
@ ShowNothing
Do not show names on black keys.
Definition: pianokeybd.h:134
@ ShowFlats
Show flats on black keys.
Definition: pianokeybd.h:133
@ OctaveNothing
Don't show octave numbers.
Definition: pianokeybd.h:162
@ OctaveC4
Central C, MIDI note #60 is C4.
Definition: pianokeybd.h:164
@ ShowAlways
Show always note names.
Definition: pianokeybd.h:124
@ ShowMinimum
Show only note C names.
Definition: pianokeybd.h:122
@ ShowActivated
Show names when notes are activated.
Definition: pianokeybd.h:123
@ ShowNever
Don't show note names.
Definition: pianokeybd.h:121
@ HorizontalOrientation
Show horizontal names.
Definition: pianokeybd.h:142
@ PAL_SCALE
Background colors for each chromatic scale note.
Definition: pianopalette.h:59
@ PAL_SINGLE
Single highlihgting color for all keys.
Definition: pianopalette.h:56
@ PAL_HISCALE
Highlighting colors for each chromatic scale note.
Definition: pianopalette.h:62
@ PAL_CHANNELS
Different highlihgting colors for each channel.
Definition: pianopalette.h:58
@ PAL_KEYS
Two background colors (naturals/alterations)
Definition: pianopalette.h:60
@ PAL_DOUBLE
Two highlihgting colors (naturals/alterations)
Definition: pianopalette.h:57
@ PAL_FONT
Foreground font colors for names.
Definition: pianopalette.h:61
Drumstick common.
Definition: alsaclient.cpp:68
Piano Keyboard Widget.
PianoScene class declaration.