Hi,
I use a MidiKeyboardComponent to display notes played from an external MIDI keyboard and to allow triggering MIDI notes from the application GUI. So, incoming MIDI Note events are sent to a MidiKeyboardState object that merges them with MIDI Note events coming from the GUI component, and sends the whole thing to MIDI out.
My problem is that by doing so, I lose the Note Off velocity information coming from the external MIDI device when forwarding Note Off messages to MIDI out through the Keyboard component stuff.
So I have a minor request: could you please add support for NoteOff velocity for this stuff?
Unless I've missed something, here are the needed changes: (additions in bold)
in juce_MidiKeyboardState.h:
virtual void handleNoteOff (MidiKeyboardState* source,
int midiChannel, int midiNoteNumber, float velocity=0) = 0;
void noteOff(int midiChannel, int midiNoteNumber, float velocity = 0);
void noteOffInternal(int midiChannel, int midiNoteNumber, float velocity=0);
in juce_MidiKeyboardState.cpp:
void MidiKeyboardState::noteOff(const int midiChannel, const int midiNoteNumber, float velocity)
{
const ScopedLock sl (lock);
if (isNoteOn (midiChannel, midiNoteNumber))
{
const int timeNow = (int) Time::getMillisecondCounter();
eventsToAdd.addEvent(MidiMessage::noteOff(midiChannel, midiNoteNumber, velocity), timeNow);
eventsToAdd.clear (0, timeNow - 500);
noteOffInternal (midiChannel, midiNoteNumber, velocity);
}
}
void MidiKeyboardState::noteOffInternal(const int midiChannel, const int midiNoteNumber, float velocity)
{
if (isNoteOn (midiChannel, midiNoteNumber))
{
noteStates [midiNoteNumber] &= ~(1 << (midiChannel - 1));
for (int i = listeners.size(); --i >= 0;)
listeners.getUnchecked(i)->handleNoteOff (this, midiChannel, midiNoteNumber, velocity);
}
}
void MidiKeyboardState::processNextMidiEvent (const MidiMessage& message)
{
if (message.isNoteOn())
{
noteOnInternal (message.getChannel(), message.getNoteNumber(), message.getFloatVelocity());
}
else if (message.isNoteOff())
{
noteOffInternal (message.getChannel(), message.getNoteNumber(), message.getFloatVelocity());
}
else if (message.isAllNotesOff())
{
for (int i = 0; i < 128; ++i)
noteOffInternal (message.getChannel(), i);
}
In juce_MidiMessageCollector.h:
void handleNoteOff (MidiKeyboardState*, int midiChannel, int midiNoteNumber, float velocity=0) override;
In juce_MidiMessageCollector.cpp:
void MidiMessageCollector::handleNoteOff (MidiKeyboardState*, int midiChannel, int midiNoteNumber, float velocity)
{
MidiMessage m (MidiMessage::noteOff (midiChannel, midiNoteNumber, velocity));
m.setTimeStamp (Time::getMillisecondCounterHiRes() * 0.001);
addMessageToQueue (m);
}
In juce_MidiMidiKeyboardComponent.h:
void handleNoteOff (MidiKeyboardState*, int midiChannel, int midiNoteNumber, float velocity=0) override;
In juce_MidiMidiKeyboardComponent.cpp:
void MidiKeyboardComponent::handleNoteOff(MidiKeyboardState*, int /*midiChannel*/, int /*midiNoteNumber*/, float /*velocity*/)
void MidiKeyboardComponent::updateNoteUnderMouse (Point<int> pos, bool isDown, int fingerNum)
{
[...]
else if (oldNoteDown >= 0)
{
mouseDownNotes.set (fingerNum, -1);
if (!mouseDownNotes.contains(oldNoteDown))
{
if (!useMousePositionForVelocity)
mousePositionVelocity = 1.0f;
state.noteOff(midiChannel, oldNoteDown, mousePositionVelocity * velocity);
}
}
}
As these arguments are made optional, there will be no compatibility issue with prior Juce versions
This addition would be greatly appreciated (so I won't have to re-edit Juce code after each update, and hopefully it can be helpful to other users)
Thanks in advance!