drumstick  2.5.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 <QApplication>
20 #include <QDataStream>
21 #include <QByteArray>
22 #include <QGraphicsSceneMouseEvent>
23 #include <QKeyEvent>
24 #include <QPalette>
25 #include <QPixmap>
26 #include <QtMath>
27 #if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
28 #include <QTouchDevice>
29 #else
30 #include <QInputDevice>
31 #endif
32 #include <drumstick/pianokeybd.h>
33 #include "pianoscene.h"
34 
46 namespace drumstick { namespace widgets {
47 
48 class PianoScene::PianoScenePrivate
49 {
50 public:
51  PianoScenePrivate ( const int baseOctave,
52  const int numKeys,
53  const int startKey ):
54  m_baseOctave( baseOctave ),
55  m_numKeys( numKeys ),
56  m_startKey( startKey ),
57  m_minNote( 0 ),
58  m_maxNote( 127 ),
59  m_transpose( 0 ),
60  m_showLabels( ShowNever ),
61  m_alterations( ShowSharps ),
62  m_octave( OctaveC4 ),
63  m_orientation( HorizontalOrientation ),
64  m_rawkbd( false ),
65  m_keyboardEnabled( true ),
66  m_mouseEnabled( true ),
67  m_touchEnabled( true ),
68  m_mousePressed( false ),
69  m_velocity( 100 ),
70  m_channel( 0 ),
71  m_velocityTint( true ),
72  m_handler( nullptr ),
73  m_keybdMap( nullptr ),
74  m_showColorScale( false ),
75  m_hilightPalette(PianoPalette(PAL_SINGLE)),
76  m_backgroundPalette(PianoPalette(PAL_KEYS)),
77  m_foregroundPalette(PianoPalette(PAL_FONT)),
78  m_useKeyPix( true )
79  { }
80 
81  void saveData(QByteArray& buffer)
82  {
83  QDataStream ds(&buffer, QIODevice::WriteOnly);
84  ds << m_minNote;
85  ds << m_maxNote;
86  ds << m_transpose;
87  ds << m_showLabels;
88  ds << m_alterations;
89  ds << m_octave;
90  ds << m_orientation;
91  ds << m_rawkbd;
92  ds << m_keyboardEnabled;
93  ds << m_mouseEnabled;
94  ds << m_touchEnabled;
95  ds << m_mousePressed;
96  ds << m_velocity;
97  ds << m_channel;
98  ds << m_velocityTint;
99  ds << m_noteNames;
100  ds << m_names_s;
101  ds << m_names_f;
102  ds << m_showColorScale;
103  ds << m_hilightPalette;
104  ds << m_backgroundPalette;
105  ds << m_foregroundPalette;
106  ds << m_useKeyPix;
107  ds << m_keyPix[0];
108  ds << m_keyPix[1];
109  }
110 
111  void loadData(QByteArray& buffer)
112  {
113  quint32 u;
114  QDataStream ds(&buffer, QIODevice::ReadOnly);
115  ds >> m_minNote;
116  ds >> m_maxNote;
117  ds >> m_transpose;
118  ds >> u; m_showLabels = LabelVisibility(u);
119  ds >> u; m_alterations = LabelAlteration(u);
120  ds >> u; m_octave = LabelCentralOctave(u);
121  ds >> u; m_orientation = LabelOrientation(u);
122  ds >> m_rawkbd;
123  ds >> m_keyboardEnabled;
124  ds >> m_mouseEnabled;
125  ds >> m_touchEnabled;
126  ds >> m_mousePressed;
127  ds >> m_velocity;
128  ds >> m_channel;
129  ds >> m_velocityTint;
130  ds >> m_noteNames;
131  ds >> m_names_s;
132  ds >> m_names_f;
133  ds >> m_showColorScale;
134  ds >> m_hilightPalette;
135  ds >> m_backgroundPalette;
136  ds >> m_foregroundPalette;
137  ds >> m_useKeyPix;
138  ds >> m_keyPix[0];
139  ds >> m_keyPix[1];
140  }
141 
142  int m_baseOctave;
143  int m_numKeys;
144  int m_startKey;
145  int m_minNote;
146  int m_maxNote;
147  int m_transpose;
148  LabelVisibility m_showLabels;
149  LabelAlteration m_alterations;
150  LabelCentralOctave m_octave;
151  LabelOrientation m_orientation;
152  bool m_rawkbd;
153  bool m_keyboardEnabled;
154  bool m_mouseEnabled;
155  bool m_touchEnabled;
156  bool m_mousePressed;
157  int m_velocity;
158  int m_channel;
159  bool m_velocityTint;
160  PianoHandler *m_handler;
161  KeyboardMap *m_keybdMap;
162  QHash<int, PianoKey *> m_keys;
163  QMap<int, KeyLabel *> m_labels;
164  QStringList m_noteNames;
165  QStringList m_names_s;
166  QStringList m_names_f;
167  bool m_showColorScale;
168  PianoPalette m_hilightPalette;
169  PianoPalette m_backgroundPalette;
170  PianoPalette m_foregroundPalette;
171  bool m_useKeyPix;
172  QPixmap m_keyPix[2];
173 };
174 
175 const int KEYWIDTH = 180;
176 const int KEYHEIGHT = 720;
177 
178 static qreal sceneWidth(int keys) {
179  return KEYWIDTH * qCeil( keys * 7.0 / 12.0 );
180 }
181 
190 PianoScene::PianoScene ( const int baseOctave,
191  const int numKeys,
192  const int startKey,
193  const QColor& keyPressedColor,
194  QObject * parent )
195  : QGraphicsScene( QRectF(0, 0, sceneWidth(numKeys), KEYHEIGHT), parent ),
196  d(new PianoScenePrivate(baseOctave, numKeys, startKey))
197 {
198  if (keyPressedColor.isValid()) {
199  setKeyPressedColor(keyPressedColor);
200  }
201  QBrush hilightBrush(getKeyPressedColor());
202  PianoKeybd* view = dynamic_cast<PianoKeybd*>(parent);
203  if (view != nullptr) {
204  setFont(view->font());
205  }
206  int upperLimit = d->m_numKeys + d->m_startKey;
207  int adj = d->m_startKey % 12;
208  if (adj >= 5) adj++;
209  for(int i = d->m_startKey; i < upperLimit; ++i)
210  {
211  float x = 0;
212  PianoKey* key = nullptr;
213  KeyLabel* lbl = nullptr;
214  int ocs = i / 12 * 7;
215  int j = i % 12;
216  if (j >= 5) j++;
217  if ((j % 2) == 0) {
218  x = (ocs + qFloor((j-adj) / 2.0)) * KEYWIDTH;
219  key = new PianoKey( QRectF(x, 0, KEYWIDTH, KEYHEIGHT), false, i );
220  lbl = new KeyLabel(key);
221  lbl->setDefaultTextColor(d->m_foregroundPalette.getColor(0));
222  } else {
223  x = (ocs + qFloor((j-adj) / 2.0)) * KEYWIDTH + KEYWIDTH * 0.6 + 1;
224  key = new PianoKey( QRectF( x, 0, KEYWIDTH * 0.8 - 1, KEYHEIGHT * 0.6 ), true, i );
225  key->setZValue( 1 );
226  lbl = new KeyLabel(key);
227  lbl->setDefaultTextColor(d->m_foregroundPalette.getColor(1));
228  }
229  addItem( key );
230  lbl->setFont(font());
231  key->setAcceptTouchEvents(true);
232  key->setPressedBrush(hilightBrush);
233  d->m_keys.insert(i, key);
234  d->m_labels.insert(i, lbl);
235  }
236  hideOrShowKeys();
237  retranslate();
238 }
239 
244 { }
245 
250 QSize PianoScene::sizeHint() const
251 {
252  return {static_cast<int>(sceneWidth(d->m_numKeys)), KEYHEIGHT};
253 }
254 
260 {
261  d->m_keybdMap = map;
262 }
263 
269 {
270  return d->m_keybdMap;
271 }
272 
281 {
282  return d->m_handler;
283 }
284 
294 {
295  d->m_handler = handler;
296 }
297 
303 {
304  return d->m_hilightPalette;
305 }
306 
311 void PianoScene::displayKeyOn(PianoKey* key)
312 {
313  key->setPressed(true);
314  int n = key->getNote() + d->m_baseOctave*12 + d->m_transpose;
315  QString s = QString("#%1 (%2)").arg(n).arg(noteName(key));
316  emit signalName(s);
317  KeyLabel* lbl = dynamic_cast<KeyLabel*>(key->childItems().constFirst());
318  if (lbl != nullptr) {
319  lbl->setDefaultTextColor(d->m_foregroundPalette.getColor(key->isBlack() ? 3 : 2));
320  if (d->m_showLabels == ShowActivated) {
321  lbl->setVisible(true);
322  }
323  }
324 }
325 
332 void PianoScene::showKeyOn( PianoKey* key, QColor color, int vel )
333 {
334  //qDebug() << Q_FUNC_INFO << key->getNote() << vel << color << d->m_velocityTint;
335  if (d->m_velocityTint && (vel >= 0) && (vel < 128) && color.isValid() ) {
336  QBrush hilightBrush(color.lighter(200 - vel));
337  key->setPressedBrush(hilightBrush);
338  } else if (color.isValid()) {
339  key->setPressedBrush(color);
340  }
341  displayKeyOn(key);
342 }
343 
349 void PianoScene::showKeyOn( PianoKey* key, int vel )
350 {
351  setHighlightColorFromPolicy(key, vel);
352  displayKeyOn(key);
353 }
354 
360 void PianoScene::showKeyOff( PianoKey* key, int vel)
361 {
362  Q_UNUSED(vel)
363  key->setPressed(false);
364  emit signalName(QString());
365  KeyLabel* lbl = dynamic_cast<KeyLabel*>(key->childItems().constFirst());
366  if (lbl != nullptr) {
367  lbl->restoreColor();
368  if (d->m_showLabels == ShowActivated) {
369  lbl->setVisible(false);
370  }
371  }
372 }
373 
380 void PianoScene::showNoteOn( const int note, QColor color, int vel )
381 {
382  //qDebug() << Q_FUNC_INFO << note << vel << color;
383  int n = note - d->m_baseOctave*12 - d->m_transpose;
384  if ((note >= d->m_minNote) && (note <= d->m_maxNote) && d->m_keys.contains(n) && color.isValid())
385  showKeyOn(d->m_keys.value(n), color, vel);
386 }
387 
393 void PianoScene::showNoteOn( const int note, int vel )
394 {
395  //qDebug() << Q_FUNC_INFO << note << vel;
396  int n = note - d->m_baseOctave*12 - d->m_transpose;
397  if ((note >= d->m_minNote) && (note <= d->m_maxNote) && d->m_keys.contains(n)) {
398  showKeyOn(d->m_keys.value(n), vel);
399  }
400 }
401 
407 void PianoScene::showNoteOff( const int note, int vel )
408 {
409  int n = note - d->m_baseOctave*12 - d->m_transpose;
410  if ((note >= d->m_minNote) && (note <= d->m_maxNote) && d->m_keys.contains(n)) {
411  showKeyOff(d->m_keys.value(n), vel);
412  }
413 }
414 
420 int PianoScene::baseOctave() const { return d->m_baseOctave; }
421 
429 void PianoScene::triggerNoteOn( const int note, const int vel )
430 {
431  int n = d->m_baseOctave*12 + note + d->m_transpose;
432  if ((n >= d->m_minNote) && (n <= d->m_maxNote)) {
433  if (d->m_handler != nullptr) {
434  d->m_handler->noteOn(n, vel);
435  } else {
436  emit noteOn(n, vel);
437  }
438  }
439 }
440 
448 void PianoScene::triggerNoteOff( const int note, const int vel )
449 {
450  int n = d->m_baseOctave*12 + note + d->m_transpose;
451  if ((n >= d->m_minNote) && (n <= d->m_maxNote)) {
452  if (d->m_handler != nullptr) {
453  d->m_handler->noteOff(n, vel);
454  } else {
455  emit noteOff(n, vel);
456  }
457  }
458 }
459 
466 void PianoScene::setHighlightColorFromPolicy(PianoKey* key, int vel)
467 {
468  QColor c;
469  //qDebug() << Q_FUNC_INFO << key->getNote() << vel << d->m_velocityTint;
470  switch (d->m_hilightPalette.paletteId()) {
471  case PAL_SINGLE:
472  c = d->m_hilightPalette.getColor(0);
473  break;
474  case PAL_DOUBLE:
475  c = d->m_hilightPalette.getColor(key->getType());
476  break;
477  case PAL_CHANNELS:
478  c = d->m_hilightPalette.getColor(d->m_channel);
479  break;
480  case PAL_HISCALE:
481  c = d->m_hilightPalette.getColor(key->getDegree());
482  break;
483  default:
484  return;
485  }
486  if (c.isValid()) {
487  if (d->m_velocityTint && (vel >= 0) && (vel < 128)) {
488  QBrush h(c.lighter(200 - vel));
489  key->setPressedBrush(h);
490  } else {
491  key->setPressedBrush(c);
492  }
493  }
494 }
495 
500 void PianoScene::keyOn( PianoKey* key )
501 {
502  triggerNoteOn(key->getNote(), d->m_velocity);
503  showKeyOn(key, d->m_velocity);
504 }
505 
510 void PianoScene::keyOff( PianoKey* key )
511 {
512  triggerNoteOff(key->getNote(), 0);
513  showKeyOff(key, 0);
514 }
515 
521 void PianoScene::keyOn( PianoKey* key, qreal pressure )
522 {
523  int vel = d->m_velocity * pressure;
524  triggerNoteOn(key->getNote(), vel);
525  showKeyOn(key, vel);
526 }
527 
533 void PianoScene::keyOff( PianoKey* key, qreal pressure )
534 {
535  int vel = d->m_velocity * pressure;
536  triggerNoteOff(key->getNote(), vel);
537  showKeyOff(key, vel);
538 }
539 
544 void PianoScene::keyOn(const int note)
545 {
546  if (d->m_keys.contains(note))
547  keyOn(d->m_keys.value(note));
548  else
549  triggerNoteOn(note, d->m_velocity);
550 }
551 
556 void PianoScene::keyOff(const int note)
557 {
558  if (d->m_keys.contains(note))
559  keyOff(d->m_keys.value(note));
560  else
561  triggerNoteOff(note, d->m_velocity);
562 }
563 
569 {
570  return d->m_rawkbd;
571 }
572 
578 PianoKey* PianoScene::getKeyForPos( const QPointF& p ) const
579 {
580  PianoKey* key = nullptr;
581  QList<QGraphicsItem *> ptitems = this->items(p, Qt::IntersectsItemShape, Qt::DescendingOrder);
582  foreach(QGraphicsItem *itm, ptitems) {
583  key = dynamic_cast<PianoKey*>(itm);
584  if (key != nullptr)
585  break;
586  }
587  return key;
588 }
589 
594 void PianoScene::mouseMoveEvent ( QGraphicsSceneMouseEvent * mouseEvent )
595 {
596  if (d->m_mouseEnabled) {
597  if (d->m_mousePressed) {
598  PianoKey* key = getKeyForPos(mouseEvent->scenePos());
599  PianoKey* lastkey = getKeyForPos(mouseEvent->lastScenePos());
600  if ((lastkey != nullptr) && (lastkey != key) && lastkey->isPressed()) {
601  keyOff(lastkey);
602  }
603  if ((key != nullptr) && !key->isPressed()) {
604  keyOn(key);
605  }
606  mouseEvent->accept();
607  return;
608  }
609  }
610 }
611 
616 void PianoScene::mousePressEvent ( QGraphicsSceneMouseEvent * mouseEvent )
617 {
618  if (d->m_mouseEnabled) {
619  PianoKey* key = getKeyForPos(mouseEvent->scenePos());
620  if (key != nullptr && !key->isPressed()) {
621  keyOn(key);
622  d->m_mousePressed = true;
623  mouseEvent->accept();
624  return;
625  }
626  }
627 }
628 
633 void PianoScene::mouseReleaseEvent ( QGraphicsSceneMouseEvent * mouseEvent )
634 {
635  if (d->m_mouseEnabled) {
636  d->m_mousePressed = false;
637  PianoKey* key = getKeyForPos(mouseEvent->scenePos());
638  if (key != nullptr && key->isPressed()) {
639  keyOff(key);
640  mouseEvent->accept();
641  return;
642  }
643  }
644 }
645 
651 int PianoScene::getNoteFromKey( const int key ) const
652 {
653  if (d->m_keybdMap != nullptr) {
654  KeyboardMap::ConstIterator it = d->m_keybdMap->constFind(key);
655  if ((it != d->m_keybdMap->constEnd()) && (it.key() == key)) {
656  int note = it.value();
657  return note;
658  }
659  }
660  return -1;
661 }
662 
668 PianoKey* PianoScene::getPianoKey( const int key ) const
669 {
670  int note = getNoteFromKey(key);
671  if (d->m_keys.contains(note))
672  return d->m_keys.value(note);
673  return nullptr;
674 }
675 
680 void PianoScene::keyPressEvent ( QKeyEvent * keyEvent )
681 {
682  if ( d->m_keyboardEnabled) {
683  if ( !d->m_rawkbd && !keyEvent->isAutoRepeat() ) { // ignore auto-repeats
684  int note = getNoteFromKey(keyEvent->key());
685  if (note > -1)
686  keyOn(note);
687  }
688  keyEvent->accept();
689  return;
690  }
691  keyEvent->ignore();
692 }
693 
698 void PianoScene::keyReleaseEvent ( QKeyEvent * keyEvent )
699 {
700  if (d->m_keyboardEnabled) {
701  if ( !d->m_rawkbd && !keyEvent->isAutoRepeat() ) { // ignore auto-repeats
702  int note = getNoteFromKey(keyEvent->key());
703  if (note > -1)
704  keyOff(note);
705  }
706  keyEvent->accept();
707  return;
708  }
709  keyEvent->ignore();
710 }
711 
718 {
719  switch(event->type()) {
720  case QEvent::TouchBegin:
721  case QEvent::TouchEnd:
722  case QEvent::TouchUpdate:
723  {
724  QTouchEvent *touchEvent = static_cast<QTouchEvent*>(event);
725 #if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
726  const auto touchScreen = QTouchDevice::DeviceType::TouchScreen;
727 #else
728  const auto touchScreen = QInputDevice::DeviceType::TouchScreen;
729 #endif
730  if (d->m_touchEnabled && touchEvent->device()->type() == touchScreen) {
731  QList<QTouchEvent::TouchPoint> touchPoints = touchEvent->touchPoints();
732  bool hasPressure =
733 #if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
734  touchEvent->device()->capabilities().testFlag(QTouchDevice::Pressure);
735 #else
736  touchEvent->device()->capabilities().testFlag(QInputDevice::Capability::Pressure);
737 #endif
738  foreach(const QTouchEvent::TouchPoint& touchPoint, touchPoints) {
739  switch (touchPoint.state()) {
740  //case Qt::TouchPointPrimary:
741  case Qt::TouchPointStationary:
742  continue;
743  case Qt::TouchPointReleased: {
744  PianoKey* key = getKeyForPos(touchPoint.scenePos());
745  if (key != nullptr && key->isPressed()) {
746  if (hasPressure) {
747  keyOff(key, touchPoint.pressure());
748  } else {
749  keyOff(key);
750  }
751  }
752  break;
753  }
754  case Qt::TouchPointPressed: {
755  PianoKey* key = getKeyForPos(touchPoint.scenePos());
756  if (key != nullptr && !key->isPressed()) {
757  if (hasPressure) {
758  keyOn(key, touchPoint.pressure());
759  } else {
760  keyOn(key);
761  }
762  key->ensureVisible();
763  }
764  break;
765  }
766  case Qt::TouchPointMoved: {
767  PianoKey* key = getKeyForPos(touchPoint.scenePos());
768  PianoKey* lastkey = getKeyForPos(touchPoint.lastScenePos());
769  if ((lastkey != nullptr) && (lastkey != key) && lastkey->isPressed()) {
770  if (hasPressure) {
771  keyOff(lastkey, touchPoint.pressure());
772  } else {
773  keyOff(lastkey);
774  }
775  }
776  if ((key != nullptr) && !key->isPressed()) {
777  if (hasPressure) {
778  keyOn(key, touchPoint.pressure());
779  } else {
780  keyOn(key);
781  }
782  }
783  break;
784  }
785  default:
786  //qDebug() << "TouchPoint state: " << touchPoint.state();
787  break;
788  }
789  }
790  //qDebug() << "accepted event: " << event;
791  event->accept();
792  return true;
793  }
794  break;
795  }
796  default:
797  break;
798  }
799  //qDebug() << "unprocessed event: " << event;
800  return QGraphicsScene::event(event);
801 }
802 
807 {
808  foreach(PianoKey* key, d->m_keys) {
809  key->setPressed(false);
810  }
811 }
812 
819 void PianoScene::setKeyPressedColor(const QColor& color)
820 {
821  if (color.isValid()) {
822  d->m_hilightPalette = PianoPalette(PAL_SINGLE);
823  d->m_hilightPalette.setColor(0, color);
824  QBrush hilightBrush(color);
825  for (PianoKey* key : qAsConst(d->m_keys)) {
826  key->setPressedBrush(hilightBrush);
827  }
828  }
829 }
830 
835 {
836  d->m_hilightPalette.resetColors();
837  QBrush hilightBrush(getKeyPressedColor());
838  for (PianoKey* key : qAsConst(d->m_keys)) {
839  key->setPressedBrush(hilightBrush);
840  }
841 }
842 
848 {
849  return d->m_minNote;
850 }
851 
856 {
857  for (PianoKey* key : qAsConst(d->m_keys)) {
858  int n = d->m_baseOctave*12 + key->getNote() + d->m_transpose;
859  bool b = !(n > d->m_maxNote) && !(n < d->m_minNote);
860  key->setVisible(b);
861  }
862 }
863 
868 void PianoScene::setMinNote(const int note)
869 {
870  if (d->m_minNote != note) {
871  d->m_minNote = note;
872  hideOrShowKeys();
873  }
874 }
875 
881 {
882  return d->m_maxNote;
883 }
884 
889 void PianoScene::setMaxNote(const int note)
890 {
891  if (d->m_maxNote != note) {
892  d->m_maxNote = note;
893  hideOrShowKeys();
894  }
895 }
896 
902 {
903  return d->m_transpose;
904 }
905 
910 void PianoScene::setBaseOctave(const int base)
911 {
912  if (d->m_baseOctave != base) {
913  d->m_baseOctave = base;
914  hideOrShowKeys();
915  refreshLabels();
916  }
917 }
918 
924 {
925  return d->m_numKeys;
926 }
927 
933 {
934  return d->m_startKey;
935 }
936 
942 bool PianoScene::isOctaveStart(const int note)
943 {
944  return (note + d->m_transpose + 12) % 12 == 0;
945 }
946 
952 QString PianoScene::noteName( PianoKey* key )
953 {
954  Q_ASSERT(key != nullptr);
955  int note = key->getNote();
956  int num = (note + d->m_transpose + 12) % 12;
957  int adj = ((note + d->m_transpose < 0) ? 2 : 1) - d->m_octave + 1;
958  int oct = d->m_baseOctave + ((note + d->m_transpose) / 12) - adj;
959  if (d->m_noteNames.isEmpty()) {
960  QString name;
961  if (!d->m_names_f.isEmpty() && !d->m_names_s.isEmpty()) {
962  switch(d->m_alterations) {
963  case ShowFlats:
964  name = d->m_names_f.value(num);
965  break;
966  case ShowSharps:
967  name = d->m_names_s.value(num);
968  break;
969  case ShowNothing:
970  if (key->isBlack()) {
971  return QString();
972  }
973  name = d->m_names_s.value(num);
974  break;
975  default:
976  break;
977  }
978  }
979  if (d->m_octave==OctaveNothing) {
980  return name;
981  } else {
982  return QString("%1%2").arg(name).arg(oct);
983  }
984  } else {
985  if (d->m_noteNames.length() == 128) {
986  int n = d->m_baseOctave*12 + note + d->m_transpose;
987  //qDebug() << Q_FUNC_INFO << n << note;
988  if (n >= 0 && n < d->m_noteNames.length()) {
989  return d->m_noteNames.value(n);
990  }
991  } else if (d->m_noteNames.length() >= 12) {
992  if (d->m_octave==OctaveNothing) {
993  return d->m_noteNames.value(num);
994  } else {
995  return QString("%1%2").arg(d->m_noteNames.value(num)).arg(oct);
996  }
997  }
998  return QString();
999  }
1000 }
1001 
1006 {
1007  for (KeyLabel* lbl : qAsConst(d->m_labels)) {
1008  PianoKey* key = dynamic_cast<PianoKey*>(lbl->parentItem());
1009  if (key != nullptr) {
1010  lbl->setVisible(false);
1011  lbl->setFont(font());
1012  lbl->setDefaultTextColor(d->m_foregroundPalette.getColor(key->isBlack() ? 1 : 0));
1013  lbl->setOrientation(d->m_orientation);
1014  lbl->setPlainText(noteName(key));
1015  lbl->adjust();
1016  lbl->setVisible((d->m_showLabels == ShowAlways) ||
1017  (d->m_showLabels == ShowMinimum && isOctaveStart(key->getNote())));
1018  }
1019  }
1020 }
1021 
1026 {
1027  for (PianoKey* key : qAsConst(d->m_keys)) {
1028  if (d->m_showColorScale && (d->m_backgroundPalette.paletteId() == PAL_SCALE)) {
1029  int degree = key->getNote() % 12;
1030  key->setBrush(d->m_backgroundPalette.getColor(degree));
1031  } else {
1032  key->setBrush(d->m_backgroundPalette.getColor(key->isBlack() ? 1 : 0));
1033  }
1034  key->setPressed(false);
1035  }
1036 }
1037 
1044 {
1045  //qDebug() << Q_FUNC_INFO << show;
1046  if (d->m_showLabels != show) {
1047  d->m_showLabels = show;
1048  refreshLabels();
1049  }
1050 }
1051 
1058 {
1059  return d->m_alterations;
1060 }
1061 
1068 {
1069  if (d->m_alterations != use) {
1070  d->m_alterations = use;
1071  refreshLabels();
1072  }
1073 }
1074 
1080 {
1081  return d->m_octave;
1082 }
1083 
1089 {
1090  if (d->m_orientation != orientation) {
1091  d->m_orientation = orientation;
1092  refreshLabels();
1093  }
1094 }
1095 
1096 bool PianoScene::isKeyboardEnabled() const
1097 {
1098  return d->m_keyboardEnabled;
1099 }
1100 
1101 void PianoScene::setOctave(const LabelCentralOctave octave)
1102 {
1103  if (d->m_octave != octave) {
1104  d->m_octave = octave;
1105  refreshLabels();
1106  }
1107 }
1108 
1109 LabelOrientation PianoScene::getOrientation() const
1110 {
1111  return d->m_orientation;
1112 }
1113 
1118 void PianoScene::setTranspose(const int transpose)
1119 {
1120  if (d->m_transpose != transpose && transpose > -12 && transpose < 12) {
1121  d->m_transpose = transpose;
1122  hideOrShowKeys();
1123  refreshLabels();
1124  }
1125 }
1126 
1133 {
1134  return d->m_showLabels;
1135 }
1136 
1142 {
1143  if (d->m_rawkbd != b) {
1144  d->m_rawkbd = b;
1145  }
1146 }
1147 
1152 QStringList PianoScene::customNoteNames() const
1153 {
1154  return d->m_noteNames;
1155 }
1156 
1162 {
1163  return d->m_names_s;
1164 }
1165 
1171 {
1172  return d->m_velocity;
1173 }
1174 
1179 void PianoScene::setVelocity(const int velocity)
1180 {
1181  d->m_velocity = velocity;
1182 }
1183 
1190 {
1191  return d->m_channel;
1192 }
1193 
1199 void PianoScene::setChannel(const int channel)
1200 {
1201  d->m_channel = channel;
1202 }
1203 
1208 void PianoScene::useCustomNoteNames(const QStringList& names)
1209 {
1210  //qDebug() << Q_FUNC_INFO << names;
1211  d->m_noteNames = names;
1212  refreshLabels();
1213 }
1214 
1219 {
1220  //qDebug() << Q_FUNC_INFO;
1221  d->m_noteNames.clear();
1222  refreshLabels();
1223 }
1224 
1229 void PianoScene::setKeyboardEnabled(const bool enable)
1230 {
1231  if (enable != d->m_keyboardEnabled) {
1232  d->m_keyboardEnabled = enable;
1233  }
1234 }
1235 
1241 {
1242  return d->m_mouseEnabled;
1243 }
1244 
1249 void PianoScene::setMouseEnabled(const bool enable)
1250 {
1251  if (enable != d->m_mouseEnabled) {
1252  d->m_mouseEnabled = enable;
1253  }
1254 }
1255 
1261 {
1262  return d->m_touchEnabled;
1263 }
1264 
1269 void PianoScene::setTouchEnabled(const bool enable)
1270 {
1271  if (enable != d->m_touchEnabled) {
1272  d->m_touchEnabled = enable;
1273  }
1274 }
1275 
1281 {
1282  return d->m_velocityTint;
1283 }
1284 
1289 void PianoScene::setVelocityTint(const bool enable)
1290 {
1291  //qDebug() << Q_FUNC_INFO << enable;
1292  d->m_velocityTint = enable;
1293 }
1294 
1299 {
1300  d->m_names_s = QStringList{
1301  tr("C"),
1302  tr("C♯"),
1303  tr("D"),
1304  tr("D♯"),
1305  tr("E"),
1306  tr("F"),
1307  tr("F♯"),
1308  tr("G"),
1309  tr("G♯"),
1310  tr("A"),
1311  tr("A♯"),
1312  tr("B")};
1313  d->m_names_f = QStringList{
1314  tr("C"),
1315  tr("Dâ™­"),
1316  tr("D"),
1317  tr("Eâ™­"),
1318  tr("E"),
1319  tr("F"),
1320  tr("Gâ™­"),
1321  tr("G"),
1322  tr("Aâ™­"),
1323  tr("A"),
1324  tr("Bâ™­"),
1325  tr("B")};
1326  refreshLabels();
1327 }
1328 
1333 void PianoScene::setShowColorScale(const bool show)
1334 {
1335  if (d->m_showColorScale != show) {
1336  d->m_showColorScale = show;
1337  refreshKeys();
1338  invalidate();
1339  }
1340 }
1341 
1347 {
1348  return d->m_hilightPalette.getColor(0);
1349 }
1350 
1356 {
1357  if (d->m_hilightPalette != p) {
1358  d->m_hilightPalette = p;
1359  refreshKeys();
1360  invalidate();
1361  }
1362 }
1363 
1369 {
1370  return d->m_backgroundPalette;
1371 }
1372 
1378 {
1379  if (d->m_backgroundPalette != p) {
1380  d->m_backgroundPalette = p;
1381  refreshKeys();
1382  invalidate();
1383  }
1384 }
1385 
1391 {
1392  return d->m_foregroundPalette;
1393 }
1394 
1400 {
1401  if (d->m_foregroundPalette != p) {
1402  d->m_foregroundPalette = p;
1403  refreshLabels();
1404  invalidate();
1405  }
1406 }
1407 
1413 {
1414  return d->m_showColorScale;
1415 }
1416 
1417 void PianoScene::setKeyPicture(const bool natural, const QPixmap &pix)
1418 {
1419  d->m_keyPix[int(natural)] = pix;
1420  for (PianoKey* key : qAsConst(d->m_keys)) {
1421  if (key->isBlack() == !natural) {
1422  key->setPixmap(pix);
1423  }
1424  }
1425 }
1426 
1427 QPixmap PianoScene::getKeyPicture(const bool natural)
1428 {
1429  return d->m_keyPix[int(natural)];
1430 }
1431 
1432 void PianoScene::setUseKeyPictures(const bool enable)
1433 {
1434  d->m_useKeyPix = enable;
1435  for (PianoKey* key : qAsConst(d->m_keys)) {
1436  key->setUsePixmap(enable);
1437  }
1438 }
1439 
1440 bool PianoScene::getUseKeyPictures() const
1441 {
1442  return d->m_useKeyPix;
1443 }
1444 
1445 void PianoScene::saveData(QByteArray &ba)
1446 {
1447  d->saveData(ba);
1448 }
1449 
1450 void PianoScene::loadData(QByteArray &ba)
1451 {
1452  d->loadData(ba);
1453 }
1454 
1455 } // namespace widgets
1456 } // 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:806
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:429
void resetKeyPressedColor()
Assigns the default highlight palette colors and assigns it to the scene.
Definition: pianoscene.cpp:834
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:556
void showKeyOff(PianoKey *key, int vel)
Displays as deactivated a key.
Definition: pianoscene.cpp:360
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:819
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:544
void useStandardNoteNames()
Assigns the standard note names, clearing the list of custom note names.
void hideOrShowKeys()
Hides or shows keys.
Definition: pianoscene.cpp:855
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:190
bool event(QEvent *event) override
Processes touch screen events.
Definition: pianoscene.cpp:717
int baseOctave() const
Returns the base octave number.
Definition: pianoscene.cpp:420
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:293
void setKeyboardMap(KeyboardMap *map)
Assigns the computer keyboard note map.
Definition: pianoscene.cpp:259
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:868
bool showColorScale() const
Returns whether the color scale mode is enabled.
void setBaseOctave(const int base)
Assigns the octave base number.
Definition: pianoscene.cpp:910
PianoKey * getKeyForPos(const QPointF &p) const
Returns the piano key for the given scene point coordenates.
Definition: pianoscene.cpp:578
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:923
PianoPalette getHighlightPalette()
Returns the palette used for highlighting the played keys.
Definition: pianoscene.cpp:302
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:594
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:448
PianoKey * getPianoKey(const int key) const
Returns the piano key object corresponding to the given computer keyboard key.
Definition: pianoscene.cpp:668
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:680
void setVelocityTint(const bool enable)
Enables or disables the velocity parameter of note events to influence the highlight key colors.
bool velocityTint() const
Returns whether the velocity parameter of note events is used to influence the highlight key colors.
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:651
void refreshLabels()
Refresh the visibility and other attributes of the labels shown over the piano keys.
void showNoteOff(const int note, int vel=-1)
Displays deactivated the corresponding key for a given MIDI note, with MIDI velocity.
Definition: pianoscene.cpp:407
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.
QSize sizeHint() const
Returns the calculated size of the scene.
Definition: pianoscene.cpp:250
bool isOctaveStart(const int note)
Returns whether the given note number is a octave startup note.
Definition: pianoscene.cpp:942
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:616
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:880
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:466
PianoHandler * getPianoHandler() const
Gets the PianoHandler pointer to the note receiver.
Definition: pianoscene.cpp:280
void showKeyOn(PianoKey *key, QColor color, int vel)
Displays highlighted the activated key with the supplied color and note velocity.
Definition: pianoscene.cpp:332
KeyboardMap * getKeyboardMap() const
Returns the computer keyboard note map.
Definition: pianoscene.cpp:268
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:568
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:380
void keyReleaseEvent(QKeyEvent *keyEvent) override
This event handler, for event keyEvent, is reimplemented to receive key release events.
Definition: pianoscene.cpp:698
void setMaxNote(const int note)
Assigns the maximum MIDI note number that will be displayed.
Definition: pianoscene.cpp:889
void retranslate()
Retranslates the standard note names.
int startKey() const
Returns the first key number that will be displayed.
Definition: pianoscene.cpp:932
void mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent) override
This event handler, for event mouseEvent, is reimplemented to receive mouse release events for the sc...
Definition: pianoscene.cpp:633
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:311
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:847
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:901
QString noteName(PianoKey *key)
Returns the note name string that will be displayed over a given piano key.
Definition: pianoscene.cpp:952
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.