38 for (
const char& c : keys)
59 useMousePositionForVelocity = useMousePosition;
65 jassert (midiChannelNumber > 0 && midiChannelNumber <= 16);
67 if (midiChannel != midiChannelNumber)
70 midiChannel =
jlimit (1, 16, midiChannelNumber);
76 midiInChannelMask = midiChannelMask;
77 noPendingUpdates.
store (
false);
84 keyPressNotes.
clear();
92 keyPressNotes.
add (midiNoteOffsetFromC);
98 for (
int i = keyPressNotes.
size(); --i >= 0;)
100 if (keyPressNotes.
getUnchecked (i) == midiNoteOffsetFromC)
103 keyPresses.remove (i);
110 jassert (newOctaveNumber >= 0 && newOctaveNumber <= 10);
112 keyMappingOctave = newOctaveNumber;
116void MidiKeyboardComponent::resetAnyKeysInUse()
118 if (! keysPressed.
isZero())
120 for (
int i = 128; --i >= 0;)
122 state.
noteOff (midiChannel, i, 0.0f);
127 for (
int i = mouseDownNotes.
size(); --i >= 0;)
133 state.
noteOff (midiChannel, noteDown, 0.0f);
134 mouseDownNotes.
set (i, -1);
137 mouseOverNotes.
set (i, -1);
141void MidiKeyboardComponent::updateNoteUnderMouse (
const MouseEvent& e,
bool isDown)
143 updateNoteUnderMouse (e.getEventRelativeTo (
this).position, isDown, e.source.getIndex());
146void MidiKeyboardComponent::updateNoteUnderMouse (Point<float> pos,
bool isDown,
int fingerNum)
149 const auto newNote = noteInfo.note;
150 const auto oldNote = mouseOverNotes.
getUnchecked (fingerNum);
151 const auto oldNoteDown = mouseDownNotes.
getUnchecked (fingerNum);
152 const auto eventVelocity = useMousePositionForVelocity ? noteInfo.velocity * velocity : velocity;
154 if (oldNote != newNote)
156 repaintNote (oldNote);
157 repaintNote (newNote);
158 mouseOverNotes.
set (fingerNum, newNote);
163 if (newNote != oldNoteDown)
165 if (oldNoteDown >= 0)
167 mouseDownNotes.
set (fingerNum, -1);
169 if (! mouseDownNotes.
contains (oldNoteDown))
170 state.
noteOff (midiChannel, oldNoteDown, eventVelocity);
173 if (newNote >= 0 && ! mouseDownNotes.
contains (newNote))
175 state.
noteOn (midiChannel, newNote, eventVelocity);
176 mouseDownNotes.
set (fingerNum, newNote);
180 else if (oldNoteDown >= 0)
182 mouseDownNotes.
set (fingerNum, -1);
184 if (! mouseDownNotes.
contains (oldNoteDown))
185 state.
noteOff (midiChannel, oldNoteDown, eventVelocity);
189void MidiKeyboardComponent::repaintNote (
int noteNum)
198 updateNoteUnderMouse (e,
false);
206 updateNoteUnderMouse (e,
true);
214 updateNoteUnderMouse (e,
true);
219 updateNoteUnderMouse (e,
false);
229 updateNoteUnderMouse (e,
false);
234 updateNoteUnderMouse (e,
false);
239 if (noPendingUpdates.
exchange (
true))
246 if (keysCurrentlyDrawnDown[i] != isOn)
248 keysCurrentlyDrawnDown.
setBit (i, isOn);
256 bool keyPressUsed =
false;
258 for (
int i = keyPresses.size(); --i >= 0;)
260 auto note = 12 * keyMappingOctave + keyPressNotes.
getUnchecked (i);
262 if (keyPresses.getReference (i).isCurrentlyDown())
264 if (! keysPressed[note])
266 keysPressed.
setBit (note);
267 state.
noteOn (midiChannel, note, velocity);
273 if (keysPressed[note])
276 state.
noteOff (midiChannel, note, 0.0f);
287 return keyPresses.contains (key);
305 if (currentOrientation == verticalKeyboardFacingLeft)
307 shadowGradientStart.
x = width - 1.0f;
308 shadowGradientEnd.
x = width - 5.0f;
310 else if (currentOrientation == verticalKeyboardFacingRight)
312 shadowGradientEnd.
x = 5.0f;
316 shadowGradientEnd.
y = 5.0f;
320 auto shadowColour =
findColour (shadowColourId);
322 if (! shadowColour.isTransparent())
325 shadowColour.withAlpha (0.0f), shadowGradientEnd,
328 switch (currentOrientation)
330 case horizontalKeyboard: g.
fillRect (0.0f, 0.0f, keyboardWidth, 5.0f);
break;
331 case verticalKeyboardFacingLeft: g.
fillRect (width - 5.0f, 0.0f, 5.0f, keyboardWidth);
break;
332 case verticalKeyboardFacingRight: g.
fillRect (0.0f, 0.0f, 5.0f, keyboardWidth);
break;
337 auto lineColour =
findColour (keySeparatorLineColourId);
339 if (! lineColour.isTransparent())
343 switch (currentOrientation)
345 case horizontalKeyboard: g.
fillRect (0.0f, height - 1.0f, keyboardWidth, 1.0f);
break;
346 case verticalKeyboardFacingLeft: g.
fillRect (0.0f, 0.0f, 1.0f, keyboardWidth);
break;
347 case verticalKeyboardFacingRight: g.
fillRect (width - 1.0f, 0.0f, 1.0f, keyboardWidth);
break;
354 bool isDown,
bool isOver,
Colour lineColour,
Colour textColour)
356 auto c = Colours::transparentWhite;
368 if (text.isNotEmpty())
373 g.
setFont (
Font (fontHeight).withHorizontalScale (0.8f));
375 switch (currentOrientation)
388 switch (currentOrientation)
398 switch (currentOrientation)
410 bool isDown,
bool isOver,
Colour noteFillColour)
412 auto c = noteFillColour;
428 auto sideIndent = 1.0f / 8.0f;
429 auto topIndent = 7.0f / 8.0f;
445 if (midiNoteNumber % 12 == 0)
464void MidiKeyboardComponent::drawBlackKey (
int midiNoteNumber, Graphics& g, Rectangle<float> area)
471void MidiKeyboardComponent::handleNoteOn (MidiKeyboardState*,
int ,
int ,
float )
473 noPendingUpdates.
store (
false);
476void MidiKeyboardComponent::handleNoteOff (MidiKeyboardState*,
int ,
int ,
float )
478 noPendingUpdates.
store (
false);
ElementType getUnchecked(int index) const
Returns one of the elements in the array, without checking the index passed in.
int size() const noexcept
Returns the current number of elements in the array.
void remove(int indexToRemove)
Removes an element from the array.
void add(const ElementType &newElement)
Appends a new element at the end of the array.
void set(int indexToChange, ParameterType newValue)
Replaces an element with a new value.
bool contains(ParameterType elementToLookFor) const
Returns true if the array contains at least one occurrence of an object.
void insertMultiple(int indexToInsertAt, ParameterType newElement, int numberOfTimesToInsertIt)
Inserts multiple copies of an element into the array at a given position.
void clear()
Removes all elements from the array.
BigInteger & clear() noexcept
Resets the value to 0.
BigInteger & clearBit(int bitNumber) noexcept
Clears a particular bit in the number.
bool isZero() const noexcept
Returns true if no bits are set.
BigInteger & setBit(int bitNumber)
Sets a specified bit to 1.
Represents a colour, also including a transparency value.
bool isTransparent() const noexcept
Returns true if this colour is completely transparent.
Colour overlaidWith(Colour foregroundColour) const noexcept
Returns a colour that is the result of alpha-compositing a new colour over this one.
bool isOpaque() const noexcept
Returns true if no parts of this component are transparent.
FocusChangeType
Enumeration used by the focusGained() and focusLost() methods.
void setOpaque(bool shouldBeOpaque)
Indicates whether any parts of the component might be transparent.
void repaint()
Marks the whole component as needing to be redrawn.
void setWantsKeyboardFocus(bool wantsFocus) noexcept
Sets a flag to indicate whether this component wants keyboard focus or not.
Colour findColour(int colourID, bool inheritFromParent=false) const
Looks for a colour that has been registered with the given colour ID number.
Represents a particular font, including its size, style, etc.
A graphics context, used for drawing a component or image.
void drawText(const String &text, int x, int y, int width, int height, Justification justificationType, bool useEllipsesIfTooBig=true) const
Draws a line of text within a specified rectangle.
void setFont(const Font &newFont)
Changes the font to use for subsequent text-drawing functions.
void setGradientFill(const ColourGradient &gradient)
Sets the context to use a gradient for its fill pattern.
void drawRect(int x, int y, int width, int height, int lineThickness=1) const
Draws a rectangular outline, using the current colour or brush.
void fillRect(Rectangle< int > rectangle) const
Fills a rectangle with the current colour or brush.
void setColour(Colour newColour)
Changes the current drawing colour.
void fillAll() const
Fills the context's entire clip region with the current colour or brush.
@ centredRight
Indicates that the item should be centred vertically but placed on the right hand side.
@ centredBottom
Indicates that the item should be centred horizontally and placed at the bottom.
@ centredLeft
Indicates that the item should be centred vertically but placed on the left hand side.
Represents a key press, including any modifier keys that are needed.
A base class for drawing a custom MIDI keyboard component.
float getKeyWidth() const noexcept
Returns the width that was set by setKeyWidth().
int getRangeStart() const noexcept
Returns the first note in the available range.
int getRangeEnd() const noexcept
Returns the last note in the available range.
Rectangle< float > getRectangleForKey(int midiNoteNumber) const
Returns the rectangle for a given key.
int getOctaveForMiddleC() const noexcept
This returns the value set by setOctaveForMiddleC().
NoteAndVelocity getNoteAndVelocityAtPosition(Point< float > position, bool includeChildComponents=false)
Returns the note number and velocity for a given position within the component.
Orientation getOrientation() const noexcept
Returns the keyboard's current direction.
Orientation
The direction of the keyboard.
virtual void drawWhiteNote(int midiNoteNumber, Graphics &g, Rectangle< float > area, bool isDown, bool isOver, Colour lineColour, Colour textColour)
Use this method to draw a white note of the keyboard in a given rectangle.
void colourChanged() override
This method is called when a colour is changed by the setColour() method, or when the look-and-feel i...
void setMidiChannelsToDisplay(int midiChannelMask)
Sets a mask to indicate which incoming midi channels should be represented by key movements.
virtual bool mouseDownOnKey(int midiNoteNumber, const MouseEvent &e)
Callback when the mouse is clicked on a key.
virtual void mouseUpOnKey(int midiNoteNumber, const MouseEvent &e)
Callback when the mouse is released from a key.
@ keyDownOverlayColourId
This colour will be overlaid on the normal note colour.
@ mouseOverKeyOverlayColourId
This colour will be overlaid on the normal note colour.
void timerCallback() override
The user-defined callback routine that actually gets called periodically.
void setVelocity(float velocity, bool useMousePositionForVelocity)
Changes the velocity used in midi note-on messages that are triggered by clicking on the component.
void setKeyPressForNote(const KeyPress &key, int midiNoteOffsetFromC)
Maps a key-press to a given note.
void mouseEnter(const MouseEvent &) override
Called when the mouse first enters a component.
bool keyPressed(const KeyPress &) override
Called when a key is pressed.
void setKeyPressBaseOctave(int newOctaveNumber)
Changes the base note above which key-press-triggered notes are played.
void mouseDown(const MouseEvent &) override
Called when a mouse button is pressed.
MidiKeyboardComponent(MidiKeyboardState &state, Orientation orientation)
Creates a MidiKeyboardComponent.
virtual void drawBlackNote(int midiNoteNumber, Graphics &g, Rectangle< float > area, bool isDown, bool isOver, Colour noteFillColour)
Use this method to draw a black note of the keyboard in a given rectangle.
~MidiKeyboardComponent() override
Destructor.
void mouseExit(const MouseEvent &) override
Called when the mouse moves out of a component.
void mouseMove(const MouseEvent &) override
Called when the mouse moves inside a component.
virtual String getWhiteNoteText(int midiNoteNumber)
Allows text to be drawn on the white notes.
virtual bool mouseDraggedToKey(int midiNoteNumber, const MouseEvent &e)
Callback when the mouse is dragged from one key onto another.
bool keyStateChanged(bool isKeyDown) override
Called when a key is pressed or released.
void mouseUp(const MouseEvent &) override
Called when a mouse button is released.
void mouseDrag(const MouseEvent &) override
Called when the mouse is moved while a button is held down.
void focusLost(FocusChangeType) override
Called to indicate that this component has just lost the keyboard focus.
void setMidiChannel(int midiChannelNumber)
Changes the midi channel number that will be used for events triggered by clicking on the component.
void removeKeyPressForNote(int midiNoteOffsetFromC)
Removes any key-mappings for a given note.
void clearKeyMappings()
Deletes all key-mappings.
Represents a piano keyboard, keeping track of which keys are currently pressed.
void addListener(Listener *listener)
Registers a listener for callbacks when keys go up or down.
void noteOff(int midiChannel, int midiNoteNumber, float velocity)
Turns a specified note off.
void removeListener(Listener *listener)
Deregisters a listener.
void noteOn(int midiChannel, int midiNoteNumber, float velocity)
Turns a specified note on.
bool isNoteOnForChannels(int midiChannelMask, int midiNoteNumber) const noexcept
Returns true if the given midi key is currently held down on any of a set of midi channels.
static String getMidiNoteName(int noteNumber, bool useSharps, bool includeOctaveNumber, int octaveNumForMiddleC)
Returns the name of a midi note number.
Contains position and status information about a mouse event.
const Point< float > position
The position of the mouse when the event occurred.
A pair of (x, y) coordinates.
ValueType y
The point's Y coordinate.
ValueType x
The point's X coordinate.
Manages a rectangle and allows geometric operations to be performed on it.
ValueType getRight() const noexcept
Returns the x coordinate of the rectangle's right-hand-side.
Rectangle withHeight(ValueType newHeight) const noexcept
Returns a rectangle which has the same position and width as this one, but with a different height.
Rectangle removeFromRight(ValueType amountToRemove) noexcept
Removes a strip from the right-hand edge of this rectangle, reducing this rectangle by the specified ...
Rectangle removeFromBottom(ValueType amountToRemove) noexcept
Removes a strip from the bottom of this rectangle, reducing this rectangle by the specified amount an...
ValueType getWidth() const noexcept
Returns the width of the rectangle.
Rectangle removeFromTop(ValueType amountToRemove) noexcept
Removes a strip from the top of this rectangle, reducing this rectangle by the specified amount and r...
Rectangle reduced(ValueType deltaX, ValueType deltaY) const noexcept
Returns a rectangle that is smaller than this one by a given amount.
Rectangle removeFromLeft(ValueType amountToRemove) noexcept
Removes a strip from the left-hand edge of this rectangle, reducing this rectangle by the specified a...
Rectangle withTrimmedLeft(ValueType amountToRemove) const noexcept
Returns a version of this rectangle with the given amount removed from its left-hand edge.
Rectangle withWidth(ValueType newWidth) const noexcept
Returns a rectangle which has the same position and height as this one, but with a different width.
ValueType getHeight() const noexcept
Returns the height of the rectangle.
Rectangle withTrimmedBottom(ValueType amountToRemove) const noexcept
Returns a version of this rectangle with the given amount removed from its bottom edge.
Rectangle expanded(ValueType deltaX, ValueType deltaY) const noexcept
Returns a rectangle that is larger than this one by a given amount.
void startTimerHz(int timerFrequencyHz) noexcept
Starts the timer with an interval specified in Hertz.
constexpr Type jmin(Type a, Type b)
Returns the smaller of two values.
Type jlimit(Type lowerLimit, Type upperLimit, Type valueToConstrain) noexcept
Constrains a value to keep it within a given range.