MidiKeyboardComponent request


#1

I've been racking my brain trying to figure out how to get the MidiKeyboardComponent to display multiple colors for noteOn's simultaneously.  the scenario: 

You press down a key  (midikeyboardstate.note = on )

you press down a sustain pedal

you release the key (midikeyboardstate.note = off )

the note turns off on the MidiKeyboardComponent, as expected.  

Ideally, the note in the midikeyboardcomponent would stay lit, but maybe with a different color, until a sustainOff message arrived.   Other note-on presses would be drawn with the normal keyDownOverlayColourId

I tried subclassing MidiKeyboardComponent, and exposing repaintNote() as a protected member: 

class ExtraMidiKeyboardComponent : public MidiKeyboardComponent
{

public:
    ExtraMidiKeyboardComponent( MidiKeyboardState& state, Orientation orientation) : MidiKeyboardComponent( state, orientation) {
        sustainedColor = Colour( UInt32( 0xFF79E2FF) );
    }
    ~ExtraMidiKeyboardComponent(  ) {}

    void drawSustainedNote (int note ) {
        const MessageManagerLock mmLock;
        state->noteOn(1, note, 1);
        setColour( MidiKeyboardComponent::keyDownOverlayColourId, Colours::black );
        repaintIndividualNote( note );
    }

private:
    SharedResourcePointer<MidiKeyboardState> state;
    Colour sustainedColor;
};

and then in my class that uses the MidiKeyboardComponent, I had this: 

    void handleNoteOff( MidiKeyboardState* source, int, int ) {
        if( sustain ) {
            std::cout << "handleNoteOff \n";
            std::vector<int> curNotes = detector->getCurrentOnNotes();
            for( int i = 0; i < curNotes.size(); i++ )
                keyboard->drawSustainedNote( curNotes[i] );
        }
    }

    void setSustain( bool s, const MidiMessage &message ) {
        sustain = s;
        postMessageToList( message );   //triggers repaint()
        if( sustain == false && detector->getCurrentOnNotes().size() == 0) {
            //turn off everything that's still on
            state->allNotesOff(0);
            setKeyboardNoteOnColor(defaultNoteOnColor); //because drawSustainedNotes changes it
        }
    }

What i'm hoping to achieve is that any noteOns are drawn with the color they're always drawn with, and any notes that are sustained after a note-Off occurs, are drawn with a different color. 


#2

I was able to implement this by adding the functionality to MidiKeyboardState.h/cpp and MidiKeyboardComponent.h/cpp, and LookAndFeel_V2.cpp (adding the overlay code) 

 

I can post the code if anyone is interested. 


#3

Sorry for bumping this older thread.

I’m trying to do something similar, that is defining different keyDownOverlay colours for different key ranges.

I’ve found

.setColour(MidiKeyboardComponent::keyDownOverlayColourId, Colour )

but this seems only be suitable for the whole keyboard range.

Is there a straightforward way to do this ?
If not - yes, I’d certainly be interested in the code the OP came up with.


#4

Subclass the class and write your own versions of drawWhite/BlackNote


#5

Thanks.
That’s what I thought about doing but figured rather asking before if there’s another way.
I got it working with overriding the drawing methods meanwhile.

simple example:

void CustomMidiKeyboardComponent::drawBlackNote(int midiNoteNumber, Graphics & g, int x, int y, int w, int h, bool isDown, bool isOver, const Colour & noteFillColour)
{
	if (midiNoteNumber <= splitNote) {
		Colour c(noteFillColour);
                // define keyDownOverlayColour for lower range
		if (isDown)  c = c.overlaidWith(Colours::yellow);
		if (isOver)  c = c.overlaidWith(findColour(mouseOverKeyOverlayColourId));

		g.setColour(c);
		g.fillRect(x, y, w, h);

		if (isDown)
		{
			g.setColour(noteFillColour);
			g.drawRect(x, y, w, h);
		}
		else
		{
			g.setColour(c.brighter());
			const int xIndent = jmax(1, jmin(w, h) / 8);

			g.fillRect(x + xIndent, y, w - xIndent * 2, 7 * h / 8); 
			}
		}

	if (midiNoteNumber > splitNote) {
		Colour c(noteFillColour);
                // define keyDownOverlayColour for upper range
		if (isDown)  c = c.overlaidWith(Colours::navy);
		if (isOver)  c = c.overlaidWith(findColour(mouseOverKeyOverlayColourId));

		g.setColour(c);
		g.fillRect(x, y, w, h);

		if (isDown)
		{
			g.setColour(noteFillColour);
			g.drawRect(x, y, w, h);
		}
		else
		{
			g.setColour(c.brighter());
			const int xIndent = jmax(1, jmin(w, h) / 8);

			g.fillRect(x + xIndent, y, w - xIndent * 2, 7 * h / 8);
		}
	}
}

edit:
shorter version is to set overlay color directly

        // ...
	if (isDown) {
		if (midiNoteNumber <= splitNote) {
			c = c.overlaidWith(Colours::yellow);
		}
		if (midiNoteNumber > splitNote) {
			c = c.overlaidWith(Colours::navy);
		}
		
	}
        // ...