mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
288 lines
12 KiB
C++
288 lines
12 KiB
C++
/*
|
|
==============================================================================
|
|
|
|
This file is part of the JUCE framework.
|
|
Copyright (c) Raw Material Software Limited
|
|
|
|
JUCE is an open source framework subject to commercial or open source
|
|
licensing.
|
|
|
|
By downloading, installing, or using the JUCE framework, or combining the
|
|
JUCE framework with any other source code, object code, content or any other
|
|
copyrightable work, you agree to the terms of the JUCE End User Licence
|
|
Agreement, and all incorporated terms including the JUCE Privacy Policy and
|
|
the JUCE Website Terms of Service, as applicable, which will bind you. If you
|
|
do not agree to the terms of these agreements, we will not license the JUCE
|
|
framework to you, and you must discontinue the installation or download
|
|
process and cease use of the JUCE framework.
|
|
|
|
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
|
|
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
|
|
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
|
|
|
|
Or:
|
|
|
|
You may also use this code under the terms of the AGPLv3:
|
|
https://www.gnu.org/licenses/agpl-3.0.en.html
|
|
|
|
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
|
|
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
|
|
MERCHANTABILITY OR FITNESS FOR A PARTICULAR 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
|