1 /*
2 Virtual Piano Widget for Qt5
3 Copyright (C) 2008-2021, 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
35 /**
36 * @file pianoscene.cpp
37 * Implementation of the Piano Scene
38 */
39
40 /**
41 * @class QGraphicsScene
42 * The QGraphicsScene class provides a surface for managing a large number of 2D graphical items.
43 * @see https://doc.qt.io/qt-5/qgraphicsscene.html
44 */
45
46 namespace drumstick { namespace widgets {
47
48 class PianoScene::PianoScenePrivate
49 {
50 public:
PianoScenePrivate(const int baseOctave,const int numKeys,const int startKey)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
saveData(QByteArray & buffer)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
loadData(QByteArray & buffer)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
sceneWidth(int keys)178 static qreal sceneWidth(int keys) {
179 return KEYWIDTH * qCeil( keys * 7.0 / 12.0 );
180 }
181
182 /**
183 * Constructor.
184 * @param baseOctave octave base number
185 * @param numKeys number of keys
186 * @param startKey starting key
187 * @param keyPressedColor highlight keys color
188 * @param parent owner object
189 */
PianoScene(const int baseOctave,const int numKeys,const int startKey,const QColor & keyPressedColor,QObject * parent)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
240 /**
241 * Destructor.
242 */
~PianoScene()243 PianoScene::~PianoScene()
244 { }
245
246 /**
247 * Returns the calculated size of the scene.
248 * @return the calculated size of the scene
249 */
sizeHint() const250 QSize PianoScene::sizeHint() const
251 {
252 return {static_cast<int>(sceneWidth(d->m_numKeys)), KEYHEIGHT};
253 }
254
255 /**
256 * Assigns the computer keyboard note map.
257 * @param map the computer keyboard note map.
258 */
setKeyboardMap(KeyboardMap * map)259 void PianoScene::setKeyboardMap(KeyboardMap *map)
260 {
261 d->m_keybdMap = map;
262 }
263
264 /**
265 * Returns the computer keyboard note map.
266 * @return the computer keyboard note map
267 */
getKeyboardMap() const268 KeyboardMap *PianoScene::getKeyboardMap() const
269 {
270 return d->m_keybdMap;
271 }
272
273 /**
274 * Gets the PianoHandler pointer to the note receiver.
275 *
276 * If this method returns null, then there is not a PianoHandler class assigned,
277 * and then the signals noteOn() and noteOff() are emitted instead.
278 * @return pointer to the PianoHandler class, if there is one assigned
279 */
getPianoHandler() const280 PianoHandler *PianoScene::getPianoHandler() const
281 {
282 return d->m_handler;
283 }
284
285 /**
286 * Assigns a PianoHandler pointer for processing note events.
287 *
288 * When this member is used to assign a PianoHandler instance, then
289 * the methods in that instance are called instead of emitting the
290 * signals noteOn() and noteOff().
291 * @param handler pointer to a PianoHandler instance
292 */
setPianoHandler(PianoHandler * handler)293 void PianoScene::setPianoHandler(PianoHandler *handler)
294 {
295 d->m_handler = handler;
296 }
297
298 /**
299 * Returns the palette used for highlighting the played keys
300 * @return The PianoPalette used to highlight the played keys
301 */
getHighlightPalette()302 PianoPalette PianoScene::getHighlightPalette()
303 {
304 return d->m_hilightPalette;
305 }
306
307 /**
308 * Displays the note label over a highligted key
309 * @param key the activated key
310 */
displayKeyOn(PianoKey * key)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
326 /**
327 * Displays highlighted the activated key with the supplied color and note velocity
328 * @param key the activated key
329 * @param color the highlight color
330 * @param vel the MIDI note velocity
331 */
showKeyOn(PianoKey * key,QColor color,int vel)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
344 /**
345 * Displays highlighted the activated key with the supplied note velocity
346 * @param key the activated key
347 * @param vel the MIDI note velocity
348 */
showKeyOn(PianoKey * key,int vel)349 void PianoScene::showKeyOn( PianoKey* key, int vel )
350 {
351 setHighlightColorFromPolicy(key, vel);
352 displayKeyOn(key);
353 }
354
355 /**
356 * Displays as deactivated a key
357 * @param key the deactivated key
358 * @param vel the MIDI note velocity
359 */
showKeyOff(PianoKey * key,int vel)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
374 /**
375 * Displays highlighted the corresponding key for a given MIDI note, with a color and MIDI velocity
376 * @param note The MIDI note number
377 * @param color The highlight color
378 * @param vel The MIDI note velocity
379 */
showNoteOn(const int note,QColor color,int vel)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
388 /**
389 * Displays highlighted the corresponding key for a given MIDI note, with MIDI velocity
390 * @param note The MIDI note number
391 * @param vel The MIDI note velocity
392 */
showNoteOn(const int note,int vel)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
402 /**
403 * Displays deactivated the corresponding key for a given MIDI note, with MIDI velocity
404 * @param note The MIDI note number
405 * @param vel The MIDI note velocity
406 */
showNoteOff(const int note,int vel)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
415 /**
416 * Returns the base octave number.
417 * @see setBaseOctave()
418 * @return the base octave number
419 */
baseOctave() const420 int PianoScene::baseOctave() const { return d->m_baseOctave; }
421
422 /**
423 * Performs a Note On MIDI event for the given MIDI note number and velocity.
424 * If a PianoHandler instance is assigned, its PianoHandler::noteOn() method is called,
425 * otherwise the noteOn() signal is triggered.
426 * @param note The MIDI note number
427 * @param vel The MIDI velocity
428 */
triggerNoteOn(const int note,const int vel)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
441 /**
442 * Performs a Note Off MIDI event for the given MIDI note number and velocity.
443 * If a PianoHandler instance is assigned, its PianoHandler::noteOff() method is called,
444 * otherwise the noteOff() signal is triggered.
445 * @param note The MIDI note number
446 * @param vel The MIDI velocity
447 */
triggerNoteOff(const int note,const int vel)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
460 /**
461 * Assigns to the given key the highlight color from the active highlight palette
462 * and the given MIDI velocity.
463 * @param key The given piano key
464 * @param vel The MIDI note velocity
465 */
setHighlightColorFromPolicy(PianoKey * key,int vel)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
496 /**
497 * Produces a MIDI Note On event and highlights the given key
498 * @param key The given key
499 */
keyOn(PianoKey * key)500 void PianoScene::keyOn( PianoKey* key )
501 {
502 triggerNoteOn(key->getNote(), d->m_velocity);
503 showKeyOn(key, d->m_velocity);
504 }
505
506 /**
507 * Produces a MIDI Note Off event and deactivates the given key
508 * @param key The given key
509 */
keyOff(PianoKey * key)510 void PianoScene::keyOff( PianoKey* key )
511 {
512 triggerNoteOff(key->getNote(), 0);
513 showKeyOff(key, 0);
514 }
515
516 /**
517 * Produces a MIDI Note On event and highlights the given key with the given pressure
518 * @param key The given key
519 * @param pressure The applied pressure
520 */
keyOn(PianoKey * key,qreal pressure)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
528 /**
529 * Produces a MIDI Note Off event and deactivates the given key with the given pressure.
530 * @param key The given key
531 * @param pressure The applied pressure
532 */
keyOff(PianoKey * key,qreal pressure)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
540 /**
541 * Produces a MIDI Note On event and highlights the corresponding key for the given MIDI note number.
542 * @param note The given MIDI note number
543 */
keyOn(const int note)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
552 /**
553 * Produces a MIDI Note Off event and deactivates the corresponding key for the given MIDI note number.
554 * @param note The given MIDI note number
555 */
keyOff(const int note)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
564 /**
565 * Returns whether the low level computer keyboard mode is enabled.
566 * @return true if the low level computer keyboard mode is enabled
567 */
getRawKeyboardMode() const568 bool PianoScene::getRawKeyboardMode() const
569 {
570 return d->m_rawkbd;
571 }
572
573 /**
574 * Returns the piano key for the given scene point coordenates.
575 * @param p The given scene point coordenates
576 * @return
577 */
getKeyForPos(const QPointF & p) const578 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
590 /**
591 * This event handler, for event mouseEvent, is reimplemented to receive mouse move events for the scene.
592 * @param mouseEvent The mouse move event object pointer
593 */
mouseMoveEvent(QGraphicsSceneMouseEvent * mouseEvent)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
612 /**
613 * This event handler, for event mouseEvent, is reimplemented to receive mouse press events for the scene.
614 * @param mouseEvent The mouse press event object pointer
615 */
mousePressEvent(QGraphicsSceneMouseEvent * mouseEvent)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
629 /**
630 * This event handler, for event mouseEvent, is reimplemented to receive mouse release events for the scene.
631 * @param mouseEvent The mouse release event object pointer
632 */
mouseReleaseEvent(QGraphicsSceneMouseEvent * mouseEvent)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
646 /**
647 * Returns the note number for the given computer keyboard key code.
648 * @param key The given computer keyboard key code
649 * @return The note number
650 */
getNoteFromKey(const int key) const651 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
663 /**
664 * Returns the piano key object corresponding to the given computer keyboard key.
665 * @param key The given computer keyboard key
666 * @return The Piano Key object pointer
667 */
getPianoKey(const int key) const668 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
676 /**
677 * This event handler, for event keyEvent, is reimplemented to receive keypress events.
678 * @param keyEvent The computer keyboard pressed event
679 */
keyPressEvent(QKeyEvent * keyEvent)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
694 /**
695 * This event handler, for event keyEvent, is reimplemented to receive key release events.
696 * @param keyEvent The computer keyboard released event
697 */
keyReleaseEvent(QKeyEvent * keyEvent)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
712 /**
713 * Processes touch screen events
714 * @param event The given event
715 * @return true if the event was processed
716 */
event(QEvent * event)717 bool PianoScene::event(QEvent *event)
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
803 /**
804 * Deactivates all keys.
805 */
allKeysOff()806 void PianoScene::allKeysOff()
807 {
808 foreach(PianoKey* key, d->m_keys) {
809 key->setPressed(false);
810 }
811 }
812
813 /**
814 * Assigns a single color for key highlight. This is an alternative to creating a
815 * highlight palette with a single color and assigning it.
816 * @see setHighlightPalette()
817 * @param color Color for key highlight
818 */
setKeyPressedColor(const QColor & color)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
831 /**
832 * Assigns the default highlight palette colors and assigns it to the scene.
833 */
resetKeyPressedColor()834 void PianoScene::resetKeyPressedColor()
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
843 /**
844 * Returns the minimum MIDI note number that will be displayed.
845 * @return the minimum MIDI note number
846 */
getMinNote() const847 int PianoScene::getMinNote() const
848 {
849 return d->m_minNote;
850 }
851
852 /**
853 * Hides or shows keys
854 */
hideOrShowKeys()855 void PianoScene::hideOrShowKeys()
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
864 /**
865 * Assigns the minimum MIDI note number that will be displayed.
866 * @param note the minimum MIDI note number
867 */
setMinNote(const int note)868 void PianoScene::setMinNote(const int note)
869 {
870 if (d->m_minNote != note) {
871 d->m_minNote = note;
872 hideOrShowKeys();
873 }
874 }
875
876 /**
877 * Returns the maximum MIDI note number that will be displayed.
878 * @return the maximum MIDI note number
879 */
getMaxNote() const880 int PianoScene::getMaxNote() const
881 {
882 return d->m_maxNote;
883 }
884
885 /**
886 * Assigns the maximum MIDI note number that will be displayed.
887 * @param note the maximum MIDI note number
888 */
setMaxNote(const int note)889 void PianoScene::setMaxNote(const int note)
890 {
891 if (d->m_maxNote != note) {
892 d->m_maxNote = note;
893 hideOrShowKeys();
894 }
895 }
896
897 /**
898 * Returns the transpose amount in semitones.
899 * @return the transpose amount in semitones
900 */
getTranspose() const901 int PianoScene::getTranspose() const
902 {
903 return d->m_transpose;
904 }
905
906 /**
907 * Assigns the octave base number
908 * @param base the octave base number
909 */
setBaseOctave(const int base)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
919 /**
920 * Returns the number of keys that will be displayed.
921 * @return the number of keys
922 */
numKeys() const923 int PianoScene::numKeys() const
924 {
925 return d->m_numKeys;
926 }
927
928 /**
929 * Returns the first key number that will be displayed.
930 * @return the first key number
931 */
startKey() const932 int PianoScene::startKey() const
933 {
934 return d->m_startKey;
935 }
936
937 /**
938 * Returns whether the given note number is a octave startup note
939 * @param note The given note number
940 * @return true if the given note number is a octave startup note
941 */
isOctaveStart(const int note)942 bool PianoScene::isOctaveStart(const int note)
943 {
944 return (note + d->m_transpose + 12) % 12 == 0;
945 }
946
947 /**
948 * Returns the note name string that will be displayed over a given piano key.
949 * @param key The given piano key
950 * @return the note name string
951 */
noteName(PianoKey * key)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
1002 /**
1003 * Refresh the visibility and other attributes of the labels shown over the piano keys.
1004 */
refreshLabels()1005 void PianoScene::refreshLabels()
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
1022 /**
1023 * Refresh the background colors of all the piano keys
1024 */
refreshKeys()1025 void PianoScene::refreshKeys()
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
1038 /**
1039 * Assigns the label visibility policy to the piano keys
1040 * @see LabelVisibility
1041 * @param show the new label visibility policy
1042 */
setShowLabels(const LabelVisibility show)1043 void PianoScene::setShowLabels(const LabelVisibility show)
1044 {
1045 //qDebug() << Q_FUNC_INFO << show;
1046 if (d->m_showLabels != show) {
1047 d->m_showLabels = show;
1048 refreshLabels();
1049 }
1050 }
1051
1052 /**
1053 * Returns the alterations name policy.
1054 * @see LabelAlteration, setAlterations()
1055 * @return the alterations name policy
1056 */
alterations() const1057 LabelAlteration PianoScene::alterations() const
1058 {
1059 return d->m_alterations;
1060 }
1061
1062 /**
1063 * Assigns the alterations name policy
1064 * @see LabelAlteration, alterations()
1065 * @param use the new alterations name policy
1066 */
setAlterations(const LabelAlteration use)1067 void PianoScene::setAlterations(const LabelAlteration use)
1068 {
1069 if (d->m_alterations != use) {
1070 d->m_alterations = use;
1071 refreshLabels();
1072 }
1073 }
1074
1075 /**
1076 * Returns the central octave name policy.
1077 * @return the central octave name policy
1078 */
getOctave() const1079 LabelCentralOctave PianoScene::getOctave() const
1080 {
1081 return d->m_octave;
1082 }
1083
1084 /**
1085 * Assigns the label orientation policy.
1086 * @param orientation the label orientation policy
1087 */
setOrientation(const LabelOrientation orientation)1088 void PianoScene::setOrientation(const LabelOrientation orientation)
1089 {
1090 if (d->m_orientation != orientation) {
1091 d->m_orientation = orientation;
1092 refreshLabels();
1093 }
1094 }
1095
isKeyboardEnabled() const1096 bool PianoScene::isKeyboardEnabled() const
1097 {
1098 return d->m_keyboardEnabled;
1099 }
1100
setOctave(const LabelCentralOctave octave)1101 void PianoScene::setOctave(const LabelCentralOctave octave)
1102 {
1103 if (d->m_octave != octave) {
1104 d->m_octave = octave;
1105 refreshLabels();
1106 }
1107 }
1108
getOrientation() const1109 LabelOrientation PianoScene::getOrientation() const
1110 {
1111 return d->m_orientation;
1112 }
1113
1114 /**
1115 * Assigns the transpose amount in semitones.
1116 * @param transpose the transpose amount in semitones
1117 */
setTranspose(const int transpose)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
1127 /**
1128 * Returns the label visibility policy (display note names over the piano keys).
1129 * @see LabelVisibility, setShowLabels()
1130 * @return the label visibility policy
1131 */
showLabels() const1132 LabelVisibility PianoScene::showLabels() const
1133 {
1134 return d->m_showLabels;
1135 }
1136
1137 /**
1138 * Assigns the low level computer keyboard mode.
1139 * @param b the low level computer keyboard mode
1140 */
setRawKeyboardMode(bool b)1141 void PianoScene::setRawKeyboardMode(bool b)
1142 {
1143 if (d->m_rawkbd != b) {
1144 d->m_rawkbd = b;
1145 }
1146 }
1147
1148 /**
1149 * Returns the custom note names list.
1150 * @return the custom note names list
1151 */
customNoteNames() const1152 QStringList PianoScene::customNoteNames() const
1153 {
1154 return d->m_noteNames;
1155 }
1156
1157 /**
1158 * Returns the standard note names list.
1159 * @return the standard note names list
1160 */
standardNoteNames() const1161 QStringList PianoScene::standardNoteNames() const
1162 {
1163 return d->m_names_s;
1164 }
1165
1166 /**
1167 * Returns the MIDI note velocity parameter that is assigned to the MIDI OUT notes.
1168 * @return the MIDI note velocity
1169 */
getVelocity()1170 int PianoScene::getVelocity()
1171 {
1172 return d->m_velocity;
1173 }
1174
1175 /**
1176 * Assigns the MIDI note velocity parameter that is assigned to the MIDI OUT notes.
1177 * @param velocity the MIDI note velocity
1178 */
setVelocity(const int velocity)1179 void PianoScene::setVelocity(const int velocity)
1180 {
1181 d->m_velocity = velocity;
1182 }
1183
1184 /**
1185 * Returns the MIDI channel that is assigned to the output events, or used to filter
1186 * the input events (unless MIDI OMNI mode is enabled).
1187 * @return the MIDI channel
1188 */
getChannel() const1189 int PianoScene::getChannel() const
1190 {
1191 return d->m_channel;
1192 }
1193
1194 /**
1195 * Assigns the MIDI channel that is included into the output events, or used to filter
1196 * the input events (unless MIDI OMNI mode is enabled).
1197 * @param channel the MIDI channel
1198 */
setChannel(const int channel)1199 void PianoScene::setChannel(const int channel)
1200 {
1201 d->m_channel = channel;
1202 }
1203
1204 /**
1205 * Assigns the list of custom note names, and enables this mode.
1206 * @param names the list of custom note names
1207 */
useCustomNoteNames(const QStringList & names)1208 void PianoScene::useCustomNoteNames(const QStringList& names)
1209 {
1210 //qDebug() << Q_FUNC_INFO << names;
1211 d->m_noteNames = names;
1212 refreshLabels();
1213 }
1214
1215 /**
1216 * Assigns the standard note names, clearing the list of custom note names.
1217 */
useStandardNoteNames()1218 void PianoScene::useStandardNoteNames()
1219 {
1220 //qDebug() << Q_FUNC_INFO;
1221 d->m_noteNames.clear();
1222 refreshLabels();
1223 }
1224
1225 /**
1226 * Enables or disables the computer keyboard note generation.
1227 * @param enable the computer keyboard note generation
1228 */
setKeyboardEnabled(const bool enable)1229 void PianoScene::setKeyboardEnabled(const bool enable)
1230 {
1231 if (enable != d->m_keyboardEnabled) {
1232 d->m_keyboardEnabled = enable;
1233 }
1234 }
1235
1236 /**
1237 * Returns whether the computer keyboard note generation is enabled
1238 * @return true if the computer keyboard note generation is enabled
1239 */
isMouseEnabled() const1240 bool PianoScene::isMouseEnabled() const
1241 {
1242 return d->m_mouseEnabled;
1243 }
1244
1245 /**
1246 * Enables or disables the mouse note generation.
1247 * @param enable the mouse note generation
1248 */
setMouseEnabled(const bool enable)1249 void PianoScene::setMouseEnabled(const bool enable)
1250 {
1251 if (enable != d->m_mouseEnabled) {
1252 d->m_mouseEnabled = enable;
1253 }
1254 }
1255
1256 /**
1257 * Returns whether the touch screen note generation is enabled.
1258 * @return true if the touch screen note generation is enabled
1259 */
isTouchEnabled() const1260 bool PianoScene::isTouchEnabled() const
1261 {
1262 return d->m_touchEnabled;
1263 }
1264
1265 /**
1266 * Enables or disables the touch screen note generation.
1267 * @param enable the touch screen note generation
1268 */
setTouchEnabled(const bool enable)1269 void PianoScene::setTouchEnabled(const bool enable)
1270 {
1271 if (enable != d->m_touchEnabled) {
1272 d->m_touchEnabled = enable;
1273 }
1274 }
1275
1276 /**
1277 * Returns whether the velocity parameter of note events is used to influence the highlight key colors.
1278 * @return whether the velocity parameter of note events is used to influence the highlight key colors
1279 */
velocityTint() const1280 bool PianoScene::velocityTint() const
1281 {
1282 return d->m_velocityTint;
1283 }
1284
1285 /**
1286 * Enables or disables the velocity parameter of note events to influence the highlight key colors.
1287 * @param enable the velocity parameter of note events to influence the highlight key colors
1288 */
setVelocityTint(const bool enable)1289 void PianoScene::setVelocityTint(const bool enable)
1290 {
1291 //qDebug() << Q_FUNC_INFO << enable;
1292 d->m_velocityTint = enable;
1293 }
1294
1295 /**
1296 * Retranslates the standard note names
1297 */
retranslate()1298 void PianoScene::retranslate()
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
1329 /**
1330 * Enables or disables the color scale key background mode.
1331 * @param show the color scale key background mode
1332 */
setShowColorScale(const bool show)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
1342 /**
1343 * Returns the single highlight palette color.
1344 * @return the single highlight palette color
1345 */
getKeyPressedColor() const1346 QColor PianoScene::getKeyPressedColor() const
1347 {
1348 return d->m_hilightPalette.getColor(0);
1349 }
1350
1351 /**
1352 * Assigns the active highlight palette.
1353 * @param p the active highlight palette
1354 */
setHighlightPalette(const PianoPalette & p)1355 void PianoScene::setHighlightPalette( const PianoPalette& p )
1356 {
1357 if (d->m_hilightPalette != p) {
1358 d->m_hilightPalette = p;
1359 refreshKeys();
1360 invalidate();
1361 }
1362 }
1363
1364 /**
1365 * Returns the background palette.
1366 * @return the background palette
1367 */
getBackgroundPalette()1368 PianoPalette PianoScene::getBackgroundPalette()
1369 {
1370 return d->m_backgroundPalette;
1371 }
1372
1373 /**
1374 * Assigns the active background palette.
1375 * @param p the active background palette
1376 */
setBackgroundPalette(const PianoPalette & p)1377 void PianoScene::setBackgroundPalette(const PianoPalette& p )
1378 {
1379 if (d->m_backgroundPalette != p) {
1380 d->m_backgroundPalette = p;
1381 refreshKeys();
1382 invalidate();
1383 }
1384 }
1385
1386 /**
1387 * Returns the active foreground palette.
1388 * @return the active foreground palette
1389 */
getForegroundPalette()1390 PianoPalette PianoScene::getForegroundPalette()
1391 {
1392 return d->m_foregroundPalette;
1393 }
1394
1395 /**
1396 * Assigns the active foreground palette.
1397 * @param p the foreground palette
1398 */
setForegroundPalette(const PianoPalette & p)1399 void PianoScene::setForegroundPalette(const PianoPalette &p)
1400 {
1401 if (d->m_foregroundPalette != p) {
1402 d->m_foregroundPalette = p;
1403 refreshLabels();
1404 invalidate();
1405 }
1406 }
1407
1408 /**
1409 * Returns whether the color scale mode is enabled.
1410 * @return true if the color scale mode is enabled
1411 */
showColorScale() const1412 bool PianoScene::showColorScale() const
1413 {
1414 return d->m_showColorScale;
1415 }
1416
setKeyPicture(const bool natural,const QPixmap & pix)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
getKeyPicture(const bool natural)1427 QPixmap PianoScene::getKeyPicture(const bool natural)
1428 {
1429 return d->m_keyPix[int(natural)];
1430 }
1431
setUseKeyPictures(const bool enable)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
getUseKeyPictures() const1440 bool PianoScene::getUseKeyPictures() const
1441 {
1442 return d->m_useKeyPix;
1443 }
1444
saveData(QByteArray & ba)1445 void PianoScene::saveData(QByteArray &ba)
1446 {
1447 d->saveData(ba);
1448 }
1449
loadData(QByteArray & ba)1450 void PianoScene::loadData(QByteArray &ba)
1451 {
1452 d->loadData(ba);
1453 }
1454
1455 } // namespace widgets
1456 } // namespace drumstick
1457