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
33 #include <drumstick/pianokeybd.h>
34 #include "pianoscene.h"
35 
47 namespace drumstick { namespace widgets {
48 
49 class PianoScene::PianoScenePrivate
50 {
51 public:
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 
238 const int KEYWIDTH = 180;
239 const int KEYHEIGHT = 720;
240 
241 static qreal sceneWidth(int keys) {
242  return KEYWIDTH * qCeil( keys * 7.0 / 12.0 );
243 }
244 
253 PianoScene::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  }
299  hideOrShowKeys();
300  retranslate();
301 }
302 
307 { }
308 
313 QSize PianoScene::sizeHint() const
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 
374 void 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 
395 void 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 
412 void PianoScene::showKeyOn( PianoKey* key, int vel )
413 {
414  setHighlightColorFromPolicy(key, vel);
415  displayKeyOn(key);
416 }
417 
423 void 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 
443 void 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 
456 void 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 
470 void 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 
483 int PianoScene::baseOctave() const { return d->m_baseOctave; }
484 
492 void 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 
511 void 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 
529 void 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 
563 void PianoScene::keyOn( PianoKey* key )
564 {
565  triggerNoteOn(key->getNote(), d->m_velocity);
566  showKeyOn(key, d->m_velocity);
567 }
568 
573 void PianoScene::keyOff( PianoKey* key )
574 {
575  triggerNoteOff(key->getNote(), 0);
576  showKeyOff(key, 0);
577 }
578 
584 void 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 
596 void 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 
607 void 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 
619 void 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 
641 PianoKey* 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 
657 void 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 
679 void 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 
696 void 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 
714 int 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 
731 PianoKey* 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 
743 void 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 
770 void 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 
820 void 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 
869 void PianoScene::setMinNote(const int note)
870 {
871  if (d->m_minNote != note) {
872  d->m_minNote = note;
873  hideOrShowKeys();
874  }
875 }
876 
882 {
883  return d->m_maxNote;
884 }
885 
890 void PianoScene::setMaxNote(const int note)
891 {
892  if (d->m_maxNote != note) {
893  d->m_maxNote = note;
894  hideOrShowKeys();
895  }
896 }
897 
903 {
904  return d->m_transpose;
905 }
906 
911 void PianoScene::setBaseOctave(const int base)
912 {
913  if (d->m_baseOctave != base) {
914  d->m_baseOctave = base;
915  hideOrShowKeys();
916  refreshLabels();
917  }
918 }
919 
925 {
926  return d->m_numKeys;
927 }
928 
934 {
935  return d->m_startKey;
936 }
937 
943 bool PianoScene::isOctaveStart(const int note)
944 {
945  return (note + d->m_transpose + 12) % 12 == 0;
946 }
947 
953 QString 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 
1053 bool PianoScene::isKeyboardEnabled() const
1054 {
1055  return d->m_keyboardEnabled;
1056 }
1057 
1058 void PianoScene::setOctave(const LabelCentralOctave octave)
1059 {
1060  if (d->m_octave != octave) {
1061  d->m_octave = octave;
1062  refreshLabels();
1063  }
1064 }
1065 
1066 LabelOrientation PianoScene::getOrientation() const
1067 {
1068  return d->m_orientation;
1069 }
1070 
1075 void PianoScene::setTranspose(const int transpose)
1076 {
1077  if (d->m_transpose != transpose && transpose > -12 && transpose < 12) {
1078  d->m_transpose = transpose;
1079  hideOrShowKeys();
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 
1109 QStringList PianoScene::customNoteNames() const
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 
1136 void PianoScene::setVelocity(const int velocity)
1137 {
1138  d->m_velocity = velocity;
1139 }
1140 
1147 {
1148  return d->m_channel;
1149 }
1150 
1156 void PianoScene::setChannel(const int channel)
1157 {
1158  d->m_channel = channel;
1159 }
1160 
1165 void 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 
1186 void 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 
1206 void 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 
1226 void 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 
1246 void 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 
1290 void PianoScene::setShowColorScale(const bool show)
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 
1374 void 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 
1384 QPixmap PianoScene::getKeyPicture(const bool natural)
1385 {
1386  return d->m_keyPix[int(natural)];
1387 }
1388 
1389 void 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 
1397 bool PianoScene::getUseKeyPictures() const
1398 {
1399  return d->m_useKeyPix;
1400 }
1401 
1402 void PianoScene::saveData(QByteArray &ba)
1403 {
1404  d->saveData(ba);
1405 }
1406 
1407 void PianoScene::loadData(QByteArray &ba)
1408 {
1409  d->loadData(ba);
1410 }
1411 
1417 bool 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 
1553 void 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 
1573 void 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.