From 29f8bbf13f8a8585f8df60baa9ac8449080f820b Mon Sep 17 00:00:00 2001 From: falkTX Date: Fri, 12 Sep 2014 16:09:58 +0100 Subject: [PATCH] Rework some plugin MIDI code, closes #134 --- source/backend/plugin/BridgePlugin.cpp | 24 +-- source/backend/plugin/DssiPlugin.cpp | 146 +++++++++---------- source/backend/plugin/FluidSynthPlugin.cpp | 113 ++++++++------ source/backend/plugin/JucePlugin.cpp | 42 +++--- source/backend/plugin/LinuxSamplerPlugin.cpp | 43 +++--- source/backend/plugin/Lv2Plugin.cpp | 66 +++++---- source/backend/plugin/NativePlugin.cpp | 131 ++++++++--------- source/backend/plugin/VstPlugin.cpp | 133 +++++++++-------- source/includes/CarlaMIDI.h | 26 ++-- 9 files changed, 371 insertions(+), 353 deletions(-) diff --git a/source/backend/plugin/BridgePlugin.cpp b/source/backend/plugin/BridgePlugin.cpp index 8d40b7ced..6486d9be1 100644 --- a/source/backend/plugin/BridgePlugin.cpp +++ b/source/backend/plugin/BridgePlugin.cpp @@ -966,7 +966,7 @@ public: CARLA_SAFE_ASSERT_CONTINUE(note.channel >= 0 && note.channel < MAX_MIDI_CHANNELS); uint8_t data1, data2, data3; - data1 = static_cast((note.velo > 0 ? MIDI_STATUS_NOTE_ON : MIDI_STATUS_NOTE_OFF) | (note.channel & MIDI_CHANNEL_BIT)); + data1 = uint8_t((note.velo > 0 ? MIDI_STATUS_NOTE_ON : MIDI_STATUS_NOTE_OFF) | (note.channel & MIDI_CHANNEL_BIT)); data2 = note.note; data3 = note.velo; @@ -990,7 +990,7 @@ public: bool allNotesOffSent = false; - for (uint32_t i=0, numEvents = pData->event.portIn->getEventCount(); i < numEvents; ++i) + for (uint32_t i=0, numEvents=pData->event.portIn->getEventCount(); i < numEvents; ++i) { const EngineEvent& event(pData->event.portIn->getEvent(i)); @@ -1124,11 +1124,9 @@ public: if (midiEvent.size == 0 || midiEvent.size >= MAX_MIDI_VALUE) continue; - uint8_t status = uint8_t(MIDI_GET_STATUS_FROM_DATA(midiEvent.data)); - uint8_t channel = event.channel; + const uint8_t* const midiData(midiEvent.size > EngineMidiEvent::kDataSize ? midiEvent.dataExt : midiEvent.data); - if (MIDI_IS_STATUS_NOTE_ON(status) && midiEvent.data[2] == 0) - status = MIDI_STATUS_NOTE_OFF; + uint8_t status = uint8_t(MIDI_GET_STATUS_FROM_DATA(midiData)); if (status == MIDI_STATUS_CHANNEL_PRESSURE && (pData->options & PLUGIN_OPTION_SEND_CHANNEL_PRESSURE) == 0) continue; @@ -1139,20 +1137,26 @@ public: if (status == MIDI_STATUS_PITCH_WHEEL_CONTROL && (pData->options & PLUGIN_OPTION_SEND_PITCHBEND) == 0) continue; + // Fix bad note-off + if (status == MIDI_STATUS_NOTE_ON && midiData[2] == 0) + status = MIDI_STATUS_NOTE_OFF; + fShmRtControl.writeOpcode(kPluginBridgeRtMidiEvent); fShmRtControl.writeUInt(event.time); fShmRtControl.writeByte(midiEvent.port); fShmRtControl.writeByte(midiEvent.size); - for (uint8_t j=0; j < midiEvent.size; ++j) - fShmRtControl.writeByte(midiEvent.data[j]); + fShmRtControl.writeByte(uint8_t(midiData[0] | (event.channel & MIDI_CHANNEL_BIT))); + + for (uint8_t j=1; j < midiEvent.size; ++j) + fShmRtControl.writeByte(midiData[j]); fShmRtControl.commitWrite(); if (status == MIDI_STATUS_NOTE_ON) - pData->postponeRtEvent(kPluginPostRtEventNoteOn, channel, midiEvent.data[1], midiEvent.data[2]); + pData->postponeRtEvent(kPluginPostRtEventNoteOn, event.channel, midiData[1], midiData[2]); else if (status == MIDI_STATUS_NOTE_OFF) - pData->postponeRtEvent(kPluginPostRtEventNoteOff, channel, midiEvent.data[1], 0.0f); + pData->postponeRtEvent(kPluginPostRtEventNoteOff, event.channel, midiData[1], 0.0f); } break; } } diff --git a/source/backend/plugin/DssiPlugin.cpp b/source/backend/plugin/DssiPlugin.cpp index dc3e82913..e772e7891 100644 --- a/source/backend/plugin/DssiPlugin.cpp +++ b/source/backend/plugin/DssiPlugin.cpp @@ -1092,6 +1092,7 @@ public: } ulong midiEventCount = 0; + carla_zeroStruct(fMidiEvents, kPluginMaxMidiEvents); // -------------------------------------------------------------------------------------------------------- // Check if needs reset @@ -1101,7 +1102,6 @@ public: if (pData->options & PLUGIN_OPTION_SEND_ALL_SOUND_OFF) { midiEventCount = MAX_MIDI_CHANNELS*2; - carla_zeroStruct(fMidiEvents, midiEventCount); for (uchar i=0, k=MAX_MIDI_CHANNELS; i < MAX_MIDI_CHANNELS; ++i) { @@ -1117,7 +1117,6 @@ public: else if (pData->ctrlChannel >= 0 && pData->ctrlChannel < MAX_MIDI_CHANNELS) { midiEventCount = MAX_MIDI_NOTE; - carla_zeroStruct(fMidiEvents, midiEventCount); for (uchar i=0; i < MAX_MIDI_NOTE; ++i) { @@ -1156,13 +1155,12 @@ public: CARLA_SAFE_ASSERT_CONTINUE(note.channel >= 0 && note.channel < MAX_MIDI_CHANNELS); - snd_seq_event_t& midiEvent(fMidiEvents[midiEventCount++]); - carla_zeroStruct(midiEvent); + snd_seq_event_t& seqEvent(fMidiEvents[midiEventCount++]); - midiEvent.type = (note.velo > 0) ? SND_SEQ_EVENT_NOTEON : SND_SEQ_EVENT_NOTEOFF; - midiEvent.data.note.channel = static_cast(note.channel); - midiEvent.data.note.note = note.note; - midiEvent.data.note.velocity = note.velo; + seqEvent.type = (note.velo > 0) ? SND_SEQ_EVENT_NOTEON : SND_SEQ_EVENT_NOTEOFF; + seqEvent.data.note.channel = static_cast(note.channel); + seqEvent.data.note.note = note.note; + seqEvent.data.note.velocity = note.velo; } pData->extNotes.mutex.unlock(); @@ -1177,7 +1175,6 @@ public: #endif const bool isSampleAccurate = (pData->options & PLUGIN_OPTION_FIXED_BUFFERS) == 0; - uint32_t numEvents = pData->event.portIn->getEventCount(); uint32_t startTime = 0; uint32_t timeOffset = 0; uint32_t nextBankId; @@ -1187,7 +1184,7 @@ public: else nextBankId = 0; - for (uint32_t i=0; i < numEvents; ++i) + for (uint32_t i=0, numEvents=pData->event.portIn->getEventCount(); i < numEvents; ++i) { const EngineEvent& event(pData->event.portIn->getEvent(i)); @@ -1319,15 +1316,14 @@ public: if (midiEventCount >= kPluginMaxMidiEvents) continue; - snd_seq_event_t& midiEvent(fMidiEvents[midiEventCount++]); - carla_zeroStruct(midiEvent); + snd_seq_event_t& seqEvent(fMidiEvents[midiEventCount++]); - midiEvent.time.tick = isSampleAccurate ? startTime : event.time; + seqEvent.time.tick = isSampleAccurate ? startTime : event.time; - midiEvent.type = SND_SEQ_EVENT_CONTROLLER; - midiEvent.data.control.channel = event.channel; - midiEvent.data.control.param = ctrlEvent.param; - midiEvent.data.control.value = int8_t(ctrlEvent.value*127.0f); + seqEvent.type = SND_SEQ_EVENT_CONTROLLER; + seqEvent.data.control.channel = event.channel; + seqEvent.data.control.param = ctrlEvent.param; + seqEvent.data.control.value = int8_t(ctrlEvent.value*127.0f); } break; } // case kEngineControlEventTypeParameter @@ -1361,14 +1357,13 @@ public: if (midiEventCount >= kPluginMaxMidiEvents) continue; - snd_seq_event_t& midiEvent(fMidiEvents[midiEventCount++]); - carla_zeroStruct(midiEvent); + snd_seq_event_t& seqEvent(fMidiEvents[midiEventCount++]); - midiEvent.time.tick = isSampleAccurate ? startTime : event.time; + seqEvent.time.tick = isSampleAccurate ? startTime : event.time; - midiEvent.type = SND_SEQ_EVENT_CONTROLLER; - midiEvent.data.control.channel = event.channel; - midiEvent.data.control.param = MIDI_CONTROL_ALL_SOUND_OFF; + seqEvent.type = SND_SEQ_EVENT_CONTROLLER; + seqEvent.data.control.channel = event.channel; + seqEvent.data.control.param = MIDI_CONTROL_ALL_SOUND_OFF; } break; @@ -1386,16 +1381,13 @@ public: if (midiEventCount >= kPluginMaxMidiEvents) continue; - snd_seq_event_t& midiEvent(fMidiEvents[midiEventCount++]); - carla_zeroStruct(midiEvent); + snd_seq_event_t& seqEvent(fMidiEvents[midiEventCount++]); - midiEvent.time.tick = isSampleAccurate ? startTime : event.time; + seqEvent.time.tick = isSampleAccurate ? startTime : event.time; - midiEvent.type = SND_SEQ_EVENT_CONTROLLER; - midiEvent.data.control.channel = event.channel; - midiEvent.data.control.param = MIDI_CONTROL_ALL_NOTES_OFF; - - midiEventCount += 1; + seqEvent.type = SND_SEQ_EVENT_CONTROLLER; + seqEvent.data.control.channel = event.channel; + seqEvent.data.control.param = MIDI_CONTROL_ALL_NOTES_OFF; } break; } // switch (ctrlEvent.type) @@ -1406,103 +1398,101 @@ public: if (midiEventCount >= kPluginMaxMidiEvents) continue; - const EngineMidiEvent& engineEvent(event.midi); + const EngineMidiEvent& midiEvent(event.midi); + + if (midiEvent.size > EngineMidiEvent::kDataSize) + continue; - uint8_t status = uint8_t(MIDI_GET_STATUS_FROM_DATA(engineEvent.data)); - uint8_t channel = event.channel; + uint8_t status = uint8_t(MIDI_GET_STATUS_FROM_DATA(midiEvent.data)); // Fix bad note-off (per DSSI spec) - if (MIDI_IS_STATUS_NOTE_ON(status) && engineEvent.data[2] == 0) + if (status == MIDI_STATUS_NOTE_ON && midiEvent.data[2] == 0) status = MIDI_STATUS_NOTE_OFF; - snd_seq_event_t& midiEvent(fMidiEvents[midiEventCount]); - carla_zeroStruct(midiEvent); + snd_seq_event_t& seqEvent(fMidiEvents[midiEventCount++]); - midiEvent.time.tick = isSampleAccurate ? startTime : event.time; + seqEvent.time.tick = isSampleAccurate ? startTime : event.time; switch (status) { case MIDI_STATUS_NOTE_OFF: { - const uint8_t note = engineEvent.data[1]; + const uint8_t note = midiEvent.data[1]; - midiEvent.type = SND_SEQ_EVENT_NOTEOFF; - midiEvent.data.note.channel = channel; - midiEvent.data.note.note = note; + seqEvent.type = SND_SEQ_EVENT_NOTEOFF; + seqEvent.data.note.channel = event.channel; + seqEvent.data.note.note = note; - pData->postponeRtEvent(kPluginPostRtEventNoteOff, channel, note, 0.0f); + pData->postponeRtEvent(kPluginPostRtEventNoteOff, event.channel, note, 0.0f); break; } case MIDI_STATUS_NOTE_ON: { - const uint8_t note = engineEvent.data[1]; - const uint8_t velo = engineEvent.data[2]; + const uint8_t note = midiEvent.data[1]; + const uint8_t velo = midiEvent.data[2]; - midiEvent.type = SND_SEQ_EVENT_NOTEON; - midiEvent.data.note.channel = channel; - midiEvent.data.note.note = note; - midiEvent.data.note.velocity = velo; + seqEvent.type = SND_SEQ_EVENT_NOTEON; + seqEvent.data.note.channel = event.channel; + seqEvent.data.note.note = note; + seqEvent.data.note.velocity = velo; - pData->postponeRtEvent(kPluginPostRtEventNoteOn, channel, note, velo); + pData->postponeRtEvent(kPluginPostRtEventNoteOn, event.channel, note, velo); break; } case MIDI_STATUS_POLYPHONIC_AFTERTOUCH: if (pData->options & PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH) { - const uint8_t note = engineEvent.data[1]; - const uint8_t pressure = engineEvent.data[2]; + const uint8_t note = midiEvent.data[1]; + const uint8_t pressure = midiEvent.data[2]; - midiEvent.type = SND_SEQ_EVENT_KEYPRESS; - midiEvent.data.note.channel = channel; - midiEvent.data.note.note = note; - midiEvent.data.note.velocity = pressure; + seqEvent.type = SND_SEQ_EVENT_KEYPRESS; + seqEvent.data.note.channel = event.channel; + seqEvent.data.note.note = note; + seqEvent.data.note.velocity = pressure; } break; case MIDI_STATUS_CONTROL_CHANGE: if (pData->options & PLUGIN_OPTION_SEND_CONTROL_CHANGES) { - const uint8_t control = engineEvent.data[1]; - const uint8_t value = engineEvent.data[2]; + const uint8_t control = midiEvent.data[1]; + const uint8_t value = midiEvent.data[2]; - midiEvent.type = SND_SEQ_EVENT_CONTROLLER; - midiEvent.data.control.channel = channel; - midiEvent.data.control.param = control; - midiEvent.data.control.value = value; + seqEvent.type = SND_SEQ_EVENT_CONTROLLER; + seqEvent.data.control.channel = event.channel; + seqEvent.data.control.param = control; + seqEvent.data.control.value = value; } break; case MIDI_STATUS_CHANNEL_PRESSURE: if (pData->options & PLUGIN_OPTION_SEND_CHANNEL_PRESSURE) { - const uint8_t pressure = engineEvent.data[1]; + const uint8_t pressure = midiEvent.data[1]; - midiEvent.type = SND_SEQ_EVENT_CHANPRESS; - midiEvent.data.control.channel = channel; - midiEvent.data.control.value = pressure; + seqEvent.type = SND_SEQ_EVENT_CHANPRESS; + seqEvent.data.control.channel = event.channel; + seqEvent.data.control.value = pressure; } break; case MIDI_STATUS_PITCH_WHEEL_CONTROL: if (pData->options & PLUGIN_OPTION_SEND_PITCHBEND) { - const uint8_t lsb = engineEvent.data[1]; - const uint8_t msb = engineEvent.data[2]; + const uint8_t lsb = midiEvent.data[1]; + const uint8_t msb = midiEvent.data[2]; - midiEvent.type = SND_SEQ_EVENT_PITCHBEND; - midiEvent.data.control.channel = channel; - midiEvent.data.control.value = ((msb << 7) | lsb) - 8192; + seqEvent.type = SND_SEQ_EVENT_PITCHBEND; + seqEvent.data.control.channel = event.channel; + seqEvent.data.control.value = ((msb << 7) | lsb) - 8192; } break; default: - continue; + --midiEventCount; break; } // switch (status) - - midiEventCount += 1; - break; - } // case kEngineEventTypeMidi + } break; } // switch (event.type) } @@ -1946,7 +1936,7 @@ public: #if 0 uint8_t midiData[4]; midiData[0] = 0; - midiData[1] = static_cast(MIDI_STATUS_NOTE_ON + channel); + midiData[1] = uint8_t(MIDI_STATUS_NOTE_ON | (channel & MIDI_CHANNEL_BIT)); midiData[2] = note; midiData[3] = velo; @@ -1965,7 +1955,7 @@ public: #if 0 uint8_t midiData[4]; midiData[0] = 0; - midiData[1] = static_cast(MIDI_STATUS_NOTE_OFF + channel); + midiData[1] = uint8_t(MIDI_STATUS_NOTE_ON | (channel & MIDI_CHANNEL_BIT)); midiData[2] = note; midiData[3] = 0; diff --git a/source/backend/plugin/FluidSynthPlugin.cpp b/source/backend/plugin/FluidSynthPlugin.cpp index 803426f95..5eb25c77e 100644 --- a/source/backend/plugin/FluidSynthPlugin.cpp +++ b/source/backend/plugin/FluidSynthPlugin.cpp @@ -1074,7 +1074,6 @@ public: #ifndef BUILD_BRIDGE bool allNotesOffSent = false; #endif - uint32_t time, nEvents = pData->event.portIn->getEventCount(); uint32_t timeOffset = 0; uint32_t nextBankIds[MAX_MIDI_CHANNELS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0 }; @@ -1082,20 +1081,20 @@ public: if (pData->midiprog.current >= 0 && pData->midiprog.count > 0 && pData->ctrlChannel >= 0 && pData->ctrlChannel < MAX_MIDI_CHANNELS) nextBankIds[pData->ctrlChannel] = pData->midiprog.data[pData->midiprog.current].bank; - for (uint32_t i=0; i < nEvents; ++i) + for (uint32_t i=0, numEvents=pData->event.portIn->getEventCount(); i < numEvents; ++i) { const EngineEvent& event(pData->event.portIn->getEvent(i)); - time = event.time; + if (event.time >= frames) + continue; - CARLA_SAFE_ASSERT_CONTINUE(time < frames); - CARLA_SAFE_ASSERT_BREAK(time >= timeOffset); + CARLA_ASSERT_INT2(event.time >= timeOffset, event.time, timeOffset); - if (time > timeOffset) + if (event.time > timeOffset) { - if (processSingle(audioOut, time - timeOffset, timeOffset)) + if (processSingle(audioOut, event.time - timeOffset, timeOffset)) { - timeOffset = time; + timeOffset = event.time; if (pData->midiprog.current >= 0 && pData->midiprog.count > 0 && pData->ctrlChannel >= 0 && pData->ctrlChannel < MAX_MIDI_CHANNELS) nextBankIds[pData->ctrlChannel] = pData->midiprog.data[pData->midiprog.current].bank; @@ -1215,6 +1214,7 @@ public: const uint32_t bankId(nextBankIds[event.channel]); const uint32_t progId(ctrlEvent.param); + // TODO int32_t midiprog.find(bank, prog) for (uint32_t k=0; k < pData->midiprog.count; ++k) { if (pData->midiprog.data[k].bank == bankId && pData->midiprog.data[k].program == progId) @@ -1265,66 +1265,85 @@ public: break; } - case kEngineEventTypeMidi: - { + case kEngineEventTypeMidi: { const EngineMidiEvent& midiEvent(event.midi); - uint8_t status = uint8_t(MIDI_GET_STATUS_FROM_DATA(midiEvent.data)); - uint8_t channel = event.channel; + if (midiEvent.size > EngineMidiEvent::kDataSize) + continue; + + uint8_t status = uint8_t(MIDI_GET_STATUS_FROM_DATA(midiEvent.data)); // Fix bad note-off - if (MIDI_IS_STATUS_NOTE_ON(status) && midiEvent.data[2] == 0) + if (status == MIDI_STATUS_NOTE_ON && midiEvent.data[2] == 0) status = MIDI_STATUS_NOTE_OFF; - if (MIDI_IS_STATUS_NOTE_OFF(status)) + switch (status) { + case MIDI_STATUS_NOTE_OFF: { const uint8_t note = midiEvent.data[1]; - fluid_synth_noteoff(fSynth, channel, note); + fluid_synth_noteoff(fSynth, event.channel, note); - pData->postponeRtEvent(kPluginPostRtEventNoteOff, channel, note, 0.0f); + pData->postponeRtEvent(kPluginPostRtEventNoteOff, event.channel, note, 0.0f); + break; } - else if (MIDI_IS_STATUS_NOTE_ON(status)) - { + + case MIDI_STATUS_NOTE_ON: { const uint8_t note = midiEvent.data[1]; const uint8_t velo = midiEvent.data[2]; - fluid_synth_noteon(fSynth, channel, note, velo); + fluid_synth_noteon(fSynth, event.channel, note, velo); - pData->postponeRtEvent(kPluginPostRtEventNoteOn, channel, note, velo); + pData->postponeRtEvent(kPluginPostRtEventNoteOn, event.channel, note, velo); + break; } - else if (MIDI_IS_STATUS_POLYPHONIC_AFTERTOUCH(status) && (pData->options & PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH) != 0) - { - //const uint8_t note = midiEvent.data[1]; - //const uint8_t pressure = midiEvent.data[2]; - // TODO, not in fluidsynth API - } - else if (MIDI_IS_STATUS_CONTROL_CHANGE(status) && (pData->options & PLUGIN_OPTION_SEND_CONTROL_CHANGES) != 0) - { - const uint8_t control = midiEvent.data[1]; - const uint8_t value = midiEvent.data[2]; + case MIDI_STATUS_POLYPHONIC_AFTERTOUCH: + if (pData->options & PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH) + { + //const uint8_t note = midiEvent.data[1]; + //const uint8_t pressure = midiEvent.data[2]; - fluid_synth_cc(fSynth, channel, control, value); - } - else if (MIDI_IS_STATUS_CHANNEL_PRESSURE(status) && (pData->options & PLUGIN_OPTION_SEND_CHANNEL_PRESSURE) != 0) - { - const uint8_t pressure = midiEvent.data[1]; + // not in fluidsynth API + } + break; - fluid_synth_channel_pressure(fSynth, channel, pressure);; - } - else if (MIDI_IS_STATUS_PITCH_WHEEL_CONTROL(status) && (pData->options & PLUGIN_OPTION_SEND_PITCHBEND) != 0) - { - const uint8_t lsb = midiEvent.data[1]; - const uint8_t msb = midiEvent.data[2]; - const int value = ((msb << 7) | lsb); + case MIDI_STATUS_CONTROL_CHANGE: + if (pData->options & PLUGIN_OPTION_SEND_CONTROL_CHANGES) + { + const uint8_t control = midiEvent.data[1]; + const uint8_t value = midiEvent.data[2]; - fluid_synth_pitch_bend(fSynth, channel, value); - } + fluid_synth_cc(fSynth, event.channel, control, value); + } + break; - break; - } - } + case MIDI_STATUS_CHANNEL_PRESSURE: + if (pData->options & PLUGIN_OPTION_SEND_CHANNEL_PRESSURE) + { + const uint8_t pressure = midiEvent.data[1]; + + fluid_synth_channel_pressure(fSynth, event.channel, pressure);; + } + break; + + case MIDI_STATUS_PITCH_WHEEL_CONTROL: + if (pData->options & PLUGIN_OPTION_SEND_PITCHBEND) + { + const uint8_t lsb = midiEvent.data[1]; + const uint8_t msb = midiEvent.data[2]; + const int value = ((msb << 7) | lsb); + + fluid_synth_pitch_bend(fSynth, event.channel, value); + } + break; + + default: + continue; + break; + } // switch (status) + } break; + } // switch (event.type) } pData->postRtEvents.trySplice(); diff --git a/source/backend/plugin/JucePlugin.cpp b/source/backend/plugin/JucePlugin.cpp index 47baaa1e7..b43f357e9 100644 --- a/source/backend/plugin/JucePlugin.cpp +++ b/source/backend/plugin/JucePlugin.cpp @@ -609,7 +609,7 @@ public: CARLA_SAFE_ASSERT_CONTINUE(note.channel >= 0 && note.channel < MAX_MIDI_CHANNELS); uint8_t midiEvent[3]; - midiEvent[0] = static_cast((note.velo > 0 ? MIDI_STATUS_NOTE_ON : MIDI_STATUS_NOTE_OFF) | (note.channel & MIDI_CHANNEL_BIT)); + midiEvent[0] = uint8_t((note.velo > 0 ? MIDI_STATUS_NOTE_ON : MIDI_STATUS_NOTE_OFF) | (note.channel & MIDI_CHANNEL_BIT)); midiEvent[1] = note.note; midiEvent[2] = note.velo; @@ -627,7 +627,6 @@ public: #ifndef BUILD_BRIDGE bool allNotesOffSent = false; #endif - uint32_t numEvents = pData->event.portIn->getEventCount(); uint32_t nextBankId; if (pData->midiprog.current >= 0 && pData->midiprog.count > 0) @@ -635,7 +634,7 @@ public: else nextBankId = 0; - for (uint32_t i=0; i < numEvents; ++i) + for (uint32_t i=0, numEvents=pData->event.portIn->getEventCount(); i < numEvents; ++i) { const EngineEvent& event(pData->event.portIn->getEvent(i)); @@ -746,8 +745,8 @@ public: if ((pData->options & PLUGIN_OPTION_SEND_CONTROL_CHANGES) != 0 && ctrlEvent.param <= 0x5F) { uint8_t midiData[3]; - midiData[0] = static_cast(MIDI_STATUS_CONTROL_CHANGE + i); - midiData[1] = static_cast(ctrlEvent.param); + midiData[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (event.channel & MIDI_CHANNEL_BIT)); + midiData[1] = uint8_t(ctrlEvent.param); midiData[2] = uint8_t(ctrlEvent.value*127.0f); fMidiBuffer.addEvent(midiData, 3, static_cast(event.time)); @@ -782,7 +781,7 @@ public: if (pData->options & PLUGIN_OPTION_SEND_ALL_SOUND_OFF) { uint8_t midiData[3]; - midiData[0] = static_cast(MIDI_STATUS_CONTROL_CHANGE + i); + midiData[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (event.channel & MIDI_CHANNEL_BIT)); midiData[1] = MIDI_CONTROL_ALL_SOUND_OFF; midiData[2] = 0; @@ -802,7 +801,7 @@ public: #endif uint8_t midiData[3]; - midiData[0] = static_cast(MIDI_STATUS_CONTROL_CHANGE + i); + midiData[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (event.channel & MIDI_CHANNEL_BIT)); midiData[1] = MIDI_CONTROL_ALL_NOTES_OFF; midiData[2] = 0; @@ -813,16 +812,12 @@ public: break; } // case kEngineEventTypeControl - case kEngineEventTypeMidi: - { + case kEngineEventTypeMidi: { const EngineMidiEvent& midiEvent(event.midi); - uint8_t status = uint8_t(MIDI_GET_STATUS_FROM_DATA(midiEvent.data)); - uint8_t channel = event.channel; + const uint8_t* const midiData(midiEvent.size > EngineMidiEvent::kDataSize ? midiEvent.dataExt : midiEvent.data); - // Fix bad note-off - if (MIDI_IS_STATUS_NOTE_ON(status) && midiEvent.data[2] == 0) - status = MIDI_STATUS_NOTE_OFF; + uint8_t status = uint8_t(MIDI_GET_STATUS_FROM_DATA(midiData)); if (status == MIDI_STATUS_CHANNEL_PRESSURE && (pData->options & PLUGIN_OPTION_SEND_CHANNEL_PRESSURE) == 0) continue; @@ -833,15 +828,22 @@ public: if (status == MIDI_STATUS_PITCH_WHEEL_CONTROL && (pData->options & PLUGIN_OPTION_SEND_PITCHBEND) == 0) continue; - fMidiBuffer.addEvent(midiEvent.data, midiEvent.size, static_cast(event.time)); + // Fix bad note-off + if (status == MIDI_STATUS_NOTE_ON && midiData[2] == 0) + status = MIDI_STATUS_NOTE_OFF; + + // put back channel in data + uint8_t midiData2[midiEvent.size]; + midiData2[0] = uint8_t(status | (event.channel & MIDI_CHANNEL_BIT)); + std::memcpy(midiData2+1, midiData+1, static_cast(midiEvent.size-1)); + + fMidiBuffer.addEvent(midiData2, midiEvent.size, static_cast(event.time)); if (status == MIDI_STATUS_NOTE_ON) - pData->postponeRtEvent(kPluginPostRtEventNoteOn, channel, midiEvent.data[1], midiEvent.data[2]); + pData->postponeRtEvent(kPluginPostRtEventNoteOn, event.channel, midiData[1], midiData[2]); else if (status == MIDI_STATUS_NOTE_OFF) - pData->postponeRtEvent(kPluginPostRtEventNoteOff, channel, midiEvent.data[1], 0.0f); - - break; - } // case kEngineEventTypeMidi + pData->postponeRtEvent(kPluginPostRtEventNoteOff, event.channel, midiData[1], 0.0f); + } break; } // switch (event.type) } diff --git a/source/backend/plugin/LinuxSamplerPlugin.cpp b/source/backend/plugin/LinuxSamplerPlugin.cpp index 2543d4581..6400f7673 100644 --- a/source/backend/plugin/LinuxSamplerPlugin.cpp +++ b/source/backend/plugin/LinuxSamplerPlugin.cpp @@ -799,11 +799,10 @@ public: #endif bool sampleAccurate = (pData->options & PLUGIN_OPTION_FIXED_BUFFERS) == 0; - uint32_t nEvents = pData->event.portIn->getEventCount(); uint32_t startTime = 0; uint32_t timeOffset = 0; - for (uint32_t i=0; i < nEvents; ++i) + for (uint32_t i=0, numEvents=pData->event.portIn->getEventCount(); i < numEvents; ++i) { const EngineEvent& event(pData->event.portIn->getEvent(i)); @@ -982,42 +981,38 @@ public: break; } - case kEngineEventTypeMidi: - { + case kEngineEventTypeMidi: { const EngineMidiEvent& midiEvent(event.midi); - uint8_t status = uint8_t(MIDI_GET_STATUS_FROM_DATA(midiEvent.data)); - uint8_t channel = event.channel; + const uint8_t* const midiData(midiEvent.size > EngineMidiEvent::kDataSize ? midiEvent.dataExt : midiEvent.data); - // Fix bad note-off - if (MIDI_IS_STATUS_NOTE_ON(status) && midiEvent.data[2] == 0) - status = MIDI_STATUS_NOTE_OFF; + uint8_t status = uint8_t(MIDI_GET_STATUS_FROM_DATA(midiData)); - if (MIDI_IS_STATUS_POLYPHONIC_AFTERTOUCH(status) && (pData->options & PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH) == 0) + if (status == MIDI_STATUS_CHANNEL_PRESSURE && (pData->options & PLUGIN_OPTION_SEND_CHANNEL_PRESSURE) == 0) continue; - if (MIDI_IS_STATUS_CONTROL_CHANGE(status) && (pData->options & PLUGIN_OPTION_SEND_CONTROL_CHANGES) == 0) + if (status == MIDI_STATUS_CONTROL_CHANGE && (pData->options & PLUGIN_OPTION_SEND_CONTROL_CHANGES) == 0) continue; - if (MIDI_IS_STATUS_CHANNEL_PRESSURE(status) && (pData->options & PLUGIN_OPTION_SEND_CHANNEL_PRESSURE) == 0) + if (status == MIDI_STATUS_POLYPHONIC_AFTERTOUCH && (pData->options & PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH) == 0) continue; - if (MIDI_IS_STATUS_PITCH_WHEEL_CONTROL(status) && (pData->options & PLUGIN_OPTION_SEND_PITCHBEND) == 0) + if (status == MIDI_STATUS_PITCH_WHEEL_CONTROL && (pData->options & PLUGIN_OPTION_SEND_PITCHBEND) == 0) continue; - // put back channel in data - uint8_t data[EngineMidiEvent::kDataSize]; - std::memcpy(data, event.midi.data, EngineMidiEvent::kDataSize); + // Fix bad note-off + if (status == MIDI_STATUS_NOTE_ON && midiData[2] == 0) + status = MIDI_STATUS_NOTE_OFF; - if (status < 0xF0 && channel < MAX_MIDI_CHANNELS) - data[0] = uint8_t(data[0] + channel); + // put back channel in data + uint8_t midiData2[midiEvent.size]; + midiData2[0] = uint8_t(status | (event.channel & MIDI_CHANNEL_BIT)); + std::memcpy(midiData2+1, midiData+1, static_cast(midiEvent.size-1)); - fMidiInputPort->DispatchRaw(data, static_cast(sampleAccurate ? startTime : event.time)); + fMidiInputPort->DispatchRaw(midiData2, static_cast(sampleAccurate ? startTime : event.time)); if (status == MIDI_STATUS_NOTE_ON) - pData->postponeRtEvent(kPluginPostRtEventNoteOn, channel, data[1], data[2]); + pData->postponeRtEvent(kPluginPostRtEventNoteOn, event.channel, midiData[1], midiData[2]); else if (status == MIDI_STATUS_NOTE_OFF) - pData->postponeRtEvent(kPluginPostRtEventNoteOff, channel,data[1], 0.0f); - - break; - } + pData->postponeRtEvent(kPluginPostRtEventNoteOff, event.channel, midiData[1], 0.0f); + } break; } } diff --git a/source/backend/plugin/Lv2Plugin.cpp b/source/backend/plugin/Lv2Plugin.cpp index b5d92f46a..ccb7e8e6e 100644 --- a/source/backend/plugin/Lv2Plugin.cpp +++ b/source/backend/plugin/Lv2Plugin.cpp @@ -2517,7 +2517,7 @@ public: if (pData->needsReset) { - uint8_t midiData[3] = { 0 }; + uint8_t midiData[3] = { 0, 0, 0 }; if (fEventsIn.ctrl != nullptr && (fEventsIn.ctrl->type & CARLA_EVENT_TYPE_MIDI) != 0) { @@ -2527,7 +2527,7 @@ public: { for (uint8_t i=0; i < MAX_MIDI_CHANNELS; ++i) { - midiData[0] = static_cast(MIDI_STATUS_CONTROL_CHANGE + i); + midiData[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (i & MIDI_CHANNEL_BIT)); midiData[1] = MIDI_CONTROL_ALL_NOTES_OFF; if (fEventsIn.ctrl->type & CARLA_EVENT_DATA_ATOM) @@ -2539,7 +2539,7 @@ public: else if (fEventsIn.ctrl->type & CARLA_EVENT_DATA_MIDI_LL) lv2midi_put_event(&evInMidiStates[j], 0.0, 3, midiData); - midiData[0] = static_cast(MIDI_STATUS_CONTROL_CHANGE + i); + midiData[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (i & MIDI_CHANNEL_BIT)); midiData[1] = MIDI_CONTROL_ALL_SOUND_OFF; if (fEventsIn.ctrl->type & CARLA_EVENT_DATA_ATOM) @@ -2556,7 +2556,7 @@ public: { for (uint8_t k=0; k < MAX_MIDI_NOTE; ++k) { - midiData[0] = static_cast(MIDI_STATUS_NOTE_OFF + pData->ctrlChannel); + midiData[0] = uint8_t(MIDI_STATUS_NOTE_OFF | (pData->ctrlChannel & MIDI_CHANNEL_BIT)); midiData[1] = k; if (fEventsIn.ctrl->type & CARLA_EVENT_DATA_ATOM) @@ -2796,7 +2796,7 @@ public: CARLA_SAFE_ASSERT_CONTINUE(note.channel >= 0 && note.channel < MAX_MIDI_CHANNELS); uint8_t midiEvent[3]; - midiEvent[0] = static_cast((note.velo > 0 ? MIDI_STATUS_NOTE_ON : MIDI_STATUS_NOTE_OFF) | (note.channel & MIDI_CHANNEL_BIT)); + midiEvent[0] = uint8_t((note.velo > 0 ? MIDI_STATUS_NOTE_ON : MIDI_STATUS_NOTE_OFF) | (note.channel & MIDI_CHANNEL_BIT)); midiEvent[1] = note.note; midiEvent[2] = note.velo; @@ -2825,7 +2825,6 @@ public: #endif bool isSampleAccurate = (pData->options & PLUGIN_OPTION_FIXED_BUFFERS) == 0; - uint32_t numEvents = (fEventsIn.ctrl->port != nullptr) ? fEventsIn.ctrl->port->getEventCount() : 0; uint32_t startTime = 0; uint32_t timeOffset = 0; uint32_t nextBankId; @@ -2835,6 +2834,8 @@ public: else nextBankId = 0; + const uint32_t numEvents = (fEventsIn.ctrl->port != nullptr) ? fEventsIn.ctrl->port->getEventCount() : 0; + for (uint32_t i=0; i < numEvents; ++i) { const EngineEvent& event(fEventsIn.ctrl->port->getEvent(i)); @@ -2984,8 +2985,8 @@ public: if ((pData->options & PLUGIN_OPTION_SEND_CONTROL_CHANGES) != 0 && ctrlEvent.param <= 0x5F) { uint8_t midiData[3]; - midiData[0] = static_cast(MIDI_STATUS_CONTROL_CHANGE + i); - midiData[1] = static_cast(ctrlEvent.param); + midiData[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (event.channel & MIDI_CHANNEL_BIT)); + midiData[1] = uint8_t(ctrlEvent.param); midiData[2] = uint8_t(ctrlEvent.value*127.0f); const uint32_t mtime(isSampleAccurate ? startTime : event.time); @@ -3031,7 +3032,7 @@ public: const uint32_t mtime(isSampleAccurate ? startTime : event.time); uint8_t midiData[3]; - midiData[0] = static_cast(MIDI_STATUS_CONTROL_CHANGE + i); + midiData[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (event.channel & MIDI_CHANNEL_BIT)); midiData[1] = MIDI_CONTROL_ALL_SOUND_OFF; midiData[2] = 0; @@ -3060,7 +3061,7 @@ public: const uint32_t mtime(isSampleAccurate ? startTime : event.time); uint8_t midiData[3]; - midiData[0] = static_cast(MIDI_STATUS_CONTROL_CHANGE + i); + midiData[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (event.channel & MIDI_CHANNEL_BIT)); midiData[1] = MIDI_CONTROL_ALL_NOTES_OFF; midiData[2] = 0; @@ -3078,17 +3079,12 @@ public: break; } // case kEngineEventTypeControl - case kEngineEventTypeMidi: - { + case kEngineEventTypeMidi: { const EngineMidiEvent& midiEvent(event.midi); - uint8_t status = uint8_t(MIDI_GET_STATUS_FROM_DATA(midiEvent.data)); - uint8_t channel = event.channel; - uint32_t mtime = isSampleAccurate ? startTime : event.time; + const uint8_t* const midiData(midiEvent.size > EngineMidiEvent::kDataSize ? midiEvent.dataExt : midiEvent.data); - // Fix bad note-off (per LV2 spec) - if (MIDI_IS_STATUS_NOTE_ON(status) && midiEvent.data[2] == 0) - status = MIDI_STATUS_NOTE_OFF; + uint8_t status = uint8_t(MIDI_GET_STATUS_FROM_DATA(midiData)); if (status == MIDI_STATUS_CHANNEL_PRESSURE && (pData->options & PLUGIN_OPTION_SEND_CHANNEL_PRESSURE) == 0) continue; @@ -3099,24 +3095,32 @@ public: if (status == MIDI_STATUS_PITCH_WHEEL_CONTROL && (pData->options & PLUGIN_OPTION_SEND_PITCHBEND) == 0) continue; - const uint32_t j = fEventsIn.ctrlIndex; + // Fix bad note-off (per LV2 spec) + if (status == MIDI_STATUS_NOTE_ON && midiData[2] == 0) + status = MIDI_STATUS_NOTE_OFF; + + const uint32_t j = fEventsIn.ctrlIndex; + const uint32_t mtime = isSampleAccurate ? startTime : event.time; + + // put back channel in data + uint8_t midiData2[midiEvent.size]; + midiData2[0] = uint8_t(status | (event.channel & MIDI_CHANNEL_BIT)); + std::memcpy(midiData2+1, midiData+1, static_cast(midiEvent.size-1)); if (fEventsIn.ctrl->type & CARLA_EVENT_DATA_ATOM) - lv2_atom_buffer_write(&evInAtomIters[j], mtime, 0, CARLA_URI_MAP_ID_MIDI_EVENT, midiEvent.size, midiEvent.data); + lv2_atom_buffer_write(&evInAtomIters[j], mtime, 0, CARLA_URI_MAP_ID_MIDI_EVENT, midiEvent.size, midiData2); else if (fEventsIn.ctrl->type & CARLA_EVENT_DATA_EVENT) - lv2_event_write(&evInEventIters[j], mtime, 0, CARLA_URI_MAP_ID_MIDI_EVENT, midiEvent.size, midiEvent.data); + lv2_event_write(&evInEventIters[j], mtime, 0, CARLA_URI_MAP_ID_MIDI_EVENT, midiEvent.size, midiData2); else if (fEventsIn.ctrl->type & CARLA_EVENT_DATA_MIDI_LL) - lv2midi_put_event(&evInMidiStates[j], mtime, midiEvent.size, midiEvent.data); + lv2midi_put_event(&evInMidiStates[j], mtime, midiEvent.size, midiData2); if (status == MIDI_STATUS_NOTE_ON) - pData->postponeRtEvent(kPluginPostRtEventNoteOn, channel, midiEvent.data[1], midiEvent.data[2]); + pData->postponeRtEvent(kPluginPostRtEventNoteOn, event.channel, midiData[1], midiData[2]); else if (status == MIDI_STATUS_NOTE_OFF) - pData->postponeRtEvent(kPluginPostRtEventNoteOff, channel, midiEvent.data[1], 0.0f); - - break; - } // case kEngineEventTypeMidi + pData->postponeRtEvent(kPluginPostRtEventNoteOff, event.channel, midiData[1], 0.0f); + } break; } // switch (event.type) } @@ -3773,7 +3777,7 @@ public: if (pData->osc.data.target != nullptr) { uint8_t midiData[4] = { 0, 0, 0, 0 }; - midiData[1] = static_cast(MIDI_STATUS_NOTE_ON + channel); + midiData[1] = uint8_t(MIDI_STATUS_NOTE_ON | (channel & MIDI_CHANNEL_BIT)); midiData[2] = note; midiData[3] = velo; osc_send_midi(pData->osc.data, midiData); @@ -3787,7 +3791,7 @@ public: midiEv.event.time.frames = 0; midiEv.event.body.type = CARLA_URI_MAP_ID_MIDI_EVENT; midiEv.event.body.size = 3; - midiEv.data[0] = static_cast(MIDI_STATUS_NOTE_ON + channel); + midiEv.data[0] = uint8_t(MIDI_STATUS_NOTE_ON | (channel & MIDI_CHANNEL_BIT)); midiEv.data[1] = note; midiEv.data[2] = velo; @@ -3807,7 +3811,7 @@ public: if (pData->osc.data.target != nullptr) { uint8_t midiData[4] = { 0, 0, 0, 0 }; - midiData[1] = static_cast(MIDI_STATUS_NOTE_OFF + channel); + midiData[1] = uint8_t(MIDI_STATUS_NOTE_OFF | (channel & MIDI_CHANNEL_BIT)); midiData[2] = note; osc_send_midi(pData->osc.data, midiData); } @@ -3820,7 +3824,7 @@ public: midiEv.event.time.frames = 0; midiEv.event.body.type = CARLA_URI_MAP_ID_MIDI_EVENT; midiEv.event.body.size = 3; - midiEv.data[0] = static_cast(MIDI_STATUS_NOTE_OFF + channel); + midiEv.data[0] = uint8_t(MIDI_STATUS_NOTE_OFF | (channel & MIDI_CHANNEL_BIT)); midiEv.data[1] = note; midiEv.data[2] = 0; diff --git a/source/backend/plugin/NativePlugin.cpp b/source/backend/plugin/NativePlugin.cpp index aa8a06fc4..f3abb0572 100644 --- a/source/backend/plugin/NativePlugin.cpp +++ b/source/backend/plugin/NativePlugin.cpp @@ -1302,32 +1302,32 @@ public: { if (pData->options & PLUGIN_OPTION_SEND_ALL_SOUND_OFF) { + fMidiEventCount = MAX_MIDI_CHANNELS*2; + for (uint8_t k=0, i=MAX_MIDI_CHANNELS; k < MAX_MIDI_CHANNELS; ++k) { - fMidiEvents[k].data[0] = static_cast(MIDI_STATUS_CONTROL_CHANGE + k); + fMidiEvents[k].data[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (k & MIDI_CHANNEL_BIT)); fMidiEvents[k].data[1] = MIDI_CONTROL_ALL_NOTES_OFF; fMidiEvents[k].data[2] = 0; fMidiEvents[k].size = 3; - fMidiEvents[k+i].data[0] = static_cast(MIDI_STATUS_CONTROL_CHANGE + k); + fMidiEvents[k+i].data[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (k & MIDI_CHANNEL_BIT)); fMidiEvents[k+i].data[1] = MIDI_CONTROL_ALL_SOUND_OFF; fMidiEvents[k+i].data[2] = 0; fMidiEvents[k+i].size = 3; } - - fMidiEventCount = MAX_MIDI_CHANNELS*2; } else if (pData->ctrlChannel >= 0 && pData->ctrlChannel < MAX_MIDI_CHANNELS) { + fMidiEventCount = MAX_MIDI_NOTE; + for (uint8_t k=0; k < MAX_MIDI_NOTE; ++k) { - fMidiEvents[k].data[0] = static_cast(MIDI_STATUS_NOTE_OFF + pData->ctrlChannel); + fMidiEvents[k].data[0] = uint8_t(MIDI_STATUS_NOTE_OFF | (pData->ctrlChannel & MIDI_CHANNEL_BIT)); fMidiEvents[k].data[1] = k; fMidiEvents[k].data[2] = 0; fMidiEvents[k].size = 3; } - - fMidiEventCount = MAX_MIDI_NOTE; } pData->needsReset = false; @@ -1372,19 +1372,18 @@ public: { ExternalMidiNote note = { 0, 0, 0 }; - //for (RtLinkedList::Itenerator it = pData->extNotes.data.begin(); it.valid(); it.next()) - while (fMidiEventCount < kPluginMaxMidiEvents*2 && ! pData->extNotes.data.isEmpty()) + for (; fMidiEventCount < kPluginMaxMidiEvents*2 && ! pData->extNotes.data.isEmpty();) { note = pData->extNotes.data.getFirst(note, true); CARLA_SAFE_ASSERT_CONTINUE(note.channel >= 0 && note.channel < MAX_MIDI_CHANNELS); - fMidiEvents[fMidiEventCount].data[0] = static_cast((note.velo > 0 ? MIDI_STATUS_NOTE_ON : MIDI_STATUS_NOTE_OFF) | (note.channel & MIDI_CHANNEL_BIT)); - fMidiEvents[fMidiEventCount].data[1] = note.note; - fMidiEvents[fMidiEventCount].data[2] = note.velo; - fMidiEvents[fMidiEventCount].size = 3; + NativeMidiEvent& nativeEvent(fMidiEvents[fMidiEventCount++]); - fMidiEventCount += 1; + nativeEvent.data[0] = uint8_t((note.velo > 0 ? MIDI_STATUS_NOTE_ON : MIDI_STATUS_NOTE_OFF) | (note.channel & MIDI_CHANNEL_BIT)); + nativeEvent.data[1] = note.note; + nativeEvent.data[2] = note.velo; + nativeEvent.size = 3; } pData->extNotes.mutex.unlock(); @@ -1399,31 +1398,30 @@ public: #endif bool sampleAccurate = (pData->options & PLUGIN_OPTION_FIXED_BUFFERS) == 0; - uint32_t time, nEvents = pData->event.portIn->getEventCount(); uint32_t startTime = 0; uint32_t timeOffset = 0; - uint32_t nextBankId = 0; + uint32_t nextBankId; if (pData->midiprog.current >= 0 && pData->midiprog.count > 0) nextBankId = pData->midiprog.data[pData->midiprog.current].bank; + else + nextBankId = 0; - for (uint32_t i=0; i < nEvents; ++i) + for (uint32_t i=0, numEvents=pData->event.portIn->getEventCount(); i < numEvents; ++i) { const EngineEvent& event(pData->event.portIn->getEvent(i)); - time = event.time; - - if (time >= frames) + if (event.time >= frames) continue; - CARLA_ASSERT_INT2(time >= timeOffset, time, timeOffset); + CARLA_ASSERT_INT2(event.time >= timeOffset, event.time, timeOffset); - if (time > timeOffset && sampleAccurate) + if (event.time > timeOffset && sampleAccurate) { - if (processSingle(audioIn, audioOut, cvIn, cvOut, time - timeOffset, timeOffset)) + if (processSingle(audioIn, audioOut, cvIn, cvOut, event.time - timeOffset, timeOffset)) { startTime = 0; - timeOffset = time; + timeOffset = event.time; if (pData->midiprog.current >= 0 && pData->midiprog.count > 0) nextBankId = pData->midiprog.data[pData->midiprog.current].bank; @@ -1538,14 +1536,14 @@ public: if (fMidiEventCount >= kPluginMaxMidiEvents*2) continue; - fMidiEvents[fMidiEventCount].port = 0; - fMidiEvents[fMidiEventCount].time = sampleAccurate ? startTime : time; - fMidiEvents[fMidiEventCount].data[0] = static_cast(MIDI_STATUS_CONTROL_CHANGE + event.channel); - fMidiEvents[fMidiEventCount].data[1] = static_cast(ctrlEvent.param); - fMidiEvents[fMidiEventCount].data[2] = uint8_t(ctrlEvent.value*127.0f); - fMidiEvents[fMidiEventCount].size = 3; + NativeMidiEvent& nativeEvent(fMidiEvents[fMidiEventCount++]); + carla_zeroStruct(nativeEvent); - fMidiEventCount += 1; + nativeEvent.time = sampleAccurate ? startTime : event.time; + nativeEvent.data[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (event.channel & MIDI_CHANNEL_BIT)); + nativeEvent.data[1] = uint8_t(ctrlEvent.param); + nativeEvent.data[2] = uint8_t(ctrlEvent.value*127.0f); + nativeEvent.size = 3; } break; } @@ -1586,14 +1584,15 @@ public: if (fMidiEventCount >= kPluginMaxMidiEvents*2) continue; - fMidiEvents[fMidiEventCount].port = 0; - fMidiEvents[fMidiEventCount].time = sampleAccurate ? startTime : time; - fMidiEvents[fMidiEventCount].data[0] = static_cast(MIDI_STATUS_CONTROL_CHANGE + event.channel); - fMidiEvents[fMidiEventCount].data[1] = MIDI_CONTROL_ALL_SOUND_OFF; - fMidiEvents[fMidiEventCount].data[2] = 0; - fMidiEvents[fMidiEventCount].size = 3; + NativeMidiEvent& nativeEvent(fMidiEvents[fMidiEventCount++]); + carla_zeroStruct(nativeEvent); - fMidiEventCount += 1; + nativeEvent.port = 0; + nativeEvent.time = sampleAccurate ? startTime : event.time; + nativeEvent.data[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (event.channel & MIDI_CHANNEL_BIT)); + nativeEvent.data[1] = MIDI_CONTROL_ALL_SOUND_OFF; + nativeEvent.data[2] = 0; + nativeEvent.size = 3; } break; @@ -1611,14 +1610,14 @@ public: if (fMidiEventCount >= kPluginMaxMidiEvents*2) continue; - fMidiEvents[fMidiEventCount].port = 0; - fMidiEvents[fMidiEventCount].time = sampleAccurate ? startTime : time; - fMidiEvents[fMidiEventCount].data[0] = static_cast(MIDI_STATUS_CONTROL_CHANGE + event.channel); - fMidiEvents[fMidiEventCount].data[1] = MIDI_CONTROL_ALL_NOTES_OFF; - fMidiEvents[fMidiEventCount].data[2] = 0; - fMidiEvents[fMidiEventCount].size = 3; + NativeMidiEvent& nativeEvent(fMidiEvents[fMidiEventCount++]); + carla_zeroStruct(nativeEvent); - fMidiEventCount += 1; + nativeEvent.time = sampleAccurate ? startTime : event.time; + nativeEvent.data[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (event.channel & MIDI_CHANNEL_BIT)); + nativeEvent.data[1] = MIDI_CONTROL_ALL_NOTES_OFF; + nativeEvent.data[2] = 0; + nativeEvent.size = 3; } break; } @@ -1631,41 +1630,43 @@ public: const EngineMidiEvent& midiEvent(event.midi); - uint8_t status = uint8_t(MIDI_GET_STATUS_FROM_DATA(midiEvent.data)); - uint8_t channel = event.channel; + if (midiEvent.size > 4) + continue; + static_assert(4 <= EngineMidiEvent::kDataSize, "Incorrect data"); + + uint8_t status = uint8_t(MIDI_GET_STATUS_FROM_DATA(midiEvent.data)); - if (MIDI_IS_STATUS_CHANNEL_PRESSURE(status) && (pData->options & PLUGIN_OPTION_SEND_CHANNEL_PRESSURE) == 0) + if (status == MIDI_STATUS_CHANNEL_PRESSURE && (pData->options & PLUGIN_OPTION_SEND_CHANNEL_PRESSURE) == 0) continue; - if (MIDI_IS_STATUS_CONTROL_CHANGE(status) && (pData->options & PLUGIN_OPTION_SEND_CONTROL_CHANGES) == 0) + if (status == MIDI_STATUS_CONTROL_CHANGE && (pData->options & PLUGIN_OPTION_SEND_CONTROL_CHANGES) == 0) continue; - if (MIDI_IS_STATUS_POLYPHONIC_AFTERTOUCH(status) && (pData->options & PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH) == 0) + if (status == MIDI_STATUS_POLYPHONIC_AFTERTOUCH && (pData->options & PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH) == 0) continue; - if (MIDI_IS_STATUS_PITCH_WHEEL_CONTROL(status) && (pData->options & PLUGIN_OPTION_SEND_PITCHBEND) == 0) + if (status == MIDI_STATUS_PITCH_WHEEL_CONTROL && (pData->options & PLUGIN_OPTION_SEND_PITCHBEND) == 0) continue; // Fix bad note-off if (status == MIDI_STATUS_NOTE_ON && midiEvent.data[2] == 0) status = MIDI_STATUS_NOTE_OFF; - fMidiEvents[fMidiEventCount].port = 0; - fMidiEvents[fMidiEventCount].time = sampleAccurate ? startTime : time; - fMidiEvents[fMidiEventCount].size = midiEvent.size; + NativeMidiEvent& nativeEvent(fMidiEvents[fMidiEventCount++]); + carla_zeroStruct(nativeEvent); - fMidiEvents[fMidiEventCount].data[0] = static_cast(status + channel); - fMidiEvents[fMidiEventCount].data[1] = midiEvent.data[1]; - fMidiEvents[fMidiEventCount].data[2] = midiEvent.data[2]; - fMidiEvents[fMidiEventCount].data[3] = midiEvent.data[3]; + nativeEvent.port = midiEvent.port; + nativeEvent.time = sampleAccurate ? startTime : event.time; + nativeEvent.size = midiEvent.size; - fMidiEventCount += 1; + nativeEvent.data[0] = uint8_t(status | (event.channel & MIDI_CHANNEL_BIT)); + nativeEvent.data[1] = midiEvent.size >= 2 ? midiEvent.data[1] : 0; + nativeEvent.data[2] = midiEvent.size >= 3 ? midiEvent.data[2] : 0; + nativeEvent.data[3] = midiEvent.size == 4 ? midiEvent.data[3] : 0; if (status == MIDI_STATUS_NOTE_ON) - pData->postponeRtEvent(kPluginPostRtEventNoteOn, channel, midiEvent.data[1], midiEvent.data[2]); + pData->postponeRtEvent(kPluginPostRtEventNoteOn, event.channel, midiEvent.data[1], midiEvent.data[2]); else if (status == MIDI_STATUS_NOTE_OFF) - pData->postponeRtEvent(kPluginPostRtEventNoteOff, channel, midiEvent.data[1], 0.0f); - - break; - } - } + pData->postponeRtEvent(kPluginPostRtEventNoteOff, event.channel, midiEvent.data[1], 0.0f); + } break; + } // switch (event.type) } pData->postRtEvents.trySplice(); diff --git a/source/backend/plugin/VstPlugin.cpp b/source/backend/plugin/VstPlugin.cpp index ac2f27e51..8c3dd1719 100644 --- a/source/backend/plugin/VstPlugin.cpp +++ b/source/backend/plugin/VstPlugin.cpp @@ -47,6 +47,8 @@ const uint PLUGIN_HAS_COCKOS_EXTENSIONS = 0x2000; const uint PLUGIN_USES_OLD_VSTSDK = 0x4000; const uint PLUGIN_WANTS_MIDI_INPUT = 0x8000; +static const int32_t kVstMidiEventSize = static_cast(sizeof(VstMidiEvent)); + // ----------------------------------------------------- class VstPlugin : public CarlaPlugin, @@ -1083,13 +1085,13 @@ public: for (uint8_t i=0, k=MAX_MIDI_CHANNELS; i < MAX_MIDI_CHANNELS; ++i) { fMidiEvents[k].type = kVstMidiType; - fMidiEvents[k].byteSize = static_cast(sizeof(VstMidiEvent)); - fMidiEvents[k].midiData[0] = static_cast(MIDI_STATUS_CONTROL_CHANGE + k); + fMidiEvents[k].byteSize = kVstMidiEventSize; + fMidiEvents[k].midiData[0] = char(MIDI_STATUS_CONTROL_CHANGE | (k & MIDI_CHANNEL_BIT)); fMidiEvents[k].midiData[1] = MIDI_CONTROL_ALL_NOTES_OFF; fMidiEvents[k+i].type = kVstMidiType; - fMidiEvents[k+i].byteSize = static_cast(sizeof(VstMidiEvent)); - fMidiEvents[k+i].midiData[0] = static_cast(MIDI_STATUS_CONTROL_CHANGE + k); + fMidiEvents[k+i].byteSize = kVstMidiEventSize; + fMidiEvents[k+i].midiData[0] = char(MIDI_STATUS_CONTROL_CHANGE | (k & MIDI_CHANNEL_BIT)); fMidiEvents[k+i].midiData[1] = MIDI_CONTROL_ALL_SOUND_OFF; } } @@ -1100,9 +1102,9 @@ public: for (uint8_t i=0; i < MAX_MIDI_NOTE; ++i) { fMidiEvents[i].type = kVstMidiType; - fMidiEvents[i].byteSize = static_cast(sizeof(VstMidiEvent)); - fMidiEvents[i].midiData[0] = static_cast(MIDI_STATUS_NOTE_OFF + pData->ctrlChannel); - fMidiEvents[i].midiData[1] = static_cast(i); + fMidiEvents[i].byteSize = kVstMidiEventSize; + fMidiEvents[i].midiData[0] = char(MIDI_STATUS_NOTE_OFF | (pData->ctrlChannel & MIDI_CHANNEL_BIT)); + fMidiEvents[i].midiData[1] = char(i); } } @@ -1193,13 +1195,13 @@ public: CARLA_SAFE_ASSERT_CONTINUE(note.channel >= 0 && note.channel < MAX_MIDI_CHANNELS); - fMidiEvents[fMidiEventCount].type = kVstMidiType; - fMidiEvents[fMidiEventCount].byteSize = static_cast(sizeof(VstMidiEvent)); - fMidiEvents[fMidiEventCount].midiData[0] = static_cast((note.velo > 0 ? MIDI_STATUS_NOTE_ON : MIDI_STATUS_NOTE_OFF) | (note.channel & MIDI_CHANNEL_BIT)); - fMidiEvents[fMidiEventCount].midiData[1] = static_cast(note.note); - fMidiEvents[fMidiEventCount].midiData[2] = static_cast(note.velo); + VstMidiEvent& vstMidiEvent(fMidiEvents[fMidiEventCount++]); - ++fMidiEventCount; + vstMidiEvent.type = kVstMidiType; + vstMidiEvent.byteSize = kVstMidiEventSize; + vstMidiEvent.midiData[0] = char((note.velo > 0 ? MIDI_STATUS_NOTE_ON : MIDI_STATUS_NOTE_OFF) | (note.channel & MIDI_CHANNEL_BIT)); + vstMidiEvent.midiData[1] = char(note.note); + vstMidiEvent.midiData[2] = char(note.velo); } pData->extNotes.mutex.unlock(); @@ -1214,11 +1216,10 @@ public: #endif bool isSampleAccurate = (pData->options & PLUGIN_OPTION_FIXED_BUFFERS) == 0; - uint32_t numEvents = pData->event.portIn->getEventCount(); uint32_t startTime = 0; uint32_t timeOffset = 0; - for (uint32_t i=0; i < numEvents; ++i) + for (uint32_t i=0, numEvents = pData->event.portIn->getEventCount(); i < numEvents; ++i) { const EngineEvent& event(pData->event.portIn->getEvent(i)); @@ -1350,16 +1351,15 @@ public: if (fMidiEventCount >= kPluginMaxMidiEvents*2) continue; - carla_zeroStruct(fMidiEvents[fMidiEventCount]); - - fMidiEvents[fMidiEventCount].type = kVstMidiType; - fMidiEvents[fMidiEventCount].byteSize = static_cast(sizeof(VstMidiEvent)); - fMidiEvents[fMidiEventCount].midiData[0] = static_cast(MIDI_STATUS_CONTROL_CHANGE + event.channel); - fMidiEvents[fMidiEventCount].midiData[1] = static_cast(ctrlEvent.param); - fMidiEvents[fMidiEventCount].midiData[2] = char(ctrlEvent.value*127.0f); - fMidiEvents[fMidiEventCount].deltaFrames = static_cast(isSampleAccurate ? startTime : event.time); + VstMidiEvent& vstMidiEvent(fMidiEvents[fMidiEventCount++]); + carla_zeroStruct(vstMidiEvent); - ++fMidiEventCount; + vstMidiEvent.type = kVstMidiType; + vstMidiEvent.byteSize = kVstMidiEventSize; + vstMidiEvent.deltaFrames = static_cast(isSampleAccurate ? startTime : event.time); + vstMidiEvent.midiData[0] = char(MIDI_STATUS_CONTROL_CHANGE | (event.channel & MIDI_CHANNEL_BIT)); + vstMidiEvent.midiData[1] = char(ctrlEvent.param); + vstMidiEvent.midiData[2] = char(ctrlEvent.value*127.0f); } break; @@ -1386,15 +1386,14 @@ public: if (fMidiEventCount >= kPluginMaxMidiEvents*2) continue; - carla_zeroStruct(fMidiEvents[fMidiEventCount]); - - fMidiEvents[fMidiEventCount].type = kVstMidiType; - fMidiEvents[fMidiEventCount].byteSize = static_cast(sizeof(VstMidiEvent)); - fMidiEvents[fMidiEventCount].midiData[0] = static_cast(MIDI_STATUS_CONTROL_CHANGE + event.channel); - fMidiEvents[fMidiEventCount].midiData[1] = MIDI_CONTROL_ALL_SOUND_OFF; - fMidiEvents[fMidiEventCount].deltaFrames = static_cast(isSampleAccurate ? startTime : event.time); + VstMidiEvent& vstMidiEvent(fMidiEvents[fMidiEventCount++]); + carla_zeroStruct(vstMidiEvent); - ++fMidiEventCount; + vstMidiEvent.type = kVstMidiType; + vstMidiEvent.byteSize = kVstMidiEventSize; + vstMidiEvent.deltaFrames = static_cast(isSampleAccurate ? startTime : event.time); + vstMidiEvent.midiData[0] = char(MIDI_STATUS_CONTROL_CHANGE | (event.channel & MIDI_CHANNEL_BIT)); + vstMidiEvent.midiData[1] = MIDI_CONTROL_ALL_SOUND_OFF; } break; @@ -1412,15 +1411,14 @@ public: if (fMidiEventCount >= kPluginMaxMidiEvents*2) continue; - carla_zeroStruct(fMidiEvents[fMidiEventCount]); + VstMidiEvent& vstMidiEvent(fMidiEvents[fMidiEventCount++]); + carla_zeroStruct(vstMidiEvent); - fMidiEvents[fMidiEventCount].type = kVstMidiType; - fMidiEvents[fMidiEventCount].byteSize = static_cast(sizeof(VstMidiEvent)); - fMidiEvents[fMidiEventCount].midiData[0] = static_cast(MIDI_STATUS_CONTROL_CHANGE + event.channel); - fMidiEvents[fMidiEventCount].midiData[1] = MIDI_CONTROL_ALL_NOTES_OFF; - fMidiEvents[fMidiEventCount].deltaFrames = static_cast(isSampleAccurate ? startTime : event.time); - - ++fMidiEventCount; + vstMidiEvent.type = kVstMidiType; + vstMidiEvent.byteSize = kVstMidiEventSize; + vstMidiEvent.deltaFrames = static_cast(isSampleAccurate ? startTime : event.time); + vstMidiEvent.midiData[0] = char(MIDI_STATUS_CONTROL_CHANGE | (event.channel & MIDI_CHANNEL_BIT)); + vstMidiEvent.midiData[1] = MIDI_CONTROL_ALL_NOTES_OFF; } break; } // switch (ctrlEvent.type) @@ -1433,12 +1431,11 @@ public: const EngineMidiEvent& midiEvent(event.midi); - uint8_t status = static_cast(MIDI_GET_STATUS_FROM_DATA(midiEvent.data)); - uint8_t channel = event.channel; + if (midiEvent.size > 3) + continue; + static_assert(3 <= EngineMidiEvent::kDataSize, "Incorrect data"); - // Fix bad note-off (per VST spec) - if (MIDI_IS_STATUS_NOTE_ON(status) && midiEvent.data[2] == 0) - status = MIDI_STATUS_NOTE_OFF; + uint8_t status = uint8_t(MIDI_GET_STATUS_FROM_DATA(midiEvent.data)); if (status == MIDI_STATUS_CHANNEL_PRESSURE && (pData->options & PLUGIN_OPTION_SEND_CHANNEL_PRESSURE) == 0) continue; @@ -1449,24 +1446,25 @@ public: if (status == MIDI_STATUS_PITCH_WHEEL_CONTROL && (pData->options & PLUGIN_OPTION_SEND_PITCHBEND) == 0) continue; - carla_zeroStruct(fMidiEvents[fMidiEventCount]); + // Fix bad note-off + if (status == MIDI_STATUS_NOTE_ON && midiEvent.data[2] == 0) + status = MIDI_STATUS_NOTE_OFF; - fMidiEvents[fMidiEventCount].type = kVstMidiType; - fMidiEvents[fMidiEventCount].byteSize = static_cast(sizeof(VstMidiEvent)); - fMidiEvents[fMidiEventCount].midiData[0] = static_cast(status + channel); - fMidiEvents[fMidiEventCount].midiData[1] = static_cast(midiEvent.data[1]); - fMidiEvents[fMidiEventCount].midiData[2] = static_cast(midiEvent.data[2]); - fMidiEvents[fMidiEventCount].deltaFrames = static_cast(isSampleAccurate ? startTime : event.time); + VstMidiEvent& vstMidiEvent(fMidiEvents[fMidiEventCount++]); + carla_zeroStruct(vstMidiEvent); - ++fMidiEventCount; + vstMidiEvent.type = kVstMidiType; + vstMidiEvent.byteSize = kVstMidiEventSize; + vstMidiEvent.deltaFrames = static_cast(isSampleAccurate ? startTime : event.time); + vstMidiEvent.midiData[0] = char(status | (event.channel & MIDI_CHANNEL_BIT)); + vstMidiEvent.midiData[1] = char(midiEvent.size >= 2 ? midiEvent.data[1] : 0); + vstMidiEvent.midiData[2] = char(midiEvent.size >= 3 ? midiEvent.data[2] : 0); if (status == MIDI_STATUS_NOTE_ON) - pData->postponeRtEvent(kPluginPostRtEventNoteOn, channel, midiEvent.data[1], midiEvent.data[2]); + pData->postponeRtEvent(kPluginPostRtEventNoteOn, event.channel, midiEvent.data[1], midiEvent.data[2]); else if (status == MIDI_STATUS_NOTE_OFF) - pData->postponeRtEvent(kPluginPostRtEventNoteOff, channel, midiEvent.data[1], 0.0f); - - break; - } // case kEngineEventTypeMidi + pData->postponeRtEvent(kPluginPostRtEventNoteOff, event.channel, midiEvent.data[1], 0.0f); + } break; } // switch (event.type) } @@ -1497,18 +1495,17 @@ public: if (fMidiEvents[k].type == 0) break; - CARLA_SAFE_ASSERT_CONTINUE(fMidiEvents[k].deltaFrames >= 0); - CARLA_SAFE_ASSERT_CONTINUE(fMidiEvents[k].midiData[0] != 0); + const VstMidiEvent& vstMidiEvent(fMidiEvents[k]); - const uint8_t status(static_cast(fMidiEvents[k].midiData[0])); - const uint8_t channel(static_cast(status < MIDI_STATUS_BIT ? status & MIDI_CHANNEL_BIT : 0)); + CARLA_SAFE_ASSERT_CONTINUE(vstMidiEvent.deltaFrames >= 0); + CARLA_SAFE_ASSERT_CONTINUE(vstMidiEvent.midiData[0] != 0); uint8_t midiData[3]; - midiData[0] = static_cast(fMidiEvents[k].midiData[0]); - midiData[1] = static_cast(fMidiEvents[k].midiData[1]); - midiData[2] = static_cast(fMidiEvents[k].midiData[2]); + midiData[0] = static_cast(vstMidiEvent.midiData[0]); + midiData[1] = static_cast(vstMidiEvent.midiData[1]); + midiData[2] = static_cast(vstMidiEvent.midiData[2]); - pData->event.portOut->writeMidiEvent(static_cast(fMidiEvents[k].deltaFrames), channel, 0, 3, midiData); + pData->event.portOut->writeMidiEvent(static_cast(vstMidiEvent.deltaFrames), MIDI_GET_CHANNEL_FROM_DATA(midiData), 0, 3, midiData); } } // End of MIDI Output @@ -1740,7 +1737,7 @@ public: uint8_t midiData[4]; midiData[0] = 0; - midiData[1] = static_cast(MIDI_STATUS_NOTE_ON + channel); + midiData[1] = uint8_t(MIDI_STATUS_NOTE_ON | (channel & MIDI_CHANNEL_BIT)); midiData[2] = note; midiData[3] = velo; @@ -1759,7 +1756,7 @@ public: uint8_t midiData[4]; midiData[0] = 0; - midiData[1] = static_cast(MIDI_STATUS_NOTE_OFF + channel); + midiData[1] = uint8_t(MIDI_STATUS_NOTE_OFF | (channel & MIDI_CHANNEL_BIT)); midiData[2] = note; midiData[3] = 0; diff --git a/source/includes/CarlaMIDI.h b/source/includes/CarlaMIDI.h index e15cdfe50..697390066 100644 --- a/source/includes/CarlaMIDI.h +++ b/source/includes/CarlaMIDI.h @@ -1,6 +1,6 @@ /* * Carla common MIDI code - * Copyright (C) 2012-2013 Filipe Coelho + * Copyright (C) 2012-2014 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -35,17 +35,23 @@ #define MIDI_STATUS_CHANNEL_PRESSURE 0xD0 // pressure (0-127), none #define MIDI_STATUS_PITCH_WHEEL_CONTROL 0xE0 // LSB (0-127), MSB (0-127) -#define MIDI_IS_STATUS_NOTE_OFF(status) (((status) < MIDI_STATUS_BIT) && ((status) & MIDI_STATUS_BIT) == MIDI_STATUS_NOTE_OFF) -#define MIDI_IS_STATUS_NOTE_ON(status) (((status) < MIDI_STATUS_BIT) && ((status) & MIDI_STATUS_BIT) == MIDI_STATUS_NOTE_ON) -#define MIDI_IS_STATUS_POLYPHONIC_AFTERTOUCH(status) (((status) < MIDI_STATUS_BIT) && ((status) & MIDI_STATUS_BIT) == MIDI_STATUS_POLYPHONIC_AFTERTOUCH) -#define MIDI_IS_STATUS_CONTROL_CHANGE(status) (((status) < MIDI_STATUS_BIT) && ((status) & MIDI_STATUS_BIT) == MIDI_STATUS_CONTROL_CHANGE) -#define MIDI_IS_STATUS_PROGRAM_CHANGE(status) (((status) < MIDI_STATUS_BIT) && ((status) & MIDI_STATUS_BIT) == MIDI_STATUS_PROGRAM_CHANGE) -#define MIDI_IS_STATUS_CHANNEL_PRESSURE(status) (((status) < MIDI_STATUS_BIT) && ((status) & MIDI_STATUS_BIT) == MIDI_STATUS_CHANNEL_PRESSURE) -#define MIDI_IS_STATUS_PITCH_WHEEL_CONTROL(status) (((status) < MIDI_STATUS_BIT) && ((status) & MIDI_STATUS_BIT) == MIDI_STATUS_PITCH_WHEEL_CONTROL) +// MIDI Message type +#define MIDI_IS_CHANNEL_MESSAGE(status) ((status) >= MIDI_STATUS_NOTE_OFF && (status) < MIDI_STATUS_BIT) +#define MIDI_IS_SYSTEM_MESSAGE(status) ((status) >= MIDI_STATUS_BIT && (status) <= 0xFF) +#define MIDI_IS_OSC_MESSAGE(status) ((status) == '/' || (status) == '#') + +// MIDI Channel message type +#define MIDI_IS_STATUS_NOTE_OFF(status) (MIDI_IS_CHANNEL_MESSAGE(status) && ((status) & MIDI_STATUS_BIT) == MIDI_STATUS_NOTE_OFF) +#define MIDI_IS_STATUS_NOTE_ON(status) (MIDI_IS_CHANNEL_MESSAGE(status) && ((status) & MIDI_STATUS_BIT) == MIDI_STATUS_NOTE_ON) +#define MIDI_IS_STATUS_POLYPHONIC_AFTERTOUCH(status) (MIDI_IS_CHANNEL_MESSAGE(status) && ((status) & MIDI_STATUS_BIT) == MIDI_STATUS_POLYPHONIC_AFTERTOUCH) +#define MIDI_IS_STATUS_CONTROL_CHANGE(status) (MIDI_IS_CHANNEL_MESSAGE(status) && ((status) & MIDI_STATUS_BIT) == MIDI_STATUS_CONTROL_CHANGE) +#define MIDI_IS_STATUS_PROGRAM_CHANGE(status) (MIDI_IS_CHANNEL_MESSAGE(status) && ((status) & MIDI_STATUS_BIT) == MIDI_STATUS_PROGRAM_CHANGE) +#define MIDI_IS_STATUS_CHANNEL_PRESSURE(status) (MIDI_IS_CHANNEL_MESSAGE(status) && ((status) & MIDI_STATUS_BIT) == MIDI_STATUS_CHANNEL_PRESSURE) +#define MIDI_IS_STATUS_PITCH_WHEEL_CONTROL(status) (MIDI_IS_CHANNEL_MESSAGE(status) && ((status) & MIDI_STATUS_BIT) == MIDI_STATUS_PITCH_WHEEL_CONTROL) // MIDI Utils -#define MIDI_GET_STATUS_FROM_DATA(data) ((data[0] < MIDI_STATUS_BIT) ? data[0] & MIDI_STATUS_BIT : data[0]) -#define MIDI_GET_CHANNEL_FROM_DATA(data) ((data[0] < MIDI_STATUS_BIT) ? data[0] & MIDI_CHANNEL_BIT : 0) +#define MIDI_GET_STATUS_FROM_DATA(data) (MIDI_IS_CHANNEL_MESSAGE(data[0]) ? data[0] & MIDI_STATUS_BIT : data[0]) +#define MIDI_GET_CHANNEL_FROM_DATA(data) (MIDI_IS_CHANNEL_MESSAGE(data[0]) ? data[0] & MIDI_CHANNEL_BIT : 0) // Control Change Messages List #define MIDI_CONTROL_BANK_SELECT 0x00 // 0-127, MSB