drumstick 2.6.1
pianoscene.cpp
Go to the documentation of this file.
1/*
2 Virtual Piano Widget for Qt5
3 Copyright (C) 2008-2022, 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 { }
82
83 void saveData(QByteArray& buffer)
84 {
85 QDataStream ds(&buffer, QIODevice::WriteOnly);
86 ds << m_minNote;
87 ds << m_maxNote;
88 ds << m_transpose;
89 ds << m_showLabels;
90 ds << m_alterations;
91 ds << m_octave;
92 ds << m_orientation;
93 ds << m_rawkbd;
94 ds << m_keyboardEnabled;
95 ds << m_mouseEnabled;
96 ds << m_touchEnabled;
97 ds << m_mousePressed;
98 ds << m_velocity;
99 ds << m_channel;
100 ds << m_velocityTint;
101 ds << m_noteNames;
102 ds << m_names_s;
103 ds << m_names_f;
104 ds << m_showColorScale;
105 ds << m_hilightPalette;
106 ds << m_backgroundPalette;
107 ds << m_foregroundPalette;
108 ds << m_useKeyPix;
109 ds << m_keyPix[0];
110 ds << m_keyPix[1];
111 ds << m_usingNativeFilter;
112 }
113
114 void loadData(QByteArray& buffer)
115 {
116 quint32 u;
117 QDataStream ds(&buffer, QIODevice::ReadOnly);
118 ds >> m_minNote;
119 ds >> m_maxNote;
120 ds >> m_transpose;
121 ds >> u; m_showLabels = LabelVisibility(u);
122 ds >> u; m_alterations = LabelAlteration(u);
123 ds >> u; m_octave = LabelCentralOctave(u);
124 ds >> u; m_orientation = LabelOrientation(u);
125 ds >> m_rawkbd;
126 ds >> m_keyboardEnabled;
127 ds >> m_mouseEnabled;
128 ds >> m_touchEnabled;
129 ds >> m_mousePressed;
130 ds >> m_velocity;
131 ds >> m_channel;
132 ds >> m_velocityTint;
133 ds >> m_noteNames;
134 ds >> m_names_s;
135 ds >> m_names_f;
136 ds >> m_showColorScale;
137 ds >> m_hilightPalette;
138 ds >> m_backgroundPalette;
139 ds >> m_foregroundPalette;
140 ds >> m_useKeyPix;
141 ds >> m_keyPix[0];
142 ds >> m_keyPix[1];
143 ds >> m_usingNativeFilter;
144 }
145
146 int m_baseOctave;
147 int m_numKeys;
148 int m_startKey;
149 int m_minNote;
150 int m_maxNote;
151 int m_transpose;
152 LabelVisibility m_showLabels;
153 LabelAlteration m_alterations;
154 LabelCentralOctave m_octave;
155 LabelOrientation m_orientation;
156 bool m_rawkbd;
157 bool m_keyboardEnabled;
158 bool m_mouseEnabled;
159 bool m_touchEnabled;
160 bool m_mousePressed;
161 int m_velocity;
162 int m_channel;
163 bool m_velocityTint;
164 PianoHandler *m_handler;
165 KeyboardMap *m_keybdMap;
166 QHash<int, PianoKey *> m_keys;
167 QMap<int, KeyLabel *> m_labels;
168 QStringList m_noteNames;
169 QStringList m_names_s;
170 QStringList m_names_f;
171 bool m_showColorScale;
172 PianoPalette m_hilightPalette;
173 PianoPalette m_backgroundPalette;
174 PianoPalette m_foregroundPalette;
175 bool m_useKeyPix;
176 QPixmap m_keyPix[2];
177 bool m_usingNativeFilter;
178 /* not serialized */
179 PianoKeybd* m_view;
180 QMap<int, PianoKey *> m_touched;
181};
182
183const int KEYWIDTH = 180;
184const int KEYHEIGHT = 720;
185
186static qreal sceneWidth(int keys) {
187 return KEYWIDTH * qCeil( keys * 7.0 / 12.0 );
188}
189
198PianoScene::PianoScene ( const int baseOctave,
199 const int numKeys,
200 const int startKey,
201 const QColor& keyPressedColor,
202 QObject * parent )
203 : QGraphicsScene( QRectF(0, 0, sceneWidth(numKeys), KEYHEIGHT), parent ),
204 d(new PianoScenePrivate(baseOctave, numKeys, startKey))
205{
206 if (keyPressedColor.isValid()) {
207 setKeyPressedColor(keyPressedColor);
208 }
209 QBrush hilightBrush(getKeyPressedColor());
210 d->m_view = dynamic_cast<PianoKeybd*>(parent);
211 if (d->m_view != nullptr) {
212 setFont(d->m_view->font());
213 }
214 int upperLimit = d->m_numKeys + d->m_startKey;
215 int adj = d->m_startKey % 12;
216 if (adj >= 5) adj++;
217 for(int i = d->m_startKey; i < upperLimit; ++i)
218 {
219 float x = 0;
220 PianoKey* key = nullptr;
221 KeyLabel* lbl = nullptr;
222 int ocs = i / 12 * 7;
223 int j = i % 12;
224 if (j >= 5) j++;
225 if ((j % 2) == 0) {
226 x = (ocs + qFloor((j-adj) / 2.0)) * KEYWIDTH;
227 key = new PianoKey( QRectF(x, 0, KEYWIDTH, KEYHEIGHT), false, i );
228 lbl = new KeyLabel(key);
229 lbl->setDefaultTextColor(d->m_foregroundPalette.getColor(0));
230 } else {
231 x = (ocs + qFloor((j-adj) / 2.0)) * KEYWIDTH + KEYWIDTH * 0.6 + 1;
232 key = new PianoKey( QRectF( x, 0, KEYWIDTH * 0.8 - 1, KEYHEIGHT * 0.6 ), true, i );
233 key->setZValue( 1 );
234 lbl = new KeyLabel(key);
235 lbl->setDefaultTextColor(d->m_foregroundPalette.getColor(1));
236 }
237 addItem( key );
238 lbl->setFont(font());
239 key->setAcceptTouchEvents(true);
240 key->setPressedBrush(hilightBrush);
241 d->m_keys.insert(i, key);
242 d->m_labels.insert(i, lbl);
243 }
245 retranslate();
246}
247
252{ }
253
259{
260 return {static_cast<int>(sceneWidth(d->m_numKeys)), KEYHEIGHT};
261}
262
268{
269 d->m_keybdMap = map;
270}
271
277{
278 return d->m_keybdMap;
279}
280
289{
290 return d->m_handler;
291}
292
302{
303 d->m_handler = handler;
304}
305
311{
312 return d->m_hilightPalette;
313}
314
319void PianoScene::displayKeyOn(PianoKey* key)
320{
321 key->setPressed(true);
322 int n = key->getNote() + d->m_baseOctave*12 + d->m_transpose;
323 QString s = QString("#%1 (%2)").arg(n).arg(noteName(key));
324 emit signalName(s);
325 KeyLabel* lbl = dynamic_cast<KeyLabel*>(key->childItems().constFirst());
326 if (lbl != nullptr) {
327 lbl->setDefaultTextColor(d->m_foregroundPalette.getColor(key->isBlack() ? 3 : 2));
328 if (d->m_showLabels == ShowActivated) {
329 lbl->setVisible(true);
330 }
331 }
332}
333
340void PianoScene::showKeyOn( PianoKey* key, QColor color, int vel )
341{
342 //qDebug() << Q_FUNC_INFO << key->getNote() << vel << color << d->m_velocityTint;
343 if (d->m_velocityTint && (vel >= 0) && (vel < 128) && color.isValid() ) {
344 QBrush hilightBrush(color.lighter(200 - vel));
345 key->setPressedBrush(hilightBrush);
346 } else if (color.isValid()) {
347 key->setPressedBrush(color);
348 }
349 displayKeyOn(key);
350}
351
357void PianoScene::showKeyOn( PianoKey* key, int vel )
358{
360 displayKeyOn(key);
361}
362
368void PianoScene::showKeyOff( PianoKey* key, int vel)
369{
370 Q_UNUSED(vel)
371 key->setPressed(false);
372 emit signalName(QString());
373 KeyLabel* lbl = dynamic_cast<KeyLabel*>(key->childItems().constFirst());
374 if (lbl != nullptr) {
375 lbl->restoreColor();
376 if (d->m_showLabels == ShowActivated) {
377 lbl->setVisible(false);
378 }
379 }
380}
381
388void PianoScene::showNoteOn( const int note, QColor color, int vel )
389{
390 //qDebug() << Q_FUNC_INFO << note << vel << color;
391 int n = note - d->m_baseOctave*12 - d->m_transpose;
392 if ((note >= d->m_minNote) && (note <= d->m_maxNote) && d->m_keys.contains(n) && color.isValid())
393 showKeyOn(d->m_keys.value(n), color, vel);
394}
395
401void PianoScene::showNoteOn( const int note, int vel )
402{
403 //qDebug() << Q_FUNC_INFO << note << vel;
404 int n = note - d->m_baseOctave*12 - d->m_transpose;
405 if ((note >= d->m_minNote) && (note <= d->m_maxNote) && d->m_keys.contains(n)) {
406 showKeyOn(d->m_keys.value(n), vel);
407 }
408}
409
415void PianoScene::showNoteOff( const int note, int vel )
416{
417 int n = note - d->m_baseOctave*12 - d->m_transpose;
418 if ((note >= d->m_minNote) && (note <= d->m_maxNote) && d->m_keys.contains(n)) {
419 showKeyOff(d->m_keys.value(n), vel);
420 }
421}
422
428int PianoScene::baseOctave() const { return d->m_baseOctave; }
429
437void PianoScene::triggerNoteOn( const int note, const int vel )
438{
439 int n = d->m_baseOctave*12 + note + d->m_transpose;
440 if ((n >= d->m_minNote) && (n <= d->m_maxNote)) {
441 if (d->m_handler != nullptr) {
442 d->m_handler->noteOn(n, vel);
443 } else {
444 emit noteOn(n, vel);
445 }
446 }
447}
448
456void PianoScene::triggerNoteOff( const int note, const int vel )
457{
458 int n = d->m_baseOctave*12 + note + d->m_transpose;
459 if ((n >= d->m_minNote) && (n <= d->m_maxNote)) {
460 if (d->m_handler != nullptr) {
461 d->m_handler->noteOff(n, vel);
462 } else {
463 emit noteOff(n, vel);
464 }
465 }
466}
467
474void PianoScene::setHighlightColorFromPolicy(PianoKey* key, int vel)
475{
476 QColor c;
477 //qDebug() << Q_FUNC_INFO << key->getNote() << vel << d->m_velocityTint;
478 switch (d->m_hilightPalette.paletteId()) {
479 case PAL_SINGLE:
480 c = d->m_hilightPalette.getColor(0);
481 break;
482 case PAL_DOUBLE:
483 c = d->m_hilightPalette.getColor(key->getType());
484 break;
485 case PAL_CHANNELS:
486 c = d->m_hilightPalette.getColor(d->m_channel);
487 break;
488 case PAL_HISCALE:
489 c = d->m_hilightPalette.getColor(key->getDegree());
490 break;
491 default:
492 return;
493 }
494 if (c.isValid()) {
495 if (d->m_velocityTint && (vel >= 0) && (vel < 128)) {
496 QBrush h(c.lighter(200 - vel));
497 key->setPressedBrush(h);
498 } else {
499 key->setPressedBrush(c);
500 }
501 }
502}
503
508void PianoScene::keyOn( PianoKey* key )
509{
510 triggerNoteOn(key->getNote(), d->m_velocity);
511 showKeyOn(key, d->m_velocity);
512}
513
518void PianoScene::keyOff( PianoKey* key )
519{
520 triggerNoteOff(key->getNote(), 0);
521 showKeyOff(key, 0);
522}
523
529void PianoScene::keyOn( PianoKey* key, qreal pressure )
530{
531 int vel = d->m_velocity * pressure;
532 triggerNoteOn(key->getNote(), vel);
533 showKeyOn(key, vel);
534}
535
541void PianoScene::keyOff( PianoKey* key, qreal pressure )
542{
543 int vel = d->m_velocity * pressure;
544 triggerNoteOff(key->getNote(), vel);
545 showKeyOff(key, vel);
546}
547
552void PianoScene::keyOn(const int note)
553{
554 if (d->m_keys.contains(note))
555 keyOn(d->m_keys.value(note));
556 else
557 triggerNoteOn(note, d->m_velocity);
558}
559
564void PianoScene::keyOff(const int note)
565{
566 if (d->m_keys.contains(note))
567 keyOff(d->m_keys.value(note));
568 else
569 triggerNoteOff(note, d->m_velocity);
570}
571
577{
578 return d->m_rawkbd;
579}
580
586PianoKey* PianoScene::getKeyForPos( const QPointF& p ) const
587{
588 PianoKey* key = nullptr;
589 QList<QGraphicsItem *> ptitems = this->items(p, Qt::IntersectsItemShape, Qt::DescendingOrder);
590 foreach(QGraphicsItem *itm, ptitems) {
591 key = dynamic_cast<PianoKey*>(itm);
592 if (key != nullptr)
593 break;
594 }
595 return key;
596}
597
602void PianoScene::mouseMoveEvent ( QGraphicsSceneMouseEvent * mouseEvent )
603{
604 if (d->m_mouseEnabled && (mouseEvent->source() == Qt::MouseEventNotSynthesized)) {
605 if (d->m_mousePressed) {
606 PianoKey* key = getKeyForPos(mouseEvent->scenePos());
607 PianoKey* lastkey = getKeyForPos(mouseEvent->lastScenePos());
608 if ((lastkey != nullptr) && (lastkey != key) && lastkey->isPressed()) {
609 keyOff(lastkey);
610 }
611 if ((key != nullptr) && !key->isPressed()) {
612 keyOn(key);
613 }
614 mouseEvent->accept();
615 return;
616 }
617 }
618}
619
624void PianoScene::mousePressEvent ( QGraphicsSceneMouseEvent * mouseEvent )
625{
626 if (d->m_mouseEnabled && (mouseEvent->source() == Qt::MouseEventNotSynthesized)) {
627 PianoKey* key = getKeyForPos(mouseEvent->scenePos());
628 if (key != nullptr && !key->isPressed()) {
629 keyOn(key);
630 d->m_mousePressed = true;
631 mouseEvent->accept();
632 return;
633 }
634 }
635}
636
641void PianoScene::mouseReleaseEvent ( QGraphicsSceneMouseEvent * mouseEvent )
642{
643 if (d->m_mouseEnabled && (mouseEvent->source() == Qt::MouseEventNotSynthesized)) {
644 d->m_mousePressed = false;
645 PianoKey* key = getKeyForPos(mouseEvent->scenePos());
646 if (key != nullptr && key->isPressed()) {
647 keyOff(key);
648 mouseEvent->accept();
649 return;
650 }
651 }
652}
653
659int PianoScene::getNoteFromKey( const int key ) const
660{
661 if (d->m_keybdMap != nullptr) {
662 KeyboardMap::ConstIterator it = d->m_keybdMap->constFind(key);
663 if ((it != d->m_keybdMap->constEnd()) && (it.key() == key)) {
664 int note = it.value();
665 return note;
666 }
667 }
668 return -1;
669}
670
676PianoKey* PianoScene::getPianoKey( const int key ) const
677{
678 int note = getNoteFromKey(key);
679 if (d->m_keys.contains(note))
680 return d->m_keys.value(note);
681 return nullptr;
682}
683
688void PianoScene::keyPressEvent ( QKeyEvent * keyEvent )
689{
690 if ( d->m_keyboardEnabled &&
691 !d->m_usingNativeFilter &&
692 !keyEvent->isAutoRepeat() ) // ignore auto-repeats
693 {
694 int keyid = d->m_rawkbd ?
695#if defined(Q_OS_MACOS)
696 keyEvent->nativeVirtualKey()
697#else
698 keyEvent->nativeScanCode()
699#endif
700 : keyEvent->key();
701 int note = getNoteFromKey( keyid );
702 if (note > -1) {
703 keyOn(note);
704 keyEvent->accept();
705 return;
706 }
707 }
708 keyEvent->ignore();
709}
710
715void PianoScene::keyReleaseEvent ( QKeyEvent * keyEvent )
716{
717 if ( d->m_keyboardEnabled &&
718 !d->m_usingNativeFilter &&
719 !keyEvent->isAutoRepeat() ) // ignore auto-repeats
720 {
721 int keyid = d->m_rawkbd ?
722#if defined(Q_OS_MACOS)
723 keyEvent->nativeVirtualKey()
724#else
725 keyEvent->nativeScanCode()
726#endif
727 : keyEvent->key();
728 int note = getNoteFromKey( keyid );
729 if (note > -1) {
730 keyOff(note);
731 keyEvent->accept();
732 return;
733 }
734 }
735 keyEvent->ignore();
736}
737
745{
746 return QGraphicsScene::event(event);
747}
748
753{
754 foreach(PianoKey* key, d->m_keys) {
755 key->setPressed(false);
756 }
757}
758
765void PianoScene::setKeyPressedColor(const QColor& color)
766{
767 if (color.isValid()) {
768 d->m_hilightPalette = PianoPalette(PAL_SINGLE);
769 d->m_hilightPalette.setColor(0, color);
770 QBrush hilightBrush(color);
771 for (PianoKey* key : qAsConst(d->m_keys)) {
772 key->setPressedBrush(hilightBrush);
773 }
774 }
775}
776
781{
782 d->m_hilightPalette.resetColors();
783 QBrush hilightBrush(getKeyPressedColor());
784 for (PianoKey* key : qAsConst(d->m_keys)) {
785 key->setPressedBrush(hilightBrush);
786 }
787}
788
794{
795 return d->m_minNote;
796}
797
802{
803 for (PianoKey* key : qAsConst(d->m_keys)) {
804 int n = d->m_baseOctave*12 + key->getNote() + d->m_transpose;
805 bool b = !(n > d->m_maxNote) && !(n < d->m_minNote);
806 key->setVisible(b);
807 }
808}
809
814void PianoScene::setMinNote(const int note)
815{
816 if (d->m_minNote != note) {
817 d->m_minNote = note;
819 }
820}
821
827{
828 return d->m_maxNote;
829}
830
835void PianoScene::setMaxNote(const int note)
836{
837 if (d->m_maxNote != note) {
838 d->m_maxNote = note;
840 }
841}
842
848{
849 return d->m_transpose;
850}
851
856void PianoScene::setBaseOctave(const int base)
857{
858 if (d->m_baseOctave != base) {
859 d->m_baseOctave = base;
862 }
863}
864
870{
871 return d->m_numKeys;
872}
873
879{
880 return d->m_startKey;
881}
882
888bool PianoScene::isOctaveStart(const int note)
889{
890 return (note + d->m_transpose + 12) % 12 == 0;
891}
892
898QString PianoScene::noteName( PianoKey* key )
899{
900 Q_ASSERT(key != nullptr);
901 int note = key->getNote();
902 int num = (note + d->m_transpose + 12) % 12;
903 int adj = ((note + d->m_transpose < 0) ? 2 : 1) - d->m_octave + 1;
904 int oct = d->m_baseOctave + ((note + d->m_transpose) / 12) - adj;
905 if (d->m_noteNames.isEmpty()) {
906 QString name;
907 if (!d->m_names_f.isEmpty() && !d->m_names_s.isEmpty()) {
908 switch(d->m_alterations) {
909 case ShowFlats:
910 name = d->m_names_f.value(num);
911 break;
912 case ShowSharps:
913 name = d->m_names_s.value(num);
914 break;
915 case ShowNothing:
916 if (key->isBlack()) {
917 return QString();
918 }
919 name = d->m_names_s.value(num);
920 break;
921 default:
922 break;
923 }
924 }
925 if (d->m_octave==OctaveNothing) {
926 return name;
927 } else {
928 return QString("%1%2").arg(name).arg(oct);
929 }
930 } else {
931 if (d->m_noteNames.length() == 128) {
932 int n = d->m_baseOctave*12 + note + d->m_transpose;
933 //qDebug() << Q_FUNC_INFO << n << note;
934 if (n >= 0 && n < d->m_noteNames.length()) {
935 return d->m_noteNames.value(n);
936 }
937 } else if (d->m_noteNames.length() >= 12) {
938 if (d->m_octave==OctaveNothing) {
939 return d->m_noteNames.value(num);
940 } else {
941 return QString("%1%2").arg(d->m_noteNames.value(num)).arg(oct);
942 }
943 }
944 return QString();
945 }
946}
947
952{
953 for (KeyLabel* lbl : qAsConst(d->m_labels)) {
954 PianoKey* key = dynamic_cast<PianoKey*>(lbl->parentItem());
955 if (key != nullptr) {
956 lbl->setVisible(false);
957 lbl->setFont(font());
958 lbl->setDefaultTextColor(d->m_foregroundPalette.getColor(key->isBlack() ? 1 : 0));
959 lbl->setOrientation(d->m_orientation);
960 lbl->setPlainText(noteName(key));
961 lbl->adjust();
962 lbl->setVisible((d->m_showLabels == ShowAlways) ||
963 (d->m_showLabels == ShowMinimum && isOctaveStart(key->getNote())));
964 }
965 }
966}
967
972{
973 for (PianoKey* key : qAsConst(d->m_keys)) {
974 if (d->m_showColorScale && (d->m_backgroundPalette.paletteId() == PAL_SCALE)) {
975 int degree = key->getNote() % 12;
976 key->setBrush(d->m_backgroundPalette.getColor(degree));
977 } else {
978 key->setBrush(d->m_backgroundPalette.getColor(key->isBlack() ? 1 : 0));
979 }
980 key->setPressed(false);
981 }
982}
983
990{
991 //qDebug() << Q_FUNC_INFO << show;
992 if (d->m_showLabels != show) {
993 d->m_showLabels = show;
995 }
996}
997
1004{
1005 return d->m_alterations;
1006}
1007
1014{
1015 if (d->m_alterations != use) {
1016 d->m_alterations = use;
1017 refreshLabels();
1018 }
1019}
1020
1026{
1027 return d->m_octave;
1028}
1029
1035{
1036 if (d->m_orientation != orientation) {
1037 d->m_orientation = orientation;
1038 refreshLabels();
1039 }
1040}
1041
1042bool PianoScene::isKeyboardEnabled() const
1043{
1044 return d->m_keyboardEnabled;
1045}
1046
1047void PianoScene::setOctave(const LabelCentralOctave octave)
1048{
1049 if (d->m_octave != octave) {
1050 d->m_octave = octave;
1051 refreshLabels();
1052 }
1053}
1054
1055LabelOrientation PianoScene::getOrientation() const
1056{
1057 return d->m_orientation;
1058}
1059
1064void PianoScene::setTranspose(const int transpose)
1065{
1066 if (d->m_transpose != transpose && transpose > -12 && transpose < 12) {
1067 d->m_transpose = transpose;
1069 refreshLabels();
1070 }
1071}
1072
1079{
1080 return d->m_showLabels;
1081}
1082
1088{
1089 if (d->m_rawkbd != b) {
1090 d->m_rawkbd = b;
1091 }
1092}
1093
1099{
1100 return d->m_noteNames;
1101}
1102
1108{
1109 return d->m_names_s;
1110}
1111
1117{
1118 return d->m_velocity;
1119}
1120
1125void PianoScene::setVelocity(const int velocity)
1126{
1127 d->m_velocity = velocity;
1128}
1129
1136{
1137 return d->m_channel;
1138}
1139
1145void PianoScene::setChannel(const int channel)
1146{
1147 d->m_channel = channel;
1148}
1149
1154void PianoScene::useCustomNoteNames(const QStringList& names)
1155{
1156 //qDebug() << Q_FUNC_INFO << names;
1157 d->m_noteNames = names;
1158 refreshLabels();
1159}
1160
1165{
1166 //qDebug() << Q_FUNC_INFO;
1167 d->m_noteNames.clear();
1168 refreshLabels();
1169}
1170
1175void PianoScene::setKeyboardEnabled(const bool enable)
1176{
1177 if (enable != d->m_keyboardEnabled) {
1178 d->m_keyboardEnabled = enable;
1179 }
1180}
1181
1187{
1188 return d->m_mouseEnabled;
1189}
1190
1195void PianoScene::setMouseEnabled(const bool enable)
1196{
1197 if (enable != d->m_mouseEnabled) {
1198 d->m_mouseEnabled = enable;
1199 }
1200}
1201
1207{
1208 return d->m_touchEnabled;
1209}
1210
1215void PianoScene::setTouchEnabled(const bool enable)
1216{
1217 if (enable != d->m_touchEnabled) {
1218 d->m_touchEnabled = enable;
1219 }
1220}
1221
1227{
1228 return d->m_velocityTint;
1229}
1230
1235void PianoScene::setVelocityTint(const bool enable)
1236{
1237 //qDebug() << Q_FUNC_INFO << enable;
1238 d->m_velocityTint = enable;
1239}
1240
1245{
1246 d->m_names_s = QStringList{
1247 tr("C"),
1248 tr("C♯"),
1249 tr("D"),
1250 tr("D♯"),
1251 tr("E"),
1252 tr("F"),
1253 tr("F♯"),
1254 tr("G"),
1255 tr("G♯"),
1256 tr("A"),
1257 tr("A♯"),
1258 tr("B")};
1259 d->m_names_f = QStringList{
1260 tr("C"),
1261 tr("Dâ™­"),
1262 tr("D"),
1263 tr("Eâ™­"),
1264 tr("E"),
1265 tr("F"),
1266 tr("Gâ™­"),
1267 tr("G"),
1268 tr("Aâ™­"),
1269 tr("A"),
1270 tr("Bâ™­"),
1271 tr("B")};
1272 refreshLabels();
1273}
1274
1280{
1281 if (d->m_showColorScale != show) {
1282 d->m_showColorScale = show;
1283 refreshKeys();
1284 invalidate();
1285 }
1286}
1287
1293{
1294 return d->m_hilightPalette.getColor(0);
1295}
1296
1302{
1303 if (d->m_hilightPalette != p) {
1304 d->m_hilightPalette = p;
1305 refreshKeys();
1306 invalidate();
1307 }
1308}
1309
1315{
1316 return d->m_backgroundPalette;
1317}
1318
1324{
1325 if (d->m_backgroundPalette != p) {
1326 d->m_backgroundPalette = p;
1327 refreshKeys();
1328 invalidate();
1329 }
1330}
1331
1337{
1338 return d->m_foregroundPalette;
1339}
1340
1346{
1347 if (d->m_foregroundPalette != p) {
1348 d->m_foregroundPalette = p;
1349 refreshLabels();
1350 invalidate();
1351 }
1352}
1353
1359{
1360 return d->m_showColorScale;
1361}
1362
1363void PianoScene::setKeyPicture(const bool natural, const QPixmap &pix)
1364{
1365 d->m_keyPix[int(natural)] = pix;
1366 for (PianoKey* key : qAsConst(d->m_keys)) {
1367 if (key->isBlack() == !natural) {
1368 key->setPixmap(pix);
1369 }
1370 }
1371}
1372
1373QPixmap PianoScene::getKeyPicture(const bool natural)
1374{
1375 return d->m_keyPix[int(natural)];
1376}
1377
1378void PianoScene::setUseKeyPictures(const bool enable)
1379{
1380 d->m_useKeyPix = enable;
1381 for (PianoKey* key : qAsConst(d->m_keys)) {
1382 key->setUsePixmap(enable);
1383 }
1384}
1385
1386bool PianoScene::getUseKeyPictures() const
1387{
1388 return d->m_useKeyPix;
1389}
1390
1391void PianoScene::saveData(QByteArray &ba)
1392{
1393 d->saveData(ba);
1394}
1395
1396void PianoScene::loadData(QByteArray &ba)
1397{
1398 d->loadData(ba);
1399}
1400
1406bool PianoScene::touchScreenEvent(QTouchEvent *touchEvent)
1407{
1408 switch(touchEvent->type()) {
1409 case QEvent::TouchEnd:
1410 case QEvent::TouchCancel:
1411 {
1412 foreach(PianoKey *key, d->m_touched) {
1413 //qDebug() << "key:" << key->getNote() << key->isPressed();
1414 if (key->isPressed()) {
1415 keyOff(key);
1416 }
1417 }
1418 d->m_touched.clear();
1419 touchEvent->accept();
1420 return true;
1421 } /* case (end and cancel touch events) */
1422 case QEvent::TouchBegin:
1423 case QEvent::TouchUpdate:
1424 {
1425 QList<QTouchEvent::TouchPoint> touchPoints =
1426 #if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
1427 touchEvent->touchPoints();
1428 #else
1429 touchEvent->points();
1430 #endif
1431 bool hasPressure =
1432 #if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
1433 touchEvent->device()->capabilities().testFlag(QTouchDevice::Pressure);
1434 #else
1435 touchEvent->device()->capabilities().testFlag(QInputDevice::Capability::Pressure);
1436 #endif
1437 foreach(const QTouchEvent::TouchPoint& touchPoint, touchPoints) {
1438 //qDebug() << touchPoint.id() << touchPoint.state();
1439 switch (touchPoint.state()) {
1440#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
1441 case Qt::TouchPointReleased:
1442#else
1443 case QEventPoint::Released:
1444#endif
1445 {
1446 PianoKey* key = d->m_touched.value(touchPoint.id());
1447 if (key != nullptr) {
1448 //qDebug() << "key:" << key->getNote() << key->isPressed();
1449 if (key->isPressed()) {
1450 if (hasPressure) {
1451 keyOff(key, touchPoint.pressure());
1452 } else {
1453 keyOff(key);
1454 }
1455 }
1456 d->m_touched.remove(touchPoint.id());
1457 }
1458 break;
1459 } /* case released state */
1460#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
1461 case Qt::TouchPointPressed:
1462#else
1463 case QEventPoint::Pressed:
1464#endif
1465 {
1466 PianoKey* key = getKeyForPos( d->m_view->mapToScene(
1467 #if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
1468 touchPoint.pos().toPoint()
1469 #else
1470 touchPoint.position().toPoint()
1471 #endif
1472 ));
1473 if (key != nullptr) {
1474 //qDebug() << "key:" << key->getNote() << key->isPressed();
1475 if (!key->isPressed()) {
1476 if (hasPressure) {
1477 keyOn(key, touchPoint.pressure());
1478 } else {
1479 keyOn(key);
1480 }
1481 key->ensureVisible();
1482 }
1483 d->m_touched[touchPoint.id()] = key;
1484 }
1485 break;
1486 } /* case pressed state */
1487#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
1488 case Qt::TouchPointMoved:
1489#else
1490 case QEventPoint::Updated:
1491#endif
1492 {
1493 PianoKey* key = getKeyForPos( d->m_view->mapToScene(
1494 #if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
1495 touchPoint.pos().toPoint()
1496 #else
1497 touchPoint.position().toPoint()
1498 #endif
1499 ));
1500 PianoKey* lastkey = d->m_touched.value(touchPoint.id());
1501 if ((lastkey != nullptr) && (lastkey != key)) {
1502 //qDebug() << "lastkey:" << lastkey->getNote() << lastkey->isPressed();
1503 if (lastkey->isPressed()) {
1504 if (hasPressure) {
1505 keyOff(lastkey, touchPoint.pressure());
1506 } else {
1507 keyOff(lastkey);
1508 }
1509 }
1510 d->m_touched.remove(touchPoint.id());
1511 }
1512 if (key != nullptr) {
1513 //qDebug() << "key:" << key->getNote() << key->isPressed();
1514 if (!key->isPressed()) {
1515 if (hasPressure) {
1516 keyOn(key, touchPoint.pressure());
1517 } else {
1518 keyOn(key);
1519 }
1520 }
1521 d->m_touched[touchPoint.id()] = key;
1522 }
1523 break;
1524 } /* case updated state */
1525 default:
1526 break;
1527 } /* switch touchpoint state */
1528 } /* foreach touchPoint */
1529 touchEvent->accept();
1530 return true;
1531 } /* case (begin and update touch events) */
1532 default:
1533 break;
1534 } /* switch touchEvent->type() */
1535 return false;
1536}
1537
1542void PianoScene::setUsingNativeFilter(const bool newState)
1543{
1544 if (newState != d->m_usingNativeFilter) {
1545 d->m_usingNativeFilter = newState;
1546 }
1547}
1548
1554{
1555 return d->m_usingNativeFilter;
1556}
1557
1558} // namespace widgets
1559} // 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:72
The PianoKeybd class.
Definition: pianokeybd.h:159
The PianoPalette class.
Definition: pianopalette.h:61
void allKeysOff()
Deactivates all keys.
Definition: pianoscene.cpp:752
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:437
void resetKeyPressedColor()
Assigns the default highlight palette colors and assigns it to the scene.
Definition: pianoscene.cpp:780
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:564
void showKeyOff(PianoKey *key, int vel)
Displays as deactivated a key.
Definition: pianoscene.cpp:368
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:765
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:552
void useStandardNoteNames()
Assigns the standard note names, clearing the list of custom note names.
void hideOrShowKeys()
Hides or shows keys.
Definition: pianoscene.cpp:801
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:198
bool event(QEvent *event) override
This method overrides QGraphicsScene::event().
Definition: pianoscene.cpp:744
int baseOctave() const
Returns the base octave number.
Definition: pianoscene.cpp:428
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:301
void setKeyboardMap(KeyboardMap *map)
Assigns the computer keyboard note map.
Definition: pianoscene.cpp:267
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:814
bool showColorScale() const
Returns whether the color scale mode is enabled.
void setBaseOctave(const int base)
Assigns the octave base number.
Definition: pianoscene.cpp:856
PianoKey * getKeyForPos(const QPointF &p) const
Returns the piano key for the given scene point coordenates.
Definition: pianoscene.cpp:586
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:869
PianoPalette getHighlightPalette()
Returns the palette used for highlighting the played keys.
Definition: pianoscene.cpp:310
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:602
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:456
PianoKey * getPianoKey(const int key) const
Returns the piano key object corresponding to the given computer keyboard key.
Definition: pianoscene.cpp:676
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:688
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:659
void refreshLabels()
Refresh the visibility and other attributes of the labels shown over the piano keys.
Definition: pianoscene.cpp:951
void showNoteOff(const int note, int vel=-1)
Displays deactivated the corresponding key for a given MIDI note, with MIDI velocity.
Definition: pianoscene.cpp:415
void setShowLabels(const LabelVisibility show)
Assigns the label visibility policy to the piano keys.
Definition: pianoscene.cpp:989
void refreshKeys()
Refresh the background colors of all the piano keys.
Definition: pianoscene.cpp:971
QSize sizeHint() const
Returns the calculated size of the scene.
Definition: pianoscene.cpp:258
bool isOctaveStart(const int note)
Returns whether the given note number is a octave startup note.
Definition: pianoscene.cpp:888
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:624
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:826
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:474
PianoHandler * getPianoHandler() const
Gets the PianoHandler pointer to the note receiver.
Definition: pianoscene.cpp:288
void showKeyOn(PianoKey *key, QColor color, int vel)
Displays highlighted the activated key with the supplied color and note velocity.
Definition: pianoscene.cpp:340
KeyboardMap * getKeyboardMap() const
Returns the computer keyboard note map.
Definition: pianoscene.cpp:276
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:576
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:388
void keyReleaseEvent(QKeyEvent *keyEvent) override
This event handler, for event keyEvent, is reimplemented to receive key release events.
Definition: pianoscene.cpp:715
void setMaxNote(const int note)
Assigns the maximum MIDI note number that will be displayed.
Definition: pianoscene.cpp:835
void retranslate()
Retranslates the standard note names.
int startKey() const
Returns the first key number that will be displayed.
Definition: pianoscene.cpp:878
void mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent) override
This event handler, for event mouseEvent, is reimplemented to receive mouse release events for the sc...
Definition: pianoscene.cpp:641
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:319
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:793
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).
bool isTouchEnabled() const
Returns whether the touch screen note generation is enabled.
int getTranspose() const
Returns the transpose amount in semitones.
Definition: pianoscene.cpp:847
QString noteName(PianoKey *key)
Returns the note name string that will be displayed over a given piano key.
Definition: pianoscene.cpp:898
LabelAlteration
Labels for Alterations.
Definition: pianokeybd.h:118
LabelCentralOctave
Labels Central Octave.
Definition: pianokeybd.h:145
LabelVisibility
Labels Visibility.
Definition: pianokeybd.h:108
LabelOrientation
Labels Orientation.
Definition: pianokeybd.h:127
QHash< int, int > KeyboardMap
KeyboardMap.
Definition: pianokeybd.h:96
@ ShowSharps
Show sharps on black keys.
Definition: pianokeybd.h:119
@ ShowNothing
Do not show names on black keys.
Definition: pianokeybd.h:121
@ ShowFlats
Show flats on black keys.
Definition: pianokeybd.h:120
@ OctaveNothing
Don't show octave numbers.
Definition: pianokeybd.h:146
@ OctaveC4
Central C, MIDI note #60 is C4.
Definition: pianokeybd.h:148
@ ShowAlways
Show always note names.
Definition: pianokeybd.h:112
@ ShowMinimum
Show only note C names.
Definition: pianokeybd.h:110
@ ShowActivated
Show names when notes are activated.
Definition: pianokeybd.h:111
@ ShowNever
Don't show note names.
Definition: pianokeybd.h:109
@ HorizontalOrientation
Show horizontal names.
Definition: pianokeybd.h:128
@ PAL_SCALE
Background colors for each chromatic scale note.
Definition: pianopalette.h:49
@ PAL_SINGLE
Single highlihgting color for all keys.
Definition: pianopalette.h:46
@ PAL_HISCALE
Highlighting colors for each chromatic scale note.
Definition: pianopalette.h:52
@ PAL_CHANNELS
Different highlihgting colors for each channel.
Definition: pianopalette.h:48
@ PAL_KEYS
Two background colors (naturals/alterations)
Definition: pianopalette.h:50
@ PAL_DOUBLE
Two highlihgting colors (naturals/alterations)
Definition: pianopalette.h:47
@ PAL_FONT
Foreground font colors for names.
Definition: pianopalette.h:51
Drumstick common.
Definition: alsaclient.cpp:68
Piano Keyboard Widget.
PianoScene class declaration.