From 3dcd918ddd61df32e2ce793af51dc24084a0749f Mon Sep 17 00:00:00 2001 From: jules Date: Tue, 28 Nov 2017 15:45:43 +0000 Subject: [PATCH] Cleaned up MidiKeyboardComponent, changing it to use floating point coords --- .../gui/juce_MidiKeyboardComponent.cpp | 366 ++++++++---------- .../gui/juce_MidiKeyboardComponent.h | 78 ++-- 2 files changed, 197 insertions(+), 247 deletions(-) diff --git a/modules/juce_audio_utils/gui/juce_MidiKeyboardComponent.cpp b/modules/juce_audio_utils/gui/juce_MidiKeyboardComponent.cpp index d6edfe25e3..700469f11d 100644 --- a/modules/juce_audio_utils/gui/juce_MidiKeyboardComponent.cpp +++ b/modules/juce_audio_utils/gui/juce_MidiKeyboardComponent.cpp @@ -27,17 +27,20 @@ namespace juce { -class MidiKeyboardUpDownButton : public Button +static const uint8 whiteNotes[] = { 0, 2, 4, 5, 7, 9, 11 }; +static const uint8 blackNotes[] = { 1, 3, 6, 8, 10 }; + + +struct MidiKeyboardComponent::UpDownButton : public Button { -public: - MidiKeyboardUpDownButton (MidiKeyboardComponent& comp, const int d) - : Button (String()), owner (comp), delta (d) + UpDownButton (MidiKeyboardComponent& c, int d) + : Button ({}), owner (c), delta (d) { } void clicked() override { - int note = owner.getLowestVisibleKey(); + auto note = owner.getLowestVisibleKey(); if (delta < 0) note = (note - 1) / 12; @@ -58,37 +61,21 @@ private: MidiKeyboardComponent& owner; const int delta; - JUCE_DECLARE_NON_COPYABLE (MidiKeyboardUpDownButton) + JUCE_DECLARE_NON_COPYABLE (UpDownButton) }; //============================================================================== MidiKeyboardComponent::MidiKeyboardComponent (MidiKeyboardState& s, Orientation o) - : state (s), - blackNoteLengthRatio (0.7f), - xOffset (0), - keyWidth (16.0f), - orientation (o), - midiChannel (1), - midiInChannelMask (0xffff), - velocity (1.0f), - shouldCheckState (false), - rangeStart (0), - rangeEnd (127), - firstKey (12 * 4.0f), - canScroll (true), - useMousePositionForVelocity (true), - shouldCheckMousePos (false), - keyMappingOctave (6), - octaveNumForMiddleC (3) + : state (s), orientation (o) { - addChildComponent (scrollDown = new MidiKeyboardUpDownButton (*this, -1)); - addChildComponent (scrollUp = new MidiKeyboardUpDownButton (*this, 1)); + addChildComponent (scrollDown = new UpDownButton (*this, -1)); + addChildComponent (scrollUp = new UpDownButton (*this, 1)); // initialise with a default set of qwerty key-mappings.. - const char* const keymap = "awsedftgyhujkolp;"; + int note = 0; - for (int i = 0; keymap[i] != 0; ++i) - setKeyPressForNote (KeyPress (keymap[i], 0, 0), i); + for (char c : "awsedftgyhujkolp;") + setKeyPressForNote (KeyPress (c, 0, 0), note++); mouseOverNotes.insertMultiple (0, -1, 32); mouseDownNotes.insertMultiple (0, -1, 32); @@ -107,7 +94,7 @@ MidiKeyboardComponent::~MidiKeyboardComponent() } //============================================================================== -void MidiKeyboardComponent::setKeyWidth (const float widthInPixels) +void MidiKeyboardComponent::setKeyWidth (float widthInPixels) { jassert (widthInPixels > 0); @@ -118,7 +105,7 @@ void MidiKeyboardComponent::setKeyWidth (const float widthInPixels) } } -void MidiKeyboardComponent::setOrientation (const Orientation newOrientation) +void MidiKeyboardComponent::setOrientation (Orientation newOrientation) { if (orientation != newOrientation) { @@ -127,8 +114,7 @@ void MidiKeyboardComponent::setOrientation (const Orientation newOrientation) } } -void MidiKeyboardComponent::setAvailableRange (const int lowestNote, - const int highestNote) +void MidiKeyboardComponent::setAvailableRange (int lowestNote, int highestNote) { jassert (lowestNote >= 0 && lowestNote <= 127); jassert (highestNote >= 0 && highestNote <= 127); @@ -154,7 +140,7 @@ void MidiKeyboardComponent::setLowestVisibleKeyFloat (float noteNumber) if (noteNumber != firstKey) { - const bool hasMoved = (((int) firstKey) != (int) noteNumber); + bool hasMoved = (((int) firstKey) != (int) noteNumber); firstKey = noteNumber; if (hasMoved) @@ -164,7 +150,7 @@ void MidiKeyboardComponent::setLowestVisibleKeyFloat (float noteNumber) } } -void MidiKeyboardComponent::setScrollButtonsVisible (const bool newCanScroll) +void MidiKeyboardComponent::setScrollButtonsVisible (bool newCanScroll) { if (canScroll != newCanScroll) { @@ -180,7 +166,7 @@ void MidiKeyboardComponent::colourChanged() } //============================================================================== -void MidiKeyboardComponent::setMidiChannel (const int midiChannelNumber) +void MidiKeyboardComponent::setMidiChannel (int midiChannelNumber) { jassert (midiChannelNumber > 0 && midiChannelNumber <= 16); @@ -191,20 +177,20 @@ void MidiKeyboardComponent::setMidiChannel (const int midiChannelNumber) } } -void MidiKeyboardComponent::setMidiChannelsToDisplay (const int midiChannelMask) +void MidiKeyboardComponent::setMidiChannelsToDisplay (int midiChannelMask) { midiInChannelMask = midiChannelMask; shouldCheckState = true; } -void MidiKeyboardComponent::setVelocity (const float v, const bool useMousePosition) +void MidiKeyboardComponent::setVelocity (float v, bool useMousePosition) { velocity = jlimit (0.0f, 1.0f, v); useMousePositionForVelocity = useMousePosition; } //============================================================================== -void MidiKeyboardComponent::getKeyPosition (int midiNoteNumber, const float keyWidth_, int& x, int& w) const +Range MidiKeyboardComponent::getKeyPosition (int midiNoteNumber, float targetKeyWidth) const { jassert (midiNoteNumber >= 0 && midiNoteNumber < 128); @@ -218,39 +204,39 @@ void MidiKeyboardComponent::getKeyPosition (int midiNoteNumber, const float keyW 5.0f, 6 - blackNoteWidth * 0.3f, 6.0f }; - const int octave = midiNoteNumber / 12; - const int note = midiNoteNumber % 12; + auto octave = midiNoteNumber / 12; + auto note = midiNoteNumber % 12; - x = roundToInt (octave * 7.0f * keyWidth_ + notePos [note] * keyWidth_); - w = roundToInt (MidiMessage::isMidiNoteBlack (note) ? blackNoteWidth * keyWidth_ : keyWidth_); + auto start = octave * 7.0f * targetKeyWidth + notePos[note] * targetKeyWidth; + auto width = MidiMessage::isMidiNoteBlack (note) ? blackNoteWidth * targetKeyWidth : targetKeyWidth; + + return { start, start + width }; } -void MidiKeyboardComponent::getKeyPos (int midiNoteNumber, int& x, int& w) const +Range MidiKeyboardComponent::getKeyPos (int midiNoteNumber) const { - getKeyPosition (midiNoteNumber, keyWidth, x, w); - - int rx, rw; - getKeyPosition (rangeStart, keyWidth, rx, rw); - - x -= xOffset + rx; + return getKeyPosition (midiNoteNumber, keyWidth) + - xOffset + - getKeyPosition (rangeStart, keyWidth).getStart(); } -Rectangle MidiKeyboardComponent::getRectangleForKey (const int note) const +Rectangle MidiKeyboardComponent::getRectangleForKey (int note) const { jassert (note >= rangeStart && note <= rangeEnd); - int x, w; - getKeyPos (note, x, w); + auto pos = getKeyPos (note); + auto x = pos.getStart(); + auto w = pos.getLength(); if (MidiMessage::isMidiNoteBlack (note)) { - const int blackNoteLength = getBlackNoteLength(); + auto blackNoteLength = getBlackNoteLength(); switch (orientation) { - case horizontalKeyboard: return Rectangle (x, 0, w, blackNoteLength); - case verticalKeyboardFacingLeft: return Rectangle (getWidth() - blackNoteLength, x, blackNoteLength, w); - case verticalKeyboardFacingRight: return Rectangle (0, getHeight() - x - w, blackNoteLength, w); + case horizontalKeyboard: return { x, 0, w, blackNoteLength }; + case verticalKeyboardFacingLeft: return { getWidth() - blackNoteLength, x, blackNoteLength, w }; + case verticalKeyboardFacingRight: return { 0, getHeight() - x - w, blackNoteLength, w }; default: jassertfalse; break; } } @@ -258,62 +244,55 @@ Rectangle MidiKeyboardComponent::getRectangleForKey (const int note) const { switch (orientation) { - case horizontalKeyboard: return Rectangle (x, 0, w, getHeight()); - case verticalKeyboardFacingLeft: return Rectangle (0, x, getWidth(), w); - case verticalKeyboardFacingRight: return Rectangle (0, getHeight() - x - w, getWidth(), w); + case horizontalKeyboard: return { x, 0, w, (float) getHeight() }; + case verticalKeyboardFacingLeft: return { 0, x, (float) getWidth(), w }; + case verticalKeyboardFacingRight: return { 0, getHeight() - x - w, (float) getWidth(), w }; default: jassertfalse; break; } } - return Rectangle(); + return {}; } -int MidiKeyboardComponent::getKeyStartPosition (const int midiNoteNumber) const +float MidiKeyboardComponent::getKeyStartPosition (int midiNoteNumber) const { - int x, w; - getKeyPos (midiNoteNumber, x, w); - return x; + return getKeyPos (midiNoteNumber).getStart(); } -int MidiKeyboardComponent::getTotalKeyboardWidth() const noexcept +float MidiKeyboardComponent::getTotalKeyboardWidth() const noexcept { - int x, w; - getKeyPos (rangeEnd, x, w); - return x + w; + return getKeyPos (rangeEnd).getEnd(); } -int MidiKeyboardComponent::getNoteAtPosition (Point p) +int MidiKeyboardComponent::getNoteAtPosition (Point p) { float v; return xyToNote (p, v); } -const uint8 MidiKeyboardComponent::whiteNotes[] = { 0, 2, 4, 5, 7, 9, 11 }; -const uint8 MidiKeyboardComponent::blackNotes[] = { 1, 3, 6, 8, 10 }; - -int MidiKeyboardComponent::xyToNote (Point pos, float& mousePositionVelocity) +int MidiKeyboardComponent::xyToNote (Point pos, float& mousePositionVelocity) { - if (! reallyContains (pos, false)) + if (! reallyContains (pos.toInt(), false)) return -1; - Point p (pos); + auto p = pos; if (orientation != horizontalKeyboard) { - p = Point (p.y, p.x); + p = { p.y, p.x }; if (orientation == verticalKeyboardFacingLeft) - p = Point (p.x, getWidth() - p.y); + p = { p.x, getWidth() - p.y }; else - p = Point (getHeight() - p.x, p.y); + p = { getHeight() - p.x, p.y }; } - return remappedXYToNote (p + Point (xOffset, 0), mousePositionVelocity); + return remappedXYToNote (p + Point (xOffset, 0), mousePositionVelocity); } -int MidiKeyboardComponent::remappedXYToNote (Point pos, float& mousePositionVelocity) const +int MidiKeyboardComponent::remappedXYToNote (Point pos, float& mousePositionVelocity) const { - const int blackNoteLength = getBlackNoteLength(); + auto blackNoteLength = getBlackNoteLength(); if (pos.getY() < blackNoteLength) { @@ -321,17 +300,13 @@ int MidiKeyboardComponent::remappedXYToNote (Point pos, float& mousePositio { for (int i = 0; i < 5; ++i) { - const int note = octaveStart + blackNotes [i]; + auto note = octaveStart + blackNotes[i]; if (note >= rangeStart && note <= rangeEnd) { - int kx, kw; - getKeyPos (note, kx, kw); - kx += xOffset; - - if (pos.x >= kx && pos.x < kx + kw) + if (getKeyPos (note).contains (pos.x - xOffset)) { - mousePositionVelocity = pos.y / (float) blackNoteLength; + mousePositionVelocity = pos.y / blackNoteLength; return note; } } @@ -343,17 +318,13 @@ int MidiKeyboardComponent::remappedXYToNote (Point pos, float& mousePositio { for (int i = 0; i < 7; ++i) { - const int note = octaveStart + whiteNotes [i]; + auto note = octaveStart + whiteNotes[i]; if (note >= rangeStart && note <= rangeEnd) { - int kx, kw; - getKeyPos (note, kx, kw); - kx += xOffset; - - if (pos.x >= kx && pos.x < kx + kw) + if (getKeyPos (note).contains (pos.x - xOffset)) { - const int whiteNoteLength = (orientation == horizontalKeyboard) ? getHeight() : getWidth(); + auto whiteNoteLength = (orientation == horizontalKeyboard) ? getHeight() : getWidth(); mousePositionVelocity = pos.y / (float) whiteNoteLength; return note; } @@ -366,39 +337,35 @@ int MidiKeyboardComponent::remappedXYToNote (Point pos, float& mousePositio } //============================================================================== -void MidiKeyboardComponent::repaintNote (const int noteNum) +void MidiKeyboardComponent::repaintNote (int noteNum) { if (noteNum >= rangeStart && noteNum <= rangeEnd) - repaint (getRectangleForKey (noteNum)); + repaint (getRectangleForKey (noteNum).getSmallestIntegerContainer()); } void MidiKeyboardComponent::paint (Graphics& g) { g.fillAll (findColour (whiteNoteColourId)); - const Colour lineColour (findColour (keySeparatorLineColourId)); - const Colour textColour (findColour (textLabelColourId)); + auto lineColour = findColour (keySeparatorLineColourId); + auto textColour = findColour (textLabelColourId); for (int octave = 0; octave < 128; octave += 12) { for (int white = 0; white < 7; ++white) { - const int noteNum = octave + whiteNotes [white]; + auto noteNum = octave + whiteNotes[white]; if (noteNum >= rangeStart && noteNum <= rangeEnd) - { - Rectangle pos = getRectangleForKey (noteNum); - - drawWhiteNote (noteNum, g, pos.getX(), pos.getY(), pos.getWidth(), pos.getHeight(), + drawWhiteNote (noteNum, g, getRectangleForKey (noteNum), state.isNoteOnForChannels (midiInChannelMask, noteNum), mouseOverNotes.contains (noteNum), lineColour, textColour); - } } } float x1 = 0.0f, y1 = 0.0f, x2 = 0.0f, y2 = 0.0f; - const int width = getWidth(); - const int height = getHeight(); + auto width = getWidth(); + auto height = getHeight(); if (orientation == verticalKeyboardFacingLeft) { @@ -410,11 +377,8 @@ void MidiKeyboardComponent::paint (Graphics& g) else y2 = 5.0f; - int x, w; - getKeyPos (rangeEnd, x, w); - x += w; - - const Colour shadowCol (findColour (shadowColourId)); + auto x = getKeyPos (rangeEnd).getEnd(); + auto shadowCol = findColour (shadowColourId); if (! shadowCol.isTransparent()) { @@ -422,9 +386,9 @@ void MidiKeyboardComponent::paint (Graphics& g) switch (orientation) { - case horizontalKeyboard: g.fillRect (0, 0, x, 5); break; - case verticalKeyboardFacingLeft: g.fillRect (width - 5, 0, 5, x); break; - case verticalKeyboardFacingRight: g.fillRect (0, 0, 5, x); break; + case horizontalKeyboard: g.fillRect (0.0f, 0.0f, x, 5.0f); break; + case verticalKeyboardFacingLeft: g.fillRect (width - 5.0f, 0.0f, 5.0f, x); break; + case verticalKeyboardFacingRight: g.fillRect (0.0f, 0.0f, 5.0f, x); break; default: break; } } @@ -435,61 +399,54 @@ void MidiKeyboardComponent::paint (Graphics& g) switch (orientation) { - case horizontalKeyboard: g.fillRect (0, height - 1, x, 1); break; - case verticalKeyboardFacingLeft: g.fillRect (0, 0, 1, x); break; - case verticalKeyboardFacingRight: g.fillRect (width - 1, 0, 1, x); break; + case horizontalKeyboard: g.fillRect (0.0f, height - 1.0f, x, 1.0f); break; + case verticalKeyboardFacingLeft: g.fillRect (0.0f, 0.0f, 1.0f, x); break; + case verticalKeyboardFacingRight: g.fillRect (width - 1.0f, 0.0f, 1.0f, x); break; default: break; } } - const Colour blackNoteColour (findColour (blackNoteColourId)); + auto blackNoteColour = findColour (blackNoteColourId); for (int octave = 0; octave < 128; octave += 12) { for (int black = 0; black < 5; ++black) { - const int noteNum = octave + blackNotes [black]; + auto noteNum = octave + blackNotes[black]; if (noteNum >= rangeStart && noteNum <= rangeEnd) - { - Rectangle pos = getRectangleForKey (noteNum); - - drawBlackNote (noteNum, g, pos.getX(), pos.getY(), pos.getWidth(), pos.getHeight(), + drawBlackNote (noteNum, g, getRectangleForKey (noteNum), state.isNoteOnForChannels (midiInChannelMask, noteNum), mouseOverNotes.contains (noteNum), blackNoteColour); - } } } } -void MidiKeyboardComponent::drawWhiteNote (int midiNoteNumber, - Graphics& g, int x, int y, int w, int h, - bool isDown, bool isOver, - const Colour& lineColour, - const Colour& textColour) +void MidiKeyboardComponent::drawWhiteNote (int midiNoteNumber, Graphics& g, Rectangle area, + bool isDown, bool isOver, Colour lineColour, Colour textColour) { - Colour c (Colours::transparentWhite); + auto c = Colours::transparentWhite; if (isDown) c = findColour (keyDownOverlayColourId); if (isOver) c = c.overlaidWith (findColour (mouseOverKeyOverlayColourId)); g.setColour (c); - g.fillRect (x, y, w, h); + g.fillRect (area); - const String text (getWhiteNoteText (midiNoteNumber)); + auto text = getWhiteNoteText (midiNoteNumber); if (text.isNotEmpty()) { - const float fontHeight = jmin (12.0f, keyWidth * 0.9f); + auto fontHeight = jmin (12.0f, keyWidth * 0.9f); g.setColour (textColour); g.setFont (Font (fontHeight).withHorizontalScale (0.8f)); switch (orientation) { - case horizontalKeyboard: g.drawText (text, x + 1, y, w - 1, h - 2, Justification::centredBottom, false); break; - case verticalKeyboardFacingLeft: g.drawText (text, x + 2, y + 2, w - 4, h - 4, Justification::centredLeft, false); break; - case verticalKeyboardFacingRight: g.drawText (text, x + 2, y + 2, w - 4, h - 4, Justification::centredRight, false); break; + case horizontalKeyboard: g.drawText (text, area.withTrimmedLeft (1.0f).withTrimmedBottom (2.0f), Justification::centredBottom, false); break; + case verticalKeyboardFacingLeft: g.drawText (text, area.reduced (2.0f), Justification::centredLeft, false); break; + case verticalKeyboardFacingRight: g.drawText (text, area.reduced (2.0f), Justification::centredRight, false); break; default: break; } } @@ -500,9 +457,9 @@ void MidiKeyboardComponent::drawWhiteNote (int midiNoteNumber, switch (orientation) { - case horizontalKeyboard: g.fillRect (x, y, 1, h); break; - case verticalKeyboardFacingLeft: g.fillRect (x, y, w, 1); break; - case verticalKeyboardFacingRight: g.fillRect (x, y + h - 1, w, 1); break; + case horizontalKeyboard: g.fillRect (area.withWidth (1.0f)); break; + case verticalKeyboardFacingLeft: g.fillRect (area.withHeight (1.0f)); break; + case verticalKeyboardFacingRight: g.fillRect (area.removeFromBottom (1.0f)); break; default: break; } @@ -510,55 +467,56 @@ void MidiKeyboardComponent::drawWhiteNote (int midiNoteNumber, { switch (orientation) { - case horizontalKeyboard: g.fillRect (x + w, y, 1, h); break; - case verticalKeyboardFacingLeft: g.fillRect (x, y + h, w, 1); break; - case verticalKeyboardFacingRight: g.fillRect (x, y - 1, w, 1); break; + case horizontalKeyboard: g.fillRect (area.expanded (1.0f, 0).removeFromRight (1.0f)); break; + case verticalKeyboardFacingLeft: g.fillRect (area.expanded (0, 1.0f).removeFromBottom (1.0f)); break; + case verticalKeyboardFacingRight: g.fillRect (area.expanded (0, 1.0f).removeFromTop (1.0f)); break; default: break; } } } } -void MidiKeyboardComponent::drawBlackNote (int /*midiNoteNumber*/, - Graphics& g, int x, int y, int w, int h, - bool isDown, bool isOver, - const Colour& noteFillColour) +void MidiKeyboardComponent::drawBlackNote (int /*midiNoteNumber*/, Graphics& g, Rectangle area, + bool isDown, bool isOver, Colour noteFillColour) { - Colour c (noteFillColour); + auto c = noteFillColour; if (isDown) c = c.overlaidWith (findColour (keyDownOverlayColourId)); if (isOver) c = c.overlaidWith (findColour (mouseOverKeyOverlayColourId)); g.setColour (c); - g.fillRect (x, y, w, h); + g.fillRect (area); if (isDown) { g.setColour (noteFillColour); - g.drawRect (x, y, w, h); + g.drawRect (area); } else { g.setColour (c.brighter()); - const int xIndent = jmax (1, jmin (w, h) / 8); + auto sideIndent = 1.0f / 8.0f; + auto topIndent = 7.0f / 8.0f; + auto w = area.getWidth(); + auto h = area.getHeight(); switch (orientation) { - case horizontalKeyboard: g.fillRect (x + xIndent, y, w - xIndent * 2, 7 * h / 8); break; - case verticalKeyboardFacingLeft: g.fillRect (x + w / 8, y + xIndent, w - w / 8, h - xIndent * 2); break; - case verticalKeyboardFacingRight: g.fillRect (x, y + xIndent, 7 * w / 8, h - xIndent * 2); break; + case horizontalKeyboard: g.fillRect (area.reduced (w * sideIndent, 0).removeFromTop (h * topIndent)); break; + case verticalKeyboardFacingLeft: g.fillRect (area.reduced (0, h * sideIndent).removeFromRight (w * topIndent)); break; + case verticalKeyboardFacingRight: g.fillRect (area.reduced (0, h * sideIndent).removeFromLeft (w * topIndent)); break; default: break; } } } -void MidiKeyboardComponent::setOctaveForMiddleC (const int octaveNum) +void MidiKeyboardComponent::setOctaveForMiddleC (int octaveNum) { octaveNumForMiddleC = octaveNum; repaint(); } -String MidiKeyboardComponent::getWhiteNoteText (const int midiNoteNumber) +String MidiKeyboardComponent::getWhiteNoteText (int midiNoteNumber) { if (midiNoteNumber % 12 == 0) return MidiMessage::getMidiNoteName (midiNoteNumber, true, true, octaveNumForMiddleC); @@ -567,20 +525,20 @@ String MidiKeyboardComponent::getWhiteNoteText (const int midiNoteNumber) } void MidiKeyboardComponent::drawUpDownButton (Graphics& g, int w, int h, - const bool mouseOver, - const bool buttonDown, - const bool movesOctavesUp) + bool mouseOver, + bool buttonDown, + bool movesOctavesUp) { g.fillAll (findColour (upDownButtonBackgroundColourId)); - float angle; + float angle = 0; switch (orientation) { case horizontalKeyboard: angle = movesOctavesUp ? 0.0f : 0.5f; break; case verticalKeyboardFacingLeft: angle = movesOctavesUp ? 0.25f : 0.75f; break; case verticalKeyboardFacingRight: angle = movesOctavesUp ? 0.75f : 0.25f; break; - default: jassertfalse; angle = 0; break; + default: jassertfalse; break; } Path path; @@ -596,6 +554,7 @@ void MidiKeyboardComponent::drawUpDownButton (Graphics& g, int w, int h, void MidiKeyboardComponent::setBlackNoteLengthProportion (float ratio) noexcept { jassert (ratio >= 0.0f && ratio <= 1.0f); + if (blackNoteLengthRatio != ratio) { blackNoteLengthRatio = ratio; @@ -603,32 +562,27 @@ void MidiKeyboardComponent::setBlackNoteLengthProportion (float ratio) noexcept } } -int MidiKeyboardComponent::getBlackNoteLength() const noexcept +float MidiKeyboardComponent::getBlackNoteLength() const noexcept { - const int whiteNoteLength = orientation == horizontalKeyboard ? getHeight() : getWidth(); - - return roundToInt (whiteNoteLength * blackNoteLengthRatio); + auto whiteNoteLength = orientation == horizontalKeyboard ? getHeight() : getWidth(); + return whiteNoteLength * blackNoteLengthRatio; } void MidiKeyboardComponent::resized() { - int w = getWidth(); - int h = getHeight(); + auto w = getWidth(); + auto h = getHeight(); if (w > 0 && h > 0) { if (orientation != horizontalKeyboard) std::swap (w, h); - int kx2, kw2; - getKeyPos (rangeEnd, kx2, kw2); - - kx2 += kw2; + auto kx2 = getKeyPos (rangeEnd).getEnd(); if ((int) firstKey != rangeStart) { - int kx1, kw1; - getKeyPos (rangeStart, kx1, kw1); + auto kx1 = getKeyPos (rangeStart).getStart(); if (kx2 - kx1 <= w) { @@ -644,8 +598,8 @@ void MidiKeyboardComponent::resized() if (canScroll) { - const int scrollButtonW = jmin (12, w / 2); - Rectangle r (getLocalBounds()); + auto scrollButtonW = jmin (12, w / 2); + auto r = getLocalBounds(); if (orientation == horizontalKeyboard) { @@ -663,13 +617,11 @@ void MidiKeyboardComponent::resized() scrollUp ->setBounds (r.removeFromTop (scrollButtonW)); } - int endOfLastKey, kw; - getKeyPos (rangeEnd, endOfLastKey, kw); - endOfLastKey += kw; + auto endOfLastKey = getKeyPos (rangeEnd).getEnd(); float mousePositionVelocity; - const int spaceAvailable = w; - const int lastStartKey = remappedXYToNote (Point (endOfLastKey - spaceAvailable, 0), mousePositionVelocity) + 1; + auto spaceAvailable = w; + auto lastStartKey = remappedXYToNote ({ endOfLastKey - spaceAvailable, 0 }, mousePositionVelocity) + 1; if (lastStartKey >= 0 && ((int) firstKey) > lastStartKey) { @@ -677,17 +629,14 @@ void MidiKeyboardComponent::resized() sendChangeMessage(); } - int newOffset = 0; - getKeyPos ((int) firstKey, newOffset, kw); - xOffset = newOffset; + xOffset = getKeyPos ((int) firstKey).getStart(); } else { firstKey = (float) rangeStart; } - getKeyPos (rangeEnd, kx2, kw2); - scrollUp->setVisible (canScroll && kx2 > w); + scrollUp->setVisible (canScroll && getKeyPos (rangeEnd).getStart() > w); repaint(); } } @@ -717,7 +666,7 @@ void MidiKeyboardComponent::resetAnyKeysInUse() for (int i = mouseDownNotes.size(); --i >= 0;) { - const int noteDown = mouseDownNotes.getUnchecked(i); + auto noteDown = mouseDownNotes.getUnchecked(i); if (noteDown >= 0) { @@ -731,16 +680,16 @@ void MidiKeyboardComponent::resetAnyKeysInUse() void MidiKeyboardComponent::updateNoteUnderMouse (const MouseEvent& e, bool isDown) { - updateNoteUnderMouse (e.getEventRelativeTo (this).getPosition(), isDown, e.source.getIndex()); + updateNoteUnderMouse (e.getEventRelativeTo (this).position, isDown, e.source.getIndex()); } -void MidiKeyboardComponent::updateNoteUnderMouse (Point pos, bool isDown, int fingerNum) +void MidiKeyboardComponent::updateNoteUnderMouse (Point pos, bool isDown, int fingerNum) { float mousePositionVelocity = 0.0f; - const int newNote = xyToNote (pos, mousePositionVelocity); - const int oldNote = mouseOverNotes.getUnchecked (fingerNum); - const int oldNoteDown = mouseDownNotes.getUnchecked (fingerNum); - const float eventVelocity = useMousePositionForVelocity ? mousePositionVelocity * velocity : 1.0f; + auto newNote = xyToNote (pos, mousePositionVelocity); + auto oldNote = mouseOverNotes.getUnchecked (fingerNum); + auto oldNoteDown = mouseDownNotes.getUnchecked (fingerNum); + auto eventVelocity = useMousePositionForVelocity ? mousePositionVelocity * velocity : 1.0f; if (oldNote != newNote) { @@ -786,7 +735,7 @@ void MidiKeyboardComponent::mouseMove (const MouseEvent& e) void MidiKeyboardComponent::mouseDrag (const MouseEvent& e) { float mousePositionVelocity; - const int newNote = xyToNote (e.getPosition(), mousePositionVelocity); + auto newNote = xyToNote (e.position, mousePositionVelocity); if (newNote >= 0) mouseDraggedToKey (newNote, e); @@ -801,7 +750,7 @@ void MidiKeyboardComponent::mouseUpOnKey (int, const MouseEvent&) {} void MidiKeyboardComponent::mouseDown (const MouseEvent& e) { float mousePositionVelocity; - const int newNote = xyToNote (e.getPosition(), mousePositionVelocity); + auto newNote = xyToNote (e.position, mousePositionVelocity); if (newNote >= 0 && mouseDownOnKey (newNote, e)) { @@ -816,7 +765,8 @@ void MidiKeyboardComponent::mouseUp (const MouseEvent& e) shouldCheckMousePos = false; float mousePositionVelocity; - const int note = xyToNote (e.getPosition(), mousePositionVelocity); + auto note = xyToNote (e.position, mousePositionVelocity); + if (note >= 0) mouseUpOnKey (note, e); } @@ -833,9 +783,9 @@ void MidiKeyboardComponent::mouseExit (const MouseEvent& e) void MidiKeyboardComponent::mouseWheelMove (const MouseEvent&, const MouseWheelDetails& wheel) { - const float amount = (orientation == horizontalKeyboard && wheel.deltaX != 0) - ? wheel.deltaX : (orientation == verticalKeyboardFacingLeft ? wheel.deltaY - : -wheel.deltaY); + auto amount = (orientation == horizontalKeyboard && wheel.deltaX != 0) + ? wheel.deltaX : (orientation == verticalKeyboardFacingLeft ? wheel.deltaY + : -wheel.deltaY); setLowestVisibleKeyFloat (firstKey - amount * keyWidth); } @@ -848,9 +798,11 @@ void MidiKeyboardComponent::timerCallback() for (int i = rangeStart; i <= rangeEnd; ++i) { - if (keysCurrentlyDrawnDown[i] != state.isNoteOnForChannels (midiInChannelMask, i)) + bool isOn = state.isNoteOnForChannels (midiInChannelMask, i); + + if (keysCurrentlyDrawnDown[i] != isOn) { - keysCurrentlyDrawnDown.setBit (i, state.isNoteOnForChannels (midiInChannelMask, i)); + keysCurrentlyDrawnDown.setBit (i, isOn); repaintNote (i); } } @@ -860,7 +812,7 @@ void MidiKeyboardComponent::timerCallback() { for (auto& ms : Desktop::getInstance().getMouseSources()) if (ms.getComponentUnderMouse() == this || isParentOf (ms.getComponentUnderMouse())) - updateNoteUnderMouse (getLocalPoint (nullptr, ms.getScreenPosition()).roundToInt(), ms.isDragging(), ms.getIndex()); + updateNoteUnderMouse (getLocalPoint (nullptr, ms.getScreenPosition()), ms.isDragging(), ms.getIndex()); } } @@ -880,7 +832,7 @@ void MidiKeyboardComponent::setKeyPressForNote (const KeyPress& key, int midiNot keyPresses.add (key); } -void MidiKeyboardComponent::removeKeyPressForNote (const int midiNoteOffsetFromC) +void MidiKeyboardComponent::removeKeyPressForNote (int midiNoteOffsetFromC) { for (int i = keyPressNotes.size(); --i >= 0;) { @@ -892,24 +844,24 @@ void MidiKeyboardComponent::removeKeyPressForNote (const int midiNoteOffsetFromC } } -void MidiKeyboardComponent::setKeyPressBaseOctave (const int newOctaveNumber) +void MidiKeyboardComponent::setKeyPressBaseOctave (int newOctaveNumber) { jassert (newOctaveNumber >= 0 && newOctaveNumber <= 10); keyMappingOctave = newOctaveNumber; } -bool MidiKeyboardComponent::keyStateChanged (const bool /*isKeyDown*/) +bool MidiKeyboardComponent::keyStateChanged (bool /*isKeyDown*/) { bool keyPressUsed = false; for (int i = keyPresses.size(); --i >= 0;) { - const int note = 12 * keyMappingOctave + keyPressNotes.getUnchecked (i); + auto note = 12 * keyMappingOctave + keyPressNotes.getUnchecked (i); if (keyPresses.getReference(i).isCurrentlyDown()) { - if (! keysPressed [note]) + if (! keysPressed[note]) { keysPressed.setBit (note); state.noteOn (midiChannel, note, velocity); @@ -918,7 +870,7 @@ bool MidiKeyboardComponent::keyStateChanged (const bool /*isKeyDown*/) } else { - if (keysPressed [note]) + if (keysPressed[note]) { keysPressed.clearBit (note); state.noteOff (midiChannel, note, 0.0f); diff --git a/modules/juce_audio_utils/gui/juce_MidiKeyboardComponent.h b/modules/juce_audio_utils/gui/juce_MidiKeyboardComponent.h index 7d40fc10f3..87865035dd 100644 --- a/modules/juce_audio_utils/gui/juce_MidiKeyboardComponent.h +++ b/modules/juce_audio_utils/gui/juce_MidiKeyboardComponent.h @@ -175,7 +175,7 @@ public: /** Returns the absolute length of the black notes. This will be their vertical or horizontal length, depending on the keyboard's orientation. */ - int getBlackNoteLength() const noexcept; + float getBlackNoteLength() const noexcept; /** If set to true, then scroll buttons will appear at either end of the keyboard if there are too many notes to fit them all in the component at once. @@ -208,13 +208,13 @@ public: Depending on the keyboard's orientation, this may be a horizontal or vertical distance, in either direction. */ - int getKeyStartPosition (int midiNoteNumber) const; + float getKeyStartPosition (int midiNoteNumber) const; /** Returns the total width needed to fit all the keys in the available range. */ - int getTotalKeyboardWidth() const noexcept; + float getTotalKeyboardWidth() const noexcept; /** Returns the key at a given coordinate. */ - int getNoteAtPosition (Point position); + int getNoteAtPosition (Point position); //============================================================================== /** Deletes all key-mappings. @@ -311,11 +311,9 @@ protected: When doing this, be sure to note the keyboard's orientation. */ virtual void drawWhiteNote (int midiNoteNumber, - Graphics& g, - int x, int y, int w, int h, + Graphics& g, Rectangle area, bool isDown, bool isOver, - const Colour& lineColour, - const Colour& textColour); + Colour lineColour, Colour textColour); /** Draws a black note in the given rectangle. @@ -325,22 +323,21 @@ protected: When doing this, be sure to note the keyboard's orientation. */ virtual void drawBlackNote (int midiNoteNumber, - Graphics& g, - int x, int y, int w, int h, + Graphics& g, Rectangle area, bool isDown, bool isOver, - const Colour& noteFillColour); + Colour noteFillColour); /** 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 (const int midiNoteNumber); + virtual String getWhiteNoteText (int midiNoteNumber); - /** Draws the up and down buttons that change the base note. */ + /** Draws the up and down buttons that scroll the keyboard up/down in octaves. */ virtual void drawUpDownButton (Graphics& g, int w, int h, - const bool isMouseOver, - const bool isButtonPressed, - const bool movesOctavesUp); + bool isMouseOver, + bool isButtonPressed, + bool movesOctavesUp); /** Callback when the mouse is clicked on a key. @@ -369,55 +366,56 @@ protected: @param midiNoteNumber the note to find @param keyWidth the desired width in pixels of one key - see setKeyWidth() - @param x the x position of the left-hand edge of the key (this method - always works in terms of a horizontal keyboard) - @param w the width of the key + @returns the start and length of the key along the axis of the keyboard */ - virtual void getKeyPosition (int midiNoteNumber, float keyWidth, - int& x, int& w) const; + virtual Range getKeyPosition (int midiNoteNumber, float keyWidth) const; /** Returns the rectangle for a given key if within the displayable range */ - Rectangle getRectangleForKey (int midiNoteNumber) const; + Rectangle getRectangleForKey (int midiNoteNumber) const; private: //============================================================================== - friend class MidiKeyboardUpDownButton; + struct UpDownButton; MidiKeyboardState& state; - float blackNoteLengthRatio; - int xOffset; - float keyWidth; + float blackNoteLengthRatio = 0.7f; + float xOffset = 0; + float keyWidth = 16.0f; Orientation orientation; - int midiChannel, midiInChannelMask; - float velocity; + int midiChannel = 1, midiInChannelMask = 0xffff; + float velocity = 1.0f; Array mouseOverNotes, mouseDownNotes; BigInteger keysPressed, keysCurrentlyDrawnDown; - bool shouldCheckState; + bool shouldCheckState = false; - int rangeStart, rangeEnd; - float firstKey; - bool canScroll, useMousePositionForVelocity, shouldCheckMousePos; + int rangeStart = 0, rangeEnd = 127; + float firstKey = 12 * 4.0f; + bool canScroll = true, useMousePositionForVelocity = true, shouldCheckMousePos = false; ScopedPointer