|
- /*
- ==============================================================================
-
- This file is part of the JUCE library.
- Copyright (c) 2022 - Raw Material Software Limited
-
- JUCE is an open source library subject to commercial or open-source
- licensing.
-
- By using JUCE, you agree to the terms of both the JUCE 7 End-User License
- Agreement and JUCE Privacy Policy.
-
- End User License Agreement: www.juce.com/juce-7-licence
- Privacy Policy: www.juce.com/juce-privacy-policy
-
- Or: You may also use this code under the terms of the GPL v3 (see
- www.gnu.org/licenses).
-
- JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
- EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
- DISCLAIMED.
-
- ==============================================================================
- */
-
- namespace juce
- {
-
- //==============================================================================
- /**
- A component that displays a piano keyboard, whose notes can be clicked on.
-
- This component will mimic a physical midi keyboard, showing the current state of
- a MidiKeyboardState object. When the on-screen keys are clicked on, it will play these
- notes by calling the noteOn() and noteOff() methods of its MidiKeyboardState object.
-
- Another feature is that the computer keyboard can also be used to play notes. By
- default it maps the top two rows of a standard qwerty keyboard to the notes, but
- these can be remapped if needed. It will only respond to keypresses when it has
- the keyboard focus, so to disable this feature you can call setWantsKeyboardFocus (false).
-
- The component is also a ChangeBroadcaster, so if you want to be informed when the
- keyboard is scrolled, you can register a ChangeListener for callbacks.
-
- @see MidiKeyboardState
-
- @tags{Audio}
- */
- class JUCE_API MidiKeyboardComponent : public KeyboardComponentBase,
- private MidiKeyboardState::Listener,
- private Timer
- {
- public:
- //==============================================================================
- /** Creates a MidiKeyboardComponent.
-
- @param state the midi keyboard model that this component will represent
- @param orientation whether the keyboard is horizontal or vertical
- */
- MidiKeyboardComponent (MidiKeyboardState& state, Orientation orientation);
-
- /** Destructor. */
- ~MidiKeyboardComponent() override;
-
- //==============================================================================
- /** Changes the velocity used in midi note-on messages that are triggered by clicking
- on the component.
-
- Values are 0 to 1.0, where 1.0 is the heaviest.
-
- @see setMidiChannel
- */
- void setVelocity (float velocity, bool useMousePositionForVelocity);
-
- //==============================================================================
- /** Changes the midi channel number that will be used for events triggered by clicking
- on the component.
-
- The channel must be between 1 and 16 (inclusive). This is the channel that will be
- passed on to the MidiKeyboardState::noteOn() method when the user clicks the component.
-
- Although this is the channel used for outgoing events, the component can display
- incoming events from more than one channel - see setMidiChannelsToDisplay()
-
- @see setVelocity
- */
- void setMidiChannel (int midiChannelNumber);
-
- /** Returns the midi channel that the keyboard is using for midi messages.
- @see setMidiChannel
- */
- int getMidiChannel() const noexcept { return midiChannel; }
-
- /** Sets a mask to indicate which incoming midi channels should be represented by
- key movements.
-
- The mask is a set of bits, where bit 0 = midi channel 1, bit 1 = midi channel 2, etc.
-
- If the MidiKeyboardState has a key down for any of the channels whose bits are set
- in this mask, the on-screen keys will also go down.
-
- By default, this mask is set to 0xffff (all channels displayed).
-
- @see setMidiChannel
- */
- void setMidiChannelsToDisplay (int midiChannelMask);
-
- /** Returns the current set of midi channels represented by the component.
- This is the value that was set with setMidiChannelsToDisplay().
- */
- int getMidiChannelsToDisplay() const noexcept { return midiInChannelMask; }
-
- //==============================================================================
- /** Deletes all key-mappings.
-
- @see setKeyPressForNote
- */
- void clearKeyMappings();
-
- /** Maps a key-press to a given note.
-
- @param key the key that should trigger the note
- @param midiNoteOffsetFromC how many semitones above C the triggered note should
- be. The actual midi note that gets played will be
- this value + (12 * the current base octave). To change
- the base octave, see setKeyPressBaseOctave()
- */
- void setKeyPressForNote (const KeyPress& key, int midiNoteOffsetFromC);
-
- /** Removes any key-mappings for a given note.
-
- For a description of what the note number means, see setKeyPressForNote().
- */
- void removeKeyPressForNote (int midiNoteOffsetFromC);
-
- /** Changes the base note above which key-press-triggered notes are played.
-
- The set of key-mappings that trigger notes can be moved up and down to cover
- the entire scale using this method.
-
- The value passed in is an octave number between 0 and 10 (inclusive), and
- indicates which C is the base note to which the key-mapped notes are
- relative.
- */
- void setKeyPressBaseOctave (int newOctaveNumber);
-
- //==============================================================================
- /** A set of colour IDs to use to change the colour of various aspects of the keyboard.
-
- These constants can be used either via the Component::setColour(), or LookAndFeel::setColour()
- methods.
-
- @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour
- */
- enum ColourIds
- {
- whiteNoteColourId = 0x1005000,
- blackNoteColourId = 0x1005001,
- keySeparatorLineColourId = 0x1005002,
- mouseOverKeyOverlayColourId = 0x1005003, /**< This colour will be overlaid on the normal note colour. */
- keyDownOverlayColourId = 0x1005004, /**< This colour will be overlaid on the normal note colour. */
- textLabelColourId = 0x1005005,
- shadowColourId = 0x1005006
- };
-
- //==============================================================================
- /** Use this method to draw a white note of the keyboard in a given rectangle.
-
- isOver indicates whether the mouse is over the key, isDown indicates whether the key is
- currently pressed down.
-
- When doing this, be sure to note the keyboard's orientation.
- */
- virtual void drawWhiteNote (int midiNoteNumber, Graphics& g, Rectangle<float> area,
- bool isDown, bool isOver, Colour lineColour, Colour textColour);
-
- /** Use this method to draw a black note of the keyboard in a given rectangle.
-
- isOver indicates whether the mouse is over the key, isDown indicates whether the key is
- currently pressed down.
-
- When doing this, be sure to note the keyboard's orientation.
- */
- virtual void drawBlackNote (int midiNoteNumber, Graphics& g, Rectangle<float> area,
- bool isDown, bool isOver, Colour noteFillColour);
-
- /** Callback when the mouse is clicked on a key.
-
- You could use this to do things like handle right-clicks on keys, etc.
-
- Return true if you want the click to trigger the note, or false if you
- want to handle it yourself and not have the note played.
-
- @see mouseDraggedToKey
- */
- virtual bool mouseDownOnKey (int midiNoteNumber, const MouseEvent& e);
-
- /** Callback when the mouse is dragged from one key onto another.
-
- Return true if you want the drag to trigger the new note, or false if you
- want to handle it yourself and not have the note played.
-
- @see mouseDownOnKey
- */
- virtual bool mouseDraggedToKey (int midiNoteNumber, const MouseEvent& e);
-
- /** Callback when the mouse is released from a key.
-
- @see mouseDownOnKey
- */
- virtual void mouseUpOnKey (int midiNoteNumber, const MouseEvent& e);
-
- /** Allows text to be drawn on the white notes.
-
- By default this is used to label the C in each octave, but could be used for other things.
-
- @see setOctaveForMiddleC
- */
- virtual String getWhiteNoteText (int midiNoteNumber);
-
- //==============================================================================
- /** @internal */
- void mouseMove (const MouseEvent&) override;
- /** @internal */
- void mouseDrag (const MouseEvent&) override;
- /** @internal */
- void mouseDown (const MouseEvent&) override;
- /** @internal */
- void mouseUp (const MouseEvent&) override;
- /** @internal */
- void mouseEnter (const MouseEvent&) override;
- /** @internal */
- void mouseExit (const MouseEvent&) override;
- /** @internal */
- void timerCallback() override;
- /** @internal */
- bool keyStateChanged (bool isKeyDown) override;
- /** @internal */
- bool keyPressed (const KeyPress&) override;
- /** @internal */
- void focusLost (FocusChangeType) override;
- /** @internal */
- void colourChanged() override;
-
- private:
- //==============================================================================
- void drawKeyboardBackground (Graphics& g, Rectangle<float> area) override final;
- void drawWhiteKey (int midiNoteNumber, Graphics& g, Rectangle<float> area) override final;
- void drawBlackKey (int midiNoteNumber, Graphics& g, Rectangle<float> area) override final;
-
- void handleNoteOn (MidiKeyboardState*, int, int, float) override;
- void handleNoteOff (MidiKeyboardState*, int, int, float) override;
-
- //==============================================================================
- void resetAnyKeysInUse();
- void updateNoteUnderMouse (Point<float>, bool isDown, int fingerNum);
- void updateNoteUnderMouse (const MouseEvent&, bool isDown);
- void repaintNote (int midiNoteNumber);
-
- //==============================================================================
- MidiKeyboardState& state;
- int midiChannel = 1, midiInChannelMask = 0xffff;
- int keyMappingOctave = 6;
-
- float velocity = 1.0f;
- bool useMousePositionForVelocity = true;
-
- Array<int> mouseOverNotes, mouseDownNotes;
- Array<KeyPress> keyPresses;
- Array<int> keyPressNotes;
- BigInteger keysPressed, keysCurrentlyDrawnDown;
-
- std::atomic<bool> noPendingUpdates { true };
-
- //==============================================================================
- JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiKeyboardComponent)
- };
-
- } // namespace juce
|