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 #ifndef PIANOKEYBD_H
20 #define PIANOKEYBD_H
21 
22 #include <QGraphicsView>
23 #include <QScopedPointer>
24 #include <QGraphicsScene>
25 #include "macros.h"
26 #include "pianopalette.h"
27 
28 /**
29  * @file pianokeybd.h
30  * Piano Keyboard Widget
31  */
32 
33 namespace drumstick { namespace widgets {
34 
35     /**
36      * @addtogroup Widgets
37      * @{
38      *
39      * @class RawKbdHandler
40      * @brief The RawKbdHandler class callbacks
41      *
42      * RawKbdHandler provides callbacks for low level computer keyboard events
43      */
44     class RawKbdHandler {
45     public:
46         virtual ~RawKbdHandler() = default;
47         /**
48          * @brief handleKeyPressed handles low level computer keyboard press events
49          * @param keycode The low level key code pressed
50          * @return whether the event has been processed or not
51          */
52         virtual bool handleKeyPressed(int keycode) = 0;
53         /**
54          * @brief handleKeyReleased handles low level computer keyboard reelase events
55          * @param keycode The low level key code released
56          * @return whether the event has been processed or not
57          */
58         virtual bool handleKeyReleased(int keycode) = 0;
59     };
60 
61     /**
62      * @brief The PianoHandler class callbacks
63      *
64      * This class provides handler methods for note events. This class must be
65      * inherited and implemented by a program using also PianoKeybd to receive the
66      * note events generated from a computer keyboard, mouse or touch events. It is
67      * provided using the method @ref PianoKeybd::setPianoHandler() and can be retrieved
68      * using @ref PianoKeybd::getPianoHandler(). This mechanism is an option alternative
69      * to proces signals @ref PianoKeybd::noteOn() and @ref PianoKeybd::noteOff() .
70      */
71     class PianoHandler
72     {
73     public:
74         virtual ~PianoHandler() = default;
75         /**
76          * @brief noteOn handles MIDI note on events
77          * @param note MIDI note number
78          * @param vel MIDI velocity
79          */
80         virtual void noteOn( const int note, const int vel ) = 0;
81         /**
82          * @brief noteOff handles MIDI note off events
83          * @param note MIDI note number
84          * @param vel MIDI velocity
85          */
86         virtual void noteOff( const int note, const int vel ) = 0;
87     };
88 
89     /**
90      * @brief KeyboardMap
91      *
92      * KeyboardMap represents a mapping definition to translate from
93      * computer keyboard keys and MIDI notes, either for alphanumeric
94      * or low level (raw) events.
95      */
96     typedef QHash<int, int> KeyboardMap;
97 
98     extern DRUMSTICK_EXPORT KeyboardMap g_DefaultKeyMap;    ///< Global Key Map Variable
99     extern DRUMSTICK_EXPORT KeyboardMap g_DefaultRawKeyMap; ///< Global Raw Key Map Variable
100 
101     const int DEFAULTSTARTINGKEY = 9;   ///< Default starting key (A)
102     const int DEFAULTBASEOCTAVE = 1;    ///< Default base octave
103     const int DEFAULTNUMBEROFKEYS = 88; ///< Default number of piano keys
104 
105     /**
106      * @brief Labels Visibility
107      */
108     enum LabelVisibility {
109         ShowNever,          ///< Don't show note names
110         ShowMinimum,        ///< Show only note C names
111         ShowActivated,      ///< Show names when notes are activated
112         ShowAlways          ///< Show always note names
113     };
114 
115     /**
116      * @brief Labels for Alterations
117      */
118     enum LabelAlteration {
119         ShowSharps,         ///< Show sharps on black keys
120         ShowFlats,          ///< Show flats on black keys
121         ShowNothing         ///< Do not show names on black keys
122     };
123 
124     /**
125      * @brief Labels Orientation
126      */
127     enum LabelOrientation {
128         HorizontalOrientation,  ///< Show horizontal names
129         VerticalOrientation,    ///< Show vertical names
130         AutomaticOrientation    ///< Show horizonal or vertical names depending on the size
131     };
132 
133     /**
134      * @brief Labels Naming
135      */
136     enum LabelNaming {
137         StandardNames,          ///< Show standard names
138         CustomNamesWithSharps,  ///< Show custom names with sharps
139         CustomNamesWithFlats    ///< Show custom names with flats
140     };
141 
142     /**
143      * @brief Labels Central Octave
144      */
145     enum LabelCentralOctave {
146         OctaveNothing = -1,     ///< Don't show octave numbers
147         OctaveC3,               ///< Central C, MIDI note #60 is C3
148         OctaveC4,               ///< Central C, MIDI note #60 is C4
149         OctaveC5                ///< Central C, MIDI note #60 is C5
150     };
151 
152     /**
153      * @brief The PianoKeybd class
154      *
155      * This class is a widget providing the look and behavior of a musical piano keyboard.
156      * It is implemented as a QGraphicsView displaying the contents of a QGraphicsScene (PianoScene).
157      */
158     class DRUMSTICK_EXPORT PianoKeybd : public QGraphicsView, public RawKbdHandler
159     {
160         Q_OBJECT
161         Q_PROPERTY( int baseOctave READ baseOctave WRITE setBaseOctave )
162         Q_PROPERTY( int numKeys READ numKeys WRITE setNumKeys )
163         Q_PROPERTY( int rotation READ getRotation WRITE setRotation )
164         Q_PROPERTY( QColor keyPressedColor READ getKeyPressedColor WRITE setKeyPressedColor )
165         Q_PROPERTY( LabelVisibility showLabels READ showLabels WRITE setShowLabels )
166         Q_PROPERTY( LabelAlteration alterations READ labelAlterations WRITE setLabelAlterations )
167         Q_PROPERTY( LabelOrientation labelOrientation READ labelOrientation WRITE setLabelOrientation )
168         Q_PROPERTY( LabelCentralOctave labelOctave READ labelOctave WRITE setLabelOctave )
169         Q_PROPERTY( int transpose READ getTranspose WRITE setTranspose )
170 
171 #ifndef Q_MOC_RUN
172         Q_CLASSINFO("Author", "Pedro Lopez-Cabanillas <plcl@users.sf.net>")
173         Q_CLASSINFO("URL", "https://sourceforge.net/projects/drumstick")
174         Q_CLASSINFO("Version", QT_STRINGIFY(VERSION))
175 #endif
176 
177     public:
178         explicit PianoKeybd(QWidget *parent = nullptr);
179         PianoKeybd(const int baseOctave, const int numKeys, const int startKey, QWidget *parent = nullptr);
180         virtual ~PianoKeybd();
181 
182         Q_ENUM(LabelVisibility);
183         Q_ENUM(LabelAlteration);
184         Q_ENUM(LabelOrientation);
185         Q_ENUM(LabelNaming);
186         Q_ENUM(LabelCentralOctave);
187 
188         void setFont(const QFont &font);
189         PianoHandler* getPianoHandler() const;
190         void setPianoHandler(PianoHandler* handler);
191 
192         PianoPalette getHighlightPalette() const;
193         void setHighlightPalette(const PianoPalette& p );
194         PianoPalette getBackgroundPalette() const;
195         void setBackgroundPalette(const PianoPalette& p );
196         PianoPalette getForegroundPalette() const;
197         void setForegroundPalette(const PianoPalette& p );
198 
199         bool showColorScale() const;
200         void setShowColorScale(const bool show);
201 
202         void useCustomNoteNames(const QStringList& names);
203         void useStandardNoteNames();
204         QStringList customNoteNames() const;
205         QStringList standardNoteNames() const;
206         void retranslate();
207 
208         int baseOctave() const;
209         void setBaseOctave(const int baseOctave);
210         int numKeys() const;
211         int startKey() const;
212         void setNumKeys(const int numKeys, const int startKey = DEFAULTSTARTINGKEY);
213         int getRotation() const;
214         void setRotation(int r);
215         QColor getKeyPressedColor() const;
216         void setKeyPressedColor(const QColor& c);
217         void resetKeyPressedColor();
218         LabelVisibility showLabels() const;
219         void setShowLabels(const LabelVisibility show);
220         LabelAlteration labelAlterations() const;
221         void setLabelAlterations(const LabelAlteration use);
222         LabelOrientation labelOrientation() const;
223         void setLabelOrientation(const LabelOrientation orientation);
224         LabelCentralOctave labelOctave() const;
225         void setLabelOctave(const LabelCentralOctave octave);
226         int getTranspose() const;
227         void setTranspose(int t);
228         int getChannel() const;
229         void setChannel(const int c);
230         int getVelocity() const;
231         void setVelocity(const int v);
232 
233         bool isKeyboardEnabled() const;
234         void setKeyboardEnabled( const bool enable );
235         bool isMouseEnabled() const;
236         void setMouseEnabled( const bool enable );
237         bool isTouchEnabled() const;
238         void setTouchEnabled( const bool enable );
239         bool velocityTint() const ;
240         void setVelocityTint( const bool enable );
241         void allKeysOff();
242 
243         QSize sizeHint() const override;
244         void setKeyboardMap(KeyboardMap* m);
245         KeyboardMap* getKeyboardMap();
246         void resetKeyboardMap();
247         void setRawKeyboardMap(KeyboardMap* m);
248         KeyboardMap* getRawKeyboardMap();
249         void resetRawKeyboardMap();
250         bool getRawKeyboardMode() const;
251         void setRawKeyboardMode(const bool b);
252 
253         void showNoteOn( const int note, QColor color, int vel = -1 );
254         void showNoteOn( const int note, int vel = -1 );
255         void showNoteOff( const int note, int vel = -1 );
256 
257         // RawKbdHandler methods
258         bool handleKeyPressed(int keycode) override;
259         bool handleKeyReleased(int keycode) override;
260 
261         void setKeyPicture(const bool natural, const QPixmap& pix);
262         QPixmap getKeyPicture(const bool natural);
263 
264         void setUseKeyPictures(const bool enable);
265         bool getUseKeyPictures() const;
266 
267     signals:
268         /**
269          * This signal is emitted for each Note On MIDI event created using
270          * the computer keyboard, mouse or touch screen. It is not emitted if
271          * a PianoHandler has been assigned using setPianoHandler().
272          * @param midiNote the MIDI note number
273          * @param vel the MIDI velocity
274          */
275         void noteOn( int midiNote, int vel );
276         /**
277          * This signal is emitted for each Note Off MIDI event created using
278          * the computer keyboard, mouse or touch screen. It is not emitted if
279          * a PianoHandler has been assigned using setPianoHandler().
280          * @param midiNote the MIDI note number
281          * @param vel the MIDI velocity
282          */
283         void noteOff( int midiNote, int vel );
284         /**
285          * signalName is emitted for each note created, and contains a string
286          * with the MIDI note number and the note name for each note on event.
287          * @param name the MIDI note number and name
288          */
289         void signalName( const QString& name );
290 
291     protected:
292         void initialize();
293         void initDefaultMap();
294         void initScene(int base, int num, int ini, const QColor& c = QColor());
295         void resizeEvent(QResizeEvent *event) override;
296 
297     private:
298         class PianoKeybdPrivate;
299         QScopedPointer<PianoKeybdPrivate> d;
300     };
301 
302 /** @} */
303 
304 }} // namespace drumstick::widgets
305 
306 #endif // PIANOKEYBD_H
307