diff --git a/source/backend/plugin/CarlaPluginVST3.cpp b/source/backend/plugin/CarlaPluginVST3.cpp index b6d62ef390..076604af3a 100644 --- a/source/backend/plugin/CarlaPluginVST3.cpp +++ b/source/backend/plugin/CarlaPluginVST3.cpp @@ -1406,9 +1406,7 @@ class CarlaPluginVST3 : public CarlaPlugin, options |= PLUGIN_OPTION_SEND_CHANNEL_PRESSURE; options |= PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH; options |= PLUGIN_OPTION_SEND_PITCHBEND; - /* TODO options |= PLUGIN_OPTION_SEND_ALL_SOUND_OFF; - */ options |= PLUGIN_OPTION_SKIP_SENDING_NOTES; } @@ -2390,6 +2388,9 @@ class CarlaPluginVST3 : public CarlaPlugin, } } + if (fEvents.paramInputs != nullptr && fV3.midiMapping != nullptr) + fMidiControllerAssignments.init(fV3.midiMapping, numEventInputBuses); + bufferSizeChanged(pData->engine->getBufferSize()); reloadPrograms(true); @@ -2460,7 +2461,32 @@ class CarlaPluginVST3 : public CarlaPlugin, if (pData->needsReset) { - if (pData->ctrlChannel >= 0 && pData->ctrlChannel < MAX_MIDI_CHANNELS && fEvents.eventInputs != nullptr) + if (pData->options & PLUGIN_OPTION_SEND_ALL_SOUND_OFF) + { + for (uint8_t c=0; c index + uint32_t index = UINT32_MAX; + for (uint32_t i=0; i < pData->param.count; ++i) + { + if (static_cast(pData->param.data[i].rindex) == paramId) + { + index = i; + break; + } + } + + if (index == UINT32_MAX) + break; + + fEvents.paramInputs->setParamValueRT(index, 0, 0.f); + } + } + } + else if (pData->ctrlChannel >= 0 && pData->ctrlChannel < MAX_MIDI_CHANNELS && fEvents.eventInputs != nullptr) { fEvents.eventInputs->numEvents = MAX_MIDI_NOTE; @@ -2588,6 +2614,9 @@ class CarlaPluginVST3 : public CarlaPlugin, // -------------------------------------------------------------------------------------------------------- // Event Input (System) +#ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH + bool allNotesOffSent = false; +#endif bool isSampleAccurate = (pData->options & PLUGIN_OPTION_FIXED_BUFFERS) == 0; uint32_t startTime = 0; @@ -2718,13 +2747,10 @@ class CarlaPluginVST3 : public CarlaPlugin, if ((pData->options & PLUGIN_OPTION_SEND_CONTROL_CHANGES) != 0 && ctrlEvent.param < MAX_MIDI_VALUE) { - v3_param_id paramId = 0; - if (v3_cpp_obj(fV3.midiMapping)->get_midi_controller_assignment(fV3.midiMapping, - 0, - event.channel, - ctrlEvent.param, - ¶mId) == V3_OK) + v3_param_id paramId; + if (fMidiControllerAssignments.get(0, event.channel, ctrlEvent.param, paramId)) { + // TODO create mapping between paramId -> index uint32_t index = UINT32_MAX; for (uint32_t i=0; i < pData->param.count; ++i) { @@ -2764,8 +2790,61 @@ class CarlaPluginVST3 : public CarlaPlugin, break; case kEngineControlEventTypeAllSoundOff: + if (pData->options & PLUGIN_OPTION_SEND_ALL_SOUND_OFF) + { + v3_param_id paramId; + if (fMidiControllerAssignments.get(0, event.channel, MIDI_CONTROL_ALL_SOUND_OFF, paramId)) + { + // TODO create mapping between paramId -> index + uint32_t index = UINT32_MAX; + for (uint32_t i=0; i < pData->param.count; ++i) + { + if (static_cast(pData->param.data[i].rindex) == paramId) + { + index = i; + break; + } + } + + if (index == UINT32_MAX) + break; + + fEvents.paramInputs->setParamValueRT(index, event.time, 0.f); + } + } + break; + case kEngineControlEventTypeAllNotesOff: - // TODO map to CC + if (pData->options & PLUGIN_OPTION_SEND_ALL_SOUND_OFF) + { +#ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH + if (event.channel == pData->ctrlChannel && ! allNotesOffSent) + { + allNotesOffSent = true; + postponeRtAllNotesOff(); + } +#endif + + v3_param_id paramId; + if (fMidiControllerAssignments.get(0, event.channel, MIDI_CONTROL_ALL_NOTES_OFF, paramId)) + { + // TODO create mapping between paramId -> index + uint32_t index = UINT32_MAX; + for (uint32_t i=0; i < pData->param.count; ++i) + { + if (static_cast(pData->param.data[i].rindex) == paramId) + { + index = i; + break; + } + } + + if (index == UINT32_MAX) + break; + + fEvents.paramInputs->setParamValueRT(index, event.time, 0.f); + } + } break; } // switch (ctrlEvent.type) break; @@ -2854,13 +2933,10 @@ class CarlaPluginVST3 : public CarlaPlugin, const uint8_t control = midiEvent.data[1]; const uint8_t value = midiEvent.data[2]; - v3_param_id paramId = 0; - if (v3_cpp_obj(fV3.midiMapping)->get_midi_controller_assignment(fV3.midiMapping, - midiEvent.port, - event.channel, - control, - ¶mId) == V3_OK) + v3_param_id paramId; + if (fMidiControllerAssignments.get(midiEvent.port, event.channel, control, paramId)) { + // TODO create mapping between paramId -> index uint32_t index = UINT32_MAX; for (uint32_t i=0; i < pData->param.count; ++i) { @@ -2885,13 +2961,10 @@ class CarlaPluginVST3 : public CarlaPlugin, { const uint8_t pressure = midiEvent.data[1]; - v3_param_id paramId = 0; - if (v3_cpp_obj(fV3.midiMapping)->get_midi_controller_assignment(fV3.midiMapping, - midiEvent.port, - event.channel, - 128, - ¶mId) == V3_OK) + v3_param_id paramId; + if (fMidiControllerAssignments.get(midiEvent.port, event.channel, 128, paramId)) { + // TODO create mapping between paramId -> index uint32_t index = UINT32_MAX; for (uint32_t i=0; i < pData->param.count; ++i) { @@ -2916,13 +2989,10 @@ class CarlaPluginVST3 : public CarlaPlugin, { const uint16_t pitchbend = (midiEvent.data[2] << 7) | midiEvent.data[1]; - v3_param_id paramId = 0; - if (v3_cpp_obj(fV3.midiMapping)->get_midi_controller_assignment(fV3.midiMapping, - midiEvent.port, - event.channel, - 129, - ¶mId) == V3_OK) + v3_param_id paramId; + if (fMidiControllerAssignments.get(midiEvent.port, event.channel, 129, paramId)) { + // TODO create mapping between paramId -> index uint32_t index = UINT32_MAX; for (uint32_t i=0; i < pData->param.count; ++i) { @@ -3544,10 +3614,8 @@ class CarlaPluginVST3 : public CarlaPlugin, pData->options |= PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH; if (isPluginOptionEnabled(options, PLUGIN_OPTION_SEND_PITCHBEND)) pData->options |= PLUGIN_OPTION_SEND_PITCHBEND; - /* TODO if (isPluginOptionEnabled(options, PLUGIN_OPTION_SEND_ALL_SOUND_OFF)) pData->options |= PLUGIN_OPTION_SEND_ALL_SOUND_OFF; - */ if (isPluginOptionInverseEnabled(options, PLUGIN_OPTION_SKIP_SENDING_NOTES)) pData->options |= PLUGIN_OPTION_SKIP_SENDING_NOTES; } @@ -4133,6 +4201,80 @@ class CarlaPluginVST3 : public CarlaPlugin, CARLA_DECLARE_NON_COPYABLE(Events) } fEvents; + struct MidiControllerAssignments { + v3_param_id* mappings; + bool* used; + + MidiControllerAssignments() noexcept + : mappings(nullptr), + used(nullptr) {} + + ~MidiControllerAssignments() noexcept + { + clear(); + } + + void init(v3_midi_mapping** const midiMapping, const uint32_t numPorts) + { + clear(); + + if (numPorts == 0) + return; + + const uint32_t dataPoints = numPorts * MAX_MIDI_CHANNELS * 130; + + mappings = new v3_param_id[dataPoints]; + used = new bool[dataPoints]; + + carla_zeroStructs(mappings, dataPoints); + carla_zeroStructs(used, dataPoints); + + v3_param_id paramId; + for (uint32_t p=0; pget_midi_controller_assignment(midiMapping, p, + ch, cc, ¶mId) == V3_OK) + { + const uint32_t index = p * (130 + MAX_MIDI_CHANNELS) + cc * MAX_MIDI_CHANNELS + ch; + mappings[index] = paramId; + used[index] = true; + } + } + } + } + } + + void clear() noexcept + { + delete[] mappings; + delete[] used; + mappings = nullptr; + used = nullptr; + } + + bool get(const uint8_t port, const uint8_t channel, const uint8_t cc, v3_param_id& paramId) noexcept + { + CARLA_SAFE_ASSERT_UINT_RETURN(channel < MAX_MIDI_CHANNELS, channel, false); + CARLA_SAFE_ASSERT_UINT_RETURN(cc < 130, cc, false); + + if (used == nullptr) + return false; + + const uint32_t index = port * (130 + MAX_MIDI_CHANNELS) + cc * MAX_MIDI_CHANNELS + channel; + if (used[index]) + { + paramId = mappings[index]; + return true; + } + + return false; + } + } fMidiControllerAssignments; + #ifdef V3_VIEW_PLATFORM_TYPE_NATIVE struct UI { bool isAttached;