drumstick  2.6.0
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
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  { }
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 
183 const int KEYWIDTH = 180;
184 const int KEYHEIGHT = 720;
185 
186 static qreal sceneWidth(int keys) {
187  return KEYWIDTH * qCeil( keys * 7.0 / 12.0 );
188 }
189 
198 PianoScene::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  }
244  hideOrShowKeys();
245  retranslate();
246 }
247 
252 { }
253 
258 QSize PianoScene::sizeHint() const
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 
319 void 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 
340 void 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 
357 void PianoScene::showKeyOn( PianoKey* key, int vel )
358 {
359  setHighlightColorFromPolicy(key, vel);
360  displayKeyOn(key);
361 }
362 
368 void 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 
388 void 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 
401 void 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 
415 void 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 
428 int PianoScene::baseOctave() const { return d->m_baseOctave; }
429 
437 void 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 
456 void 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 
474 void 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 
508 void PianoScene::keyOn( PianoKey* key )
509 {
510  triggerNoteOn(key->getNote(), d->m_velocity);
511  showKeyOn(key, d->m_velocity);
512 }
513 
518 void PianoScene::keyOff( PianoKey* key )
519 {
520  triggerNoteOff(key->getNote(), 0);
521  showKeyOff(key, 0);
522 }
523 
529 void 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 
541 void 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 
552 void 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 
564 void 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 
586 PianoKey* 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 
602 void 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 
624 void 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 
641 void 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 
659 int 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 
676 PianoKey* 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 
688 void 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 
715 void 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 
765 void 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 
814 void PianoScene::setMinNote(const int note)
815 {
816  if (d->m_minNote != note) {
817  d->m_minNote = note;
818  hideOrShowKeys();
819  }
820 }
821 
827 {
828  return d->m_maxNote;
829 }
830 
835 void PianoScene::setMaxNote(const int note)
836 {
837  if (d->m_maxNote != note) {
838  d->m_maxNote = note;
839  hideOrShowKeys();
840  }
841 }
842 
848 {
849  return d->m_transpose;
850 }
851 
856 void PianoScene::setBaseOctave(const int base)
857 {
858  if (d->m_baseOctave != base) {
859  d->m_baseOctave = base;
860  hideOrShowKeys();
861  refreshLabels();
862  }
863 }
864 
870 {
871  return d->m_numKeys;
872 }
873 
879 {
880  return d->m_startKey;
881 }
882 
888 bool PianoScene::isOctaveStart(const int note)
889 {
890  return (note + d->m_transpose + 12) % 12 == 0;
891 }
892 
898 QString 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;
994  refreshLabels();
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 
1042 bool PianoScene::isKeyboardEnabled() const
1043 {
1044  return d->m_keyboardEnabled;
1045 }
1046 
1047 void PianoScene::setOctave(const LabelCentralOctave octave)
1048 {
1049  if (d->m_octave != octave) {
1050  d->m_octave = octave;
1051  refreshLabels();
1052  }
1053 }
1054 
1055 LabelOrientation PianoScene::getOrientation() const
1056 {
1057  return d->m_orientation;
1058 }
1059 
1064 void PianoScene::setTranspose(const int transpose)
1065 {
1066  if (d->m_transpose != transpose && transpose > -12 && transpose < 12) {
1067  d->m_transpose = transpose;
1068  hideOrShowKeys();
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 
1098 QStringList PianoScene::customNoteNames() const
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 
1125 void PianoScene::setVelocity(const int velocity)
1126 {
1127  d->m_velocity = velocity;
1128 }
1129 
1136 {
1137  return d->m_channel;
1138 }
1139 
1145 void PianoScene::setChannel(const int channel)
1146 {
1147  d->m_channel = channel;
1148 }
1149 
1154 void 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 
1175 void 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 
1195 void 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 
1215 void 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 
1235 void 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 
1279 void PianoScene::setShowColorScale(const bool show)
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 
1363 void 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 
1373 QPixmap PianoScene::getKeyPicture(const bool natural)
1374 {
1375  return d->m_keyPix[int(natural)];
1376 }
1377 
1378 void 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 
1386 bool PianoScene::getUseKeyPictures() const
1387 {
1388  return d->m_useKeyPix;
1389 }
1390 
1391 void PianoScene::saveData(QByteArray &ba)
1392 {
1393  d->saveData(ba);
1394 }
1395 
1396 void PianoScene::loadData(QByteArray &ba)
1397 {
1398  d->loadData(ba);
1399 }
1400 
1406 bool 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 
1542 void 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
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
The PianoHandler class callbacks.
Definition: pianokeybd.h:71
bool isMouseEnabled() const
Returns whether the computer keyboard note generation is enabled.
bool touchScreenEvent(QTouchEvent *touchEvent)
Process touch screen events, called by the view.
QSize sizeHint() const
Returns the calculated size of the scene.
Definition: pianoscene.cpp:258
The QGraphicsScene class provides a surface for managing a large number of 2D graphical items...
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
bool velocityTint() const
Returns whether the velocity parameter of note events is used to influence the highlight key colors...
LabelOrientation
Labels Orientation.
Definition: pianokeybd.h:127
PianoPalette getBackgroundPalette()
Returns the background palette.
The PianoKeybd class.
Definition: pianokeybd.h:158
void setHighlightPalette(const PianoPalette &p)
Assigns the active highlight palette.
void showKeyOff(PianoKey *key, int vel)
Displays as deactivated a key.
Definition: pianoscene.cpp:368
void setShowColorScale(const bool show)
Enables or disables the color scale key background mode.
void allKeysOff()
Deactivates all keys.
Definition: pianoscene.cpp:752
void refreshLabels()
Refresh the visibility and other attributes of the labels shown over the piano keys.
Definition: pianoscene.cpp:951
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 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...
The PianoPalette class.
Definition: pianopalette.h:60
QHash< int, int > KeyboardMap
KeyboardMap.
Definition: pianokeybd.h:96
void signalName(const QString &name)
signalName is emitted for each note created, and contains a string with the MIDI note number and the ...
void setKeyPressedColor(const QColor &color)
Assigns a single color for key highlight.
Definition: pianoscene.cpp:765
void useStandardNoteNames()
Assigns the standard note names, clearing the list of custom note names.
KeyboardMap * getKeyboardMap() const
Returns the computer keyboard note map.
Definition: pianoscene.cpp:276
void setOrientation(const LabelOrientation orientation)
Assigns the label orientation policy.
Single highlihgting color for all keys.
Definition: pianopalette.h:46
Two highlihgting colors (naturals/alterations)
Definition: pianopalette.h:47
int getMaxNote() const
Returns the maximum MIDI note number that will be displayed.
Definition: pianoscene.cpp:826
The QObject class is the base class of all Qt objects.
int numKeys() const
Returns the number of keys that will be displayed.
Definition: pianoscene.cpp:869
void setPianoHandler(PianoHandler *handler)
Assigns a PianoHandler pointer for processing note events.
Definition: pianoscene.cpp:301
void retranslate()
Retranslates the standard note names.
void showKeyOn(PianoKey *key, QColor color, int vel)
Displays highlighted the activated key with the supplied color and note velocity. ...
Definition: pianoscene.cpp:340
LabelVisibility showLabels() const
Returns the label visibility policy (display note names over the piano keys).
Show always note names.
Definition: pianokeybd.h:112
void setMaxNote(const int note)
Assigns the maximum MIDI note number that will be displayed.
Definition: pianoscene.cpp:835
void setMouseEnabled(const bool enable)
Enables or disables the mouse note generation.
PianoHandler * getPianoHandler() const
Gets the PianoHandler pointer to the note receiver.
Definition: pianoscene.cpp:288
Don&#39;t show octave numbers.
Definition: pianokeybd.h:146
Drumstick common.
Definition: alsaclient.cpp:68
LabelVisibility
Labels Visibility.
Definition: pianokeybd.h:108
void setKeyboardMap(KeyboardMap *map)
Assigns the computer keyboard note map.
Definition: pianoscene.cpp:267
bool isTouchEnabled() const
Returns whether the touch screen note generation is enabled.
Foreground font colors for names.
Definition: pianopalette.h:51
Two background colors (naturals/alterations)
Definition: pianopalette.h:50
Show sharps on black keys.
Definition: pianokeybd.h:119
void displayKeyOn(PianoKey *key)
Displays the note label over a highligted key.
Definition: pianoscene.cpp:319
void refreshKeys()
Refresh the background colors of all the piano keys.
Definition: pianoscene.cpp:971
Show only note C names.
Definition: pianokeybd.h:110
PianoScene class declaration.
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
Don&#39;t show note names.
Definition: pianokeybd.h:109
int getVelocity()
Returns the MIDI note velocity parameter that is assigned to the MIDI OUT notes.
PianoKey * getPianoKey(const int key) const
Returns the piano key object corresponding to the given computer keyboard key.
Definition: pianoscene.cpp:676
void keyReleaseEvent(QKeyEvent *keyEvent) override
This event handler, for event keyEvent, is reimplemented to receive key release events.
Definition: pianoscene.cpp:715
Background colors for each chromatic scale note.
Definition: pianopalette.h:49
void setMinNote(const int note)
Assigns the minimum MIDI note number that will be displayed.
Definition: pianoscene.cpp:814
int startKey() const
Returns the first key number that will be displayed.
Definition: pianoscene.cpp:878
void setTranspose(const int transpose)
Assigns the transpose amount in semitones.
int getNoteFromKey(const int key) const
Returns the note number for the given computer keyboard key code.
Definition: pianoscene.cpp:659
QColor getKeyPressedColor() const
Returns the single highlight palette color.
int getChannel() const
Returns the MIDI channel that is assigned to the output events, or used to filter the input events (u...
PianoKey * getKeyForPos(const QPointF &p) const
Returns the piano key for the given scene point coordenates.
Definition: pianoscene.cpp:586
bool isUsingNativeFilter() const
Returns whether the application is filtering native events.
Show names when notes are activated.
Definition: pianokeybd.h:111
bool event(QEvent *event) override
This method overrides QGraphicsScene::event().
Definition: pianoscene.cpp:744
void useCustomNoteNames(const QStringList &names)
Assigns the list of custom note names, and enables this mode.
int getMinNote() const
Returns the minimum MIDI note number that will be displayed.
Definition: pianoscene.cpp:793
void setVelocity(const int velocity)
Assigns the MIDI note velocity parameter that is assigned to the MIDI OUT notes.
QStringList customNoteNames() const
Returns the custom note names list.
void noteOn(int n, int v)
This signal is emitted for each Note On MIDI event created using the computer keyboard, mouse or touch screen.
void setShowLabels(const LabelVisibility show)
Assigns the label visibility policy to the piano keys.
Definition: pianoscene.cpp:989
void noteOff(int n, int v)
This signal is emitted for each Note Off MIDI event created using the computer keyboard, mouse or touch screen.
void setKeyboardEnabled(const bool enable)
Enables or disables the computer keyboard note generation.
LabelAlteration
Labels for Alterations.
Definition: pianokeybd.h:118
QStringList standardNoteNames() const
Returns the standard note names list.
void resetKeyPressedColor()
Assigns the default highlight palette colors and assigns it to the scene.
Definition: pianoscene.cpp:780
Show flats on black keys.
Definition: pianokeybd.h:120
QString noteName(PianoKey *key)
Returns the note name string that will be displayed over a given piano key.
Definition: pianoscene.cpp:898
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
Highlighting colors for each chromatic scale note.
Definition: pianopalette.h:52
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
Central C, MIDI note #60 is C4.
Definition: pianokeybd.h:148
Different highlihgting colors for each channel.
Definition: pianopalette.h:48
bool isOctaveStart(const int note)
Returns whether the given note number is a octave startup note.
Definition: pianoscene.cpp:888
LabelCentralOctave
Labels Central Octave.
Definition: pianokeybd.h:145
void setForegroundPalette(const PianoPalette &p)
Assigns the active foreground palette.
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
void hideOrShowKeys()
Hides or shows keys.
Definition: pianoscene.cpp:801
void setBaseOctave(const int base)
Assigns the octave base number.
Definition: pianoscene.cpp:856
Piano Keyboard Widget.
Do not show names on black keys.
Definition: pianokeybd.h:121
PianoScene(const int baseOctave, const int numKeys, const int startKey, const QColor &keyPressedColor=QColor(), QObject *parent=nullptr)
Constructor.
Definition: pianoscene.cpp:198
PianoPalette getForegroundPalette()
Returns the active foreground palette.
LabelAlteration alterations() const
Returns the alterations name policy.
void setRawKeyboardMode(const bool b)
Assigns the low level computer keyboard mode.
void setUsingNativeFilter(const bool newState)
Enables or disables the application level usage of a native event filter.
bool showColorScale() const
Returns whether the color scale mode is enabled.
int baseOctave() const
Returns the base octave number.
Definition: pianoscene.cpp:428
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
LabelCentralOctave getOctave() const
Returns the central octave name policy.
bool getRawKeyboardMode() const
Returns whether the low level computer keyboard mode is enabled.
Definition: pianoscene.cpp:576
void setBackgroundPalette(const PianoPalette &p)
Assigns the active background palette.
The QEvent class is the base class of all event classes.
void setAlterations(const LabelAlteration use)
Assigns the alterations name policy.
void setChannel(const int channel)
Assigns the MIDI channel that is included into the output events, or used to filter the input events ...
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.
int getTranspose() const
Returns the transpose amount in semitones.
Definition: pianoscene.cpp:847
PianoPalette getHighlightPalette()
Returns the palette used for highlighting the played keys.
Definition: pianoscene.cpp:310
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