From dbf649d58d8f21c77c15a5ec554f6544085e9aa8 Mon Sep 17 00:00:00 2001 From: falkTX Date: Thu, 21 Mar 2019 10:29:25 +0100 Subject: [PATCH] WIP drag/touch params callback to host; Fix plugin rename API Signed-off-by: falkTX --- source/backend/CarlaEngine.hpp | 11 ++++- source/backend/CarlaHost.h | 11 ++++- source/backend/CarlaStandalone.cpp | 14 +++++-- source/backend/engine/CarlaEngine.cpp | 28 ++++++++----- source/backend/engine/CarlaEngineJack.cpp | 22 +++++----- source/backend/engine/CarlaEngineNative.cpp | 35 +++++++++++----- source/backend/plugin/CarlaPluginJuce.cpp | 15 ++++++- source/backend/plugin/CarlaPluginLV2.cpp | 39 +++++++++++++++++- source/backend/plugin/CarlaPluginNative.cpp | 12 ++++++ source/backend/plugin/CarlaPluginVST2.cpp | 9 ++++- source/frontend/carla_backend.py | 33 +++++++++++---- source/frontend/carla_skin.py | 10 ++++- source/frontend/carla_widgets.py | 5 +++ source/frontend/widgets/paramspinbox.py | 5 +++ source/frontend/widgets/pixmapdial.py | 3 ++ source/includes/CarlaNative.h | 1 + source/includes/CarlaNative.hpp | 9 ++++- .../distrho/src/DistrhoPluginCarla.cpp | 4 +- source/plugin/carla-lv2-export.cpp | 1 + source/plugin/carla-lv2.cpp | 18 +++++++++ source/plugin/carla-native-plugin.cpp | 1 + source/plugin/carla-vst-export.cpp | 6 +-- source/plugin/carla-vst.cpp | 40 +++++++++++-------- source/plugin/carla-vst.hpp | 7 +++- source/utils/CarlaLv2Utils.hpp | 3 ++ 25 files changed, 267 insertions(+), 75 deletions(-) diff --git a/source/backend/CarlaEngine.hpp b/source/backend/CarlaEngine.hpp index 136e958e6..818017568 100644 --- a/source/backend/CarlaEngine.hpp +++ b/source/backend/CarlaEngine.hpp @@ -862,7 +862,7 @@ public: * Returned variable must be deleted if non-null. * @see ENGINE_CALLBACK_PLUGIN_RENAMED */ - virtual const char* renamePlugin(const uint id, const char* const newName); + virtual bool renamePlugin(const uint id, const char* const newName); /*! * Clone plugin with id @a id. @@ -880,6 +880,15 @@ public: * Switch plugins with id @a idA and @a idB. */ bool switchPlugins(const uint idA, const uint idB) noexcept; + + /*! + * Set a plugin's parameter in drag/touch mode. + * Usually happens from a UI when the user is moving a parameter with a mouse or similar input. + * + * @param parameterId The parameter to update + * @param touch The new state for the parameter + */ + virtual void touchPluginParameter(const uint id, const uint32_t parameterId, const bool touch) noexcept; #endif /*! diff --git a/source/backend/CarlaHost.h b/source/backend/CarlaHost.h index 365d4f621..7239fc6b7 100644 --- a/source/backend/CarlaHost.h +++ b/source/backend/CarlaHost.h @@ -542,7 +542,7 @@ CARLA_EXPORT bool carla_remove_all_plugins(); * @param pluginId Plugin to rename * @param newName New plugin name */ -CARLA_EXPORT const char* carla_rename_plugin(uint pluginId, const char* newName); +CARLA_EXPORT bool carla_rename_plugin(uint pluginId, const char* newName); /*! * Clone a plugin. @@ -879,6 +879,15 @@ CARLA_EXPORT void carla_set_parameter_midi_channel(uint pluginId, uint32_t param * @param cc New MIDI cc */ CARLA_EXPORT void carla_set_parameter_midi_cc(uint pluginId, uint32_t parameterId, int16_t cc); + +/*! + * Change a plugin's parameter in drag/touch mode state. + * Usually happens from a UI when the user is moving a parameter with a mouse or similar input. + * @param pluginId Plugin + * @param parameterId Parameter index + * @param touch New state + */ +CARLA_EXPORT void carla_set_parameter_touch(uint pluginId, uint32_t parameterId, bool touch); #endif /*! diff --git a/source/backend/CarlaStandalone.cpp b/source/backend/CarlaStandalone.cpp index b339515fc..d221fa57e 100644 --- a/source/backend/CarlaStandalone.cpp +++ b/source/backend/CarlaStandalone.cpp @@ -954,10 +954,10 @@ bool carla_remove_all_plugins() } #ifndef BUILD_BRIDGE -const char* carla_rename_plugin(uint pluginId, const char* newName) +bool carla_rename_plugin(uint pluginId, const char* newName) { - CARLA_SAFE_ASSERT_RETURN(newName != nullptr && newName[0] != '\0', nullptr); - CARLA_SAFE_ASSERT_WITH_LAST_ERROR_RETURN(gStandalone.engine != nullptr, "Engine is not initialized", nullptr); + CARLA_SAFE_ASSERT_RETURN(newName != nullptr && newName[0] != '\0', false); + CARLA_SAFE_ASSERT_WITH_LAST_ERROR_RETURN(gStandalone.engine != nullptr, "Engine is not initialized", false); carla_debug("carla_rename_plugin(%i, \"%s\")", pluginId, newName); @@ -1812,6 +1812,14 @@ void carla_set_parameter_midi_cc(uint pluginId, uint32_t parameterId, int16_t cc return plugin->setParameterMidiCC(parameterId, cc, true, false); } + +void carla_set_parameter_touch(uint pluginId, uint32_t parameterId, bool touch) +{ + CARLA_SAFE_ASSERT_RETURN(gStandalone.engine != nullptr,); + + carla_debug("carla_set_parameter_touch(%i, %i, %s)", pluginId, parameterId, bool2str(touch)); + return gStandalone.engine->touchPluginParameter(pluginId, parameterId, touch); +} #endif // -------------------------------------------------------------------------------------------------------------------- diff --git a/source/backend/engine/CarlaEngine.cpp b/source/backend/engine/CarlaEngine.cpp index f1928d5f0..0e24af6cb 100644 --- a/source/backend/engine/CarlaEngine.cpp +++ b/source/backend/engine/CarlaEngine.cpp @@ -752,30 +752,32 @@ bool CarlaEngine::removeAllPlugins() } #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH -const char* CarlaEngine::renamePlugin(const uint id, const char* const newName) +bool CarlaEngine::renamePlugin(const uint id, const char* const newName) { - CARLA_SAFE_ASSERT_RETURN_ERRN(pData->isIdling == 0, "An operation is still being processed, please wait for it to finish"); - CARLA_SAFE_ASSERT_RETURN_ERRN(pData->plugins != nullptr, "Invalid engine internal data"); - CARLA_SAFE_ASSERT_RETURN_ERRN(pData->curPluginCount != 0, "Invalid engine internal data"); - CARLA_SAFE_ASSERT_RETURN_ERRN(pData->nextAction.opcode == kEnginePostActionNull, "Invalid engine internal data"); - CARLA_SAFE_ASSERT_RETURN_ERRN(id < pData->curPluginCount, "Invalid plugin Id"); - CARLA_SAFE_ASSERT_RETURN_ERRN(newName != nullptr && newName[0] != '\0', "Invalid plugin name"); + CARLA_SAFE_ASSERT_RETURN_ERR(pData->isIdling == 0, "An operation is still being processed, please wait for it to finish"); + CARLA_SAFE_ASSERT_RETURN_ERR(pData->plugins != nullptr, "Invalid engine internal data"); + CARLA_SAFE_ASSERT_RETURN_ERR(pData->curPluginCount != 0, "Invalid engine internal data"); + CARLA_SAFE_ASSERT_RETURN_ERR(pData->nextAction.opcode == kEnginePostActionNull, "Invalid engine internal data"); + CARLA_SAFE_ASSERT_RETURN_ERR(id < pData->curPluginCount, "Invalid plugin Id"); + CARLA_SAFE_ASSERT_RETURN_ERR(newName != nullptr && newName[0] != '\0', "Invalid plugin name"); carla_debug("CarlaEngine::renamePlugin(%i, \"%s\")", id, newName); CarlaPlugin* const plugin(pData->plugins[id].plugin); - CARLA_SAFE_ASSERT_RETURN_ERRN(plugin != nullptr, "Could not find plugin to rename"); - CARLA_SAFE_ASSERT_RETURN_ERRN(plugin->getId() == id, "Invalid engine internal data"); + CARLA_SAFE_ASSERT_RETURN_ERR(plugin != nullptr, "Could not find plugin to rename"); + CARLA_SAFE_ASSERT_RETURN_ERR(plugin->getId() == id, "Invalid engine internal data"); const char* const uniqueName(getUniquePluginName(newName)); - CARLA_SAFE_ASSERT_RETURN_ERRN(uniqueName != nullptr, "Unable to get new unique plugin name"); + CARLA_SAFE_ASSERT_RETURN_ERR(uniqueName != nullptr, "Unable to get new unique plugin name"); plugin->setName(uniqueName); if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY) pData->graph.renamePlugin(plugin, uniqueName); + callback(true, true, ENGINE_CALLBACK_PLUGIN_RENAMED, id, 0, 0, 0, 0.0f, uniqueName); + delete[] uniqueName; - return plugin->getName(); + return true; } bool CarlaEngine::clonePlugin(const uint id) @@ -875,6 +877,10 @@ bool CarlaEngine::switchPlugins(const uint idA, const uint idB) noexcept return true; } + +void CarlaEngine::touchPluginParameter(const uint, const uint32_t, const bool) noexcept +{ +} #endif CarlaPlugin* CarlaEngine::getPlugin(const uint id) const noexcept diff --git a/source/backend/engine/CarlaEngineJack.cpp b/source/backend/engine/CarlaEngineJack.cpp index 382b58b2f..4de594ea9 100644 --- a/source/backend/engine/CarlaEngineJack.cpp +++ b/source/backend/engine/CarlaEngineJack.cpp @@ -1357,7 +1357,7 @@ public: } #ifndef BUILD_BRIDGE - const char* renamePlugin(const uint id, const char* const newName) override + bool renamePlugin(const uint id, const char* const newName) override { if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK || pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY) @@ -1365,14 +1365,14 @@ public: return CarlaEngine::renamePlugin(id, newName); } - CARLA_SAFE_ASSERT_RETURN(pData->plugins != nullptr, nullptr); - CARLA_SAFE_ASSERT_RETURN(pData->curPluginCount != 0, nullptr); - CARLA_SAFE_ASSERT_RETURN(id < pData->curPluginCount, nullptr); - CARLA_SAFE_ASSERT_RETURN(newName != nullptr && newName[0] != '\0', nullptr); + CARLA_SAFE_ASSERT_RETURN(pData->plugins != nullptr, false); + CARLA_SAFE_ASSERT_RETURN(pData->curPluginCount != 0, false); + CARLA_SAFE_ASSERT_RETURN(id < pData->curPluginCount, false); + CARLA_SAFE_ASSERT_RETURN(newName != nullptr && newName[0] != '\0', false); CarlaPlugin* const plugin(pData->plugins[id].plugin); - CARLA_SAFE_ASSERT_RETURN_ERRN(plugin != nullptr, "Could not find plugin to rename"); - CARLA_SAFE_ASSERT_RETURN_ERRN(plugin->getId() == id, "Invalid engine internal data"); + CARLA_SAFE_ASSERT_RETURN_ERR(plugin != nullptr, "Could not find plugin to rename"); + CARLA_SAFE_ASSERT_RETURN_ERR(plugin->getId() == id, "Invalid engine internal data"); // before we stop the engine thread we might need to get the plugin data const bool needsReinit = (pData->options.processMode == ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS); @@ -1395,7 +1395,7 @@ public: if (uniqueName.isEmpty()) { setLastError("Failed to request new unique plugin name"); - return nullptr; + return false; } const ScopedThreadStopper sts(this); @@ -1408,7 +1408,7 @@ public: if (! client->renameInSingleClient(uniqueName)) { setLastError("Failed to rename some JACK ports, does your JACK version support proper port renaming?"); - return nullptr; + return false; } } // rename in multiple client mode @@ -1493,7 +1493,7 @@ public: else { setLastError("Failed to create new JACK client"); - return nullptr; + return false; } } @@ -1508,7 +1508,7 @@ public: plugin->setEnabled(true); } - return plugin->getName(); + return true; } // ------------------------------------------------------------------- diff --git a/source/backend/engine/CarlaEngineNative.cpp b/source/backend/engine/CarlaEngineNative.cpp index bbf3c17da..3eba3ac8a 100644 --- a/source/backend/engine/CarlaEngineNative.cpp +++ b/source/backend/engine/CarlaEngineNative.cpp @@ -331,15 +331,10 @@ public: // ------------------------------------------------------------------- - const char* renamePlugin(const uint id, const char* const newName) override + void touchPluginParameter(const uint id, const uint32_t parameterId, const bool touch) noexcept override { - if (const char* const retName = CarlaEngine::renamePlugin(id, newName)) - { - uiServerCallback(ENGINE_CALLBACK_PLUGIN_RENAMED, id, 0, 0, 0, 0.0f, retName); - return retName; - } - - return nullptr; + carla_stdout("engineNative touchPluginParameter %u %u %s", id, parameterId, bool2str(touch)); + setParameterTouchFromUI(id, parameterId, touch); } // ------------------------------------------------------------------- @@ -353,6 +348,15 @@ public: pHost->ui_parameter_changed(pHost->handle, index, value); } + void setParameterTouchFromUI(const uint32_t pluginId, const uint32_t index, const bool touch) + { + if (pluginId != 0) + return; + + carla_stdout("engineNative setParameterTouchFromUI %u %u %s", pluginId,index, bool2str(touch)); + pHost->ui_parameter_touch(pHost->handle, index, touch); + } + void reloadFromUI() { carla_zeroFloats(fParameters, kNumInParams+kNumOutParams); @@ -1927,8 +1931,7 @@ bool CarlaEngineNativeUI::msgReceived(const char*const msg) noexcept CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(pluginId), true); CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(newName), true); - // TODO - /*const char* name =*/ fEngine->renamePlugin(pluginId, newName); + ok = fEngine->renamePlugin(pluginId, newName); delete[] newName; } @@ -2119,6 +2122,18 @@ bool CarlaEngineNativeUI::msgReceived(const char*const msg) noexcept if (CarlaPlugin* const plugin = fEngine->getPlugin(pluginId)) plugin->setParameterMidiCC(parameterId, static_cast(cc), true, false); } + else if (std::strcmp(msg, "set_parameter_touch") == 0) + { + uint32_t pluginId, parameterId; + bool touching; + + CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(pluginId), true); + CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(parameterId), true); + CARLA_SAFE_ASSERT_RETURN(readNextLineAsBool(touching), true); + + if (fEngine->getPlugin(pluginId) != nullptr) + fEngine->setParameterTouchFromUI(pluginId, parameterId, touching); + } else if (std::strcmp(msg, "set_program") == 0) { uint32_t pluginId; diff --git a/source/backend/plugin/CarlaPluginJuce.cpp b/source/backend/plugin/CarlaPluginJuce.cpp index 91212bcee..22f35b5b7 100644 --- a/source/backend/plugin/CarlaPluginJuce.cpp +++ b/source/backend/plugin/CarlaPluginJuce.cpp @@ -1159,8 +1159,19 @@ protected: pData->engine->callback(true, true, ENGINE_CALLBACK_UPDATE, pData->id, 0, 0, 0, 0.0f, nullptr); } - void audioProcessorParameterChangeGestureBegin(juce::AudioProcessor*, int) override {} - void audioProcessorParameterChangeGestureEnd(juce::AudioProcessor*, int) override {} + void audioProcessorParameterChangeGestureBegin(juce::AudioProcessor*, int index) override + { + CARLA_SAFE_ASSERT_RETURN(index >= 0,); + + pData->engine->touchPluginParameter(pData->id, static_cast(index), true); + } + + void audioProcessorParameterChangeGestureEnd(juce::AudioProcessor*, int index) override + { + CARLA_SAFE_ASSERT_RETURN(index >= 0,); + + pData->engine->touchPluginParameter(pData->id, static_cast(index), false); + } bool getCurrentPosition(CurrentPositionInfo& result) override { diff --git a/source/backend/plugin/CarlaPluginLV2.cpp b/source/backend/plugin/CarlaPluginLV2.cpp index 418ab0023..dc8940091 100644 --- a/source/backend/plugin/CarlaPluginLV2.cpp +++ b/source/backend/plugin/CarlaPluginLV2.cpp @@ -615,6 +615,9 @@ public: if (fFeatures[kFeatureIdUiResize] != nullptr && fFeatures[kFeatureIdUiResize]->data != nullptr) delete (LV2UI_Resize*)fFeatures[kFeatureIdUiResize]->data; + if (fFeatures[kFeatureIdUiTouch] != nullptr && fFeatures[kFeatureIdUiTouch]->data != nullptr) + delete (LV2UI_Touch*)fFeatures[kFeatureIdUiTouch]->data; + if (fFeatures[kFeatureIdExternalUi] != nullptr && fFeatures[kFeatureIdExternalUi]->data != nullptr) delete (LV2_External_UI_Host*)fFeatures[kFeatureIdExternalUi]->data; @@ -5109,6 +5112,25 @@ public: return 0; } + void handleUITouch(const uint32_t rindex, const bool touch) + { + carla_stdout("CarlaPluginLV2::handleUITouch(%u, %s)", rindex, bool2str(touch)); + + uint32_t index = LV2UI_INVALID_PORT_INDEX; + + for (uint32_t i=0; i < pData->param.count; ++i) + { + if (pData->param.data[i].rindex != static_cast(rindex)) + continue; + index = i; + break; + } + + CARLA_SAFE_ASSERT_RETURN(index != LV2UI_INVALID_PORT_INDEX,); + + pData->engine->touchPluginParameter(pData->id, index, touch); + } + void handleUIWrite(const uint32_t rindex, const uint32_t bufferSize, const uint32_t format, const void* const buffer) { CARLA_SAFE_ASSERT_RETURN(buffer != nullptr,); @@ -6048,6 +6070,10 @@ public: uiResizeFt->handle = this; uiResizeFt->ui_resize = carla_lv2_ui_resize; + LV2UI_Touch* const uiTouchFt = new LV2UI_Touch; + uiTouchFt->handle = this; + uiTouchFt->touch = carla_lv2_ui_touch; + LV2_External_UI_Host* const uiExternalHostFt = new LV2_External_UI_Host; uiExternalHostFt->ui_closed = carla_lv2_external_ui_closed; uiExternalHostFt->plugin_human_id = fLv2Options.windowTitle; @@ -6092,7 +6118,7 @@ public: fFeatures[kFeatureIdUiResize]->data = uiResizeFt; fFeatures[kFeatureIdUiTouch]->URI = LV2_UI__touch; - fFeatures[kFeatureIdUiTouch]->data = nullptr; + fFeatures[kFeatureIdUiTouch]->data = uiTouchFt; fFeatures[kFeatureIdExternalUi]->URI = LV2_EXTERNAL_UI__Host; fFeatures[kFeatureIdExternalUi]->data = uiExternalHostFt; @@ -6770,6 +6796,17 @@ private: return ((CarlaPluginLV2*)handle)->handleUIResize(width, height); } + // ------------------------------------------------------------------- + // UI Touch Feature + + static void carla_lv2_ui_touch(LV2UI_Feature_Handle handle, uint32_t port_index, bool touch) + { + CARLA_SAFE_ASSERT_RETURN(handle != nullptr,); + carla_debug("carla_lv2_ui_touch(%p, %u, %s)", handle, port_index, bool2str(touch)); + + ((CarlaPluginLV2*)handle)->handleUITouch(port_index, touch); + } + // ------------------------------------------------------------------- // UI Extension diff --git a/source/backend/plugin/CarlaPluginNative.cpp b/source/backend/plugin/CarlaPluginNative.cpp index 07cc15321..f7b3a8128 100644 --- a/source/backend/plugin/CarlaPluginNative.cpp +++ b/source/backend/plugin/CarlaPluginNative.cpp @@ -279,6 +279,7 @@ public: fHost.get_time_info = carla_host_get_time_info; fHost.write_midi_event = carla_host_write_midi_event; fHost.ui_parameter_changed = carla_host_ui_parameter_changed; + fHost.ui_parameter_touch = carla_host_ui_parameter_touch; fHost.ui_custom_data_changed = carla_host_ui_custom_data_changed; fHost.ui_closed = carla_host_ui_closed; fHost.ui_open_file = carla_host_ui_open_file; @@ -2393,6 +2394,12 @@ protected: setParameterValue(index, value, false, true, true); } + void handleUiParameterTouch(const uint32_t index, const bool touch) const + { + carla_stdout("pluginNative handleUiParameterTouch %u %s", index, bool2str(touch)); + pData->engine->touchPluginParameter(pData->id, index, touch); + } + void handleUiCustomDataChanged(const char* const key, const char* const value) { setCustomData(CUSTOM_DATA_TYPE_STRING, key, value, false); @@ -2696,6 +2703,11 @@ private: handlePtr->handleUiParameterChanged(index, value); } + static void carla_host_ui_parameter_touch(NativeHostHandle handle, uint32_t index, bool touch) + { + handlePtr->handleUiParameterTouch(index, touch); + } + static void carla_host_ui_custom_data_changed(NativeHostHandle handle, const char* key, const char* value) { handlePtr->handleUiCustomDataChanged(key, value); diff --git a/source/backend/plugin/CarlaPluginVST2.cpp b/source/backend/plugin/CarlaPluginVST2.cpp index 3befd0704..966c6e629 100644 --- a/source/backend/plugin/CarlaPluginVST2.cpp +++ b/source/backend/plugin/CarlaPluginVST2.cpp @@ -2197,8 +2197,15 @@ protected: break; case audioMasterBeginEdit: + CARLA_SAFE_ASSERT_BREAK(index > 0); + carla_stdout("audioMasterBeginEdit %i", index); + pData->engine->touchPluginParameter(pData->id, static_cast(index), true); + break; + case audioMasterEndEdit: - // TODO + CARLA_SAFE_ASSERT_BREAK(index > 0); + carla_stdout("audioMasterEndEdit %i", index); + pData->engine->touchPluginParameter(pData->id, static_cast(index), false); break; case audioMasterOpenFileSelector: diff --git a/source/frontend/carla_backend.py b/source/frontend/carla_backend.py index a39c9d373..5ed6a16d2 100644 --- a/source/frontend/carla_backend.py +++ b/source/frontend/carla_backend.py @@ -1904,6 +1904,15 @@ class CarlaHostMeta(object): def set_parameter_midi_cc(self, pluginId, parameterId, cc): raise NotImplementedError + # Change a plugin's parameter in drag/touch mode state. + # Usually happens from a UI when the user is moving a parameter with a mouse or similar input. + # @param pluginId Plugin + # @param parameterId Parameter index + # @param touch New state + @abstractmethod + def set_parameter_touch(self, pluginId, parameterId, touch): + raise NotImplementedError + # Change a plugin's current program. # @param pluginId Plugin # @param programId New program @@ -2133,7 +2142,7 @@ class CarlaHostNull(CarlaHostMeta): return False def rename_plugin(self, pluginId, newName): - return "" + return False def clone_plugin(self, pluginId): return False @@ -2270,6 +2279,9 @@ class CarlaHostNull(CarlaHostMeta): def set_parameter_midi_cc(self, pluginId, parameterId, cc): return + def set_parameter_touch(self, pluginId, parameterId, touch): + return + def set_program(self, pluginId, programId): return @@ -2430,7 +2442,7 @@ class CarlaHostDLL(CarlaHostMeta): self.lib.carla_remove_all_plugins.restype = c_bool self.lib.carla_rename_plugin.argtypes = [c_uint, c_char_p] - self.lib.carla_rename_plugin.restype = c_char_p + self.lib.carla_rename_plugin.restype = c_bool self.lib.carla_clone_plugin.argtypes = [c_uint] self.lib.carla_clone_plugin.restype = c_bool @@ -2567,6 +2579,9 @@ class CarlaHostDLL(CarlaHostMeta): self.lib.carla_set_parameter_midi_cc.argtypes = [c_uint, c_uint32, c_int16] self.lib.carla_set_parameter_midi_cc.restype = None + self.lib.carla_set_parameter_touch.argtypes = [c_uint, c_uint32, c_bool] + self.lib.carla_set_parameter_touch.restype = None + self.lib.carla_set_program.argtypes = [c_uint, c_uint32] self.lib.carla_set_program.restype = None @@ -2722,7 +2737,7 @@ class CarlaHostDLL(CarlaHostMeta): return bool(self.lib.carla_remove_all_plugins()) def rename_plugin(self, pluginId, newName): - return charPtrToString(self.lib.carla_rename_plugin(pluginId, newName.encode("utf-8"))) + return bool(self.lib.carla_rename_plugin(pluginId, newName.encode("utf-8"))) def clone_plugin(self, pluginId): return bool(self.lib.carla_clone_plugin(pluginId)) @@ -2872,6 +2887,9 @@ class CarlaHostDLL(CarlaHostMeta): def set_parameter_midi_cc(self, pluginId, parameterId, cc): self.lib.carla_set_parameter_midi_cc(pluginId, parameterId, cc) + def set_parameter_touch(self, pluginId, parameterId, touch): + self.lib.carla_set_parameter_touch(pluginId, parameterId, touch) + def set_program(self, pluginId, programId): self.lib.carla_set_program(pluginId, programId) @@ -3097,11 +3115,7 @@ class CarlaHostPlugin(CarlaHostMeta): return self.sendMsgAndSetError(["remove_all_plugins"]) def rename_plugin(self, pluginId, newName): - if self.sendMsg(["rename_plugin", pluginId, newName]): - return newName - - self.fLastError = "Communication error with backend" - return "" + return self.sendMsgAndSetError(["rename_plugin", pluginId, newName]) def clone_plugin(self, pluginId): return self.sendMsgAndSetError(["clone_plugin", pluginId]) @@ -3263,6 +3277,9 @@ class CarlaHostPlugin(CarlaHostMeta): self.sendMsg(["set_parameter_midi_cc", pluginId, parameterId, cc]) self.fPluginsInfo[pluginId].parameterData[parameterId]['midiCC'] = cc + def set_parameter_touch(self, pluginId, parameterId, touch): + self.sendMsg(["set_parameter_touch", pluginId, parameterId, touch]) + def set_program(self, pluginId, programId): self.sendMsg(["set_program", pluginId, programId]) self.fPluginsInfo[pluginId].programCurrent = programId diff --git a/source/frontend/carla_skin.py b/source/frontend/carla_skin.py index 51fa0fe3f..8723d1840 100644 --- a/source/frontend/carla_skin.py +++ b/source/frontend/carla_skin.py @@ -624,6 +624,7 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta): for paramIndex, paramWidget in self.fParameterList: paramWidget.setContextMenuPolicy(Qt.CustomContextMenu) paramWidget.customContextMenuRequested.connect(self.slot_knobCustomMenu) + paramWidget.dragStateChanged.connect(self.slot_parameterDragStateChanged) paramWidget.realValueChanged.connect(self.slot_parameterValueChanged) paramWidget.blockSignals(True) paramWidget.setValue(self.host.get_internal_parameter_value(self.fPluginId, paramIndex)) @@ -797,8 +798,6 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta): self.host.get_last_error(), QMessageBox.Ok, QMessageBox.Ok) return - self.setName(newName) - def showReplaceDialog(self): data = gCarla.gui.showAddPluginDialog() @@ -1360,6 +1359,13 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta): #------------------------------------------------------------------ + @pyqtSlot(bool) + def slot_parameterDragStateChanged(self, touch): + index = self.sender().getIndex() + + if index >= 0: + self.host.set_parameter_touch(self.fPluginId, index, touch) + @pyqtSlot(float) def slot_parameterValueChanged(self, value): index = self.sender().getIndex() diff --git a/source/frontend/carla_widgets.py b/source/frontend/carla_widgets.py index 8184887b8..ea6aea9e5 100755 --- a/source/frontend/carla_widgets.py +++ b/source/frontend/carla_widgets.py @@ -293,6 +293,7 @@ class PluginParameter(QWidget): self.ui.sb_channel.customContextMenuRequested.connect(self.slot_channelSpinboxCustomMenu) self.ui.sb_control.valueChanged.connect(self.slot_controlSpinboxChanged) self.ui.sb_channel.valueChanged.connect(self.slot_channelSpinboxChanged) + self.ui.widget.dragStateChanged.connect(self.slot_parameterDragStateChanged) # ------------------------------------------------------------- @@ -383,6 +384,10 @@ class PluginParameter(QWidget): self.fMidiChannel = channel self.midiChannelChanged.emit(self.fParameterId, channel) + @pyqtSlot(bool) + def slot_parameterDragStateChanged(self, touch): + self.host.set_parameter_touch(self.fPluginId, self.fParameterId, touch) + def _textCallBack(self): return self.host.get_parameter_text(self.fPluginId, self.fParameterId) diff --git a/source/frontend/widgets/paramspinbox.py b/source/frontend/widgets/paramspinbox.py index 38914c26a..114600e66 100644 --- a/source/frontend/widgets/paramspinbox.py +++ b/source/frontend/widgets/paramspinbox.py @@ -107,6 +107,7 @@ class CustomInputDialog(QDialog): class ParamProgressBar(QProgressBar): # signals + dragStateChanged = pyqtSignal(bool) valueChanged = pyqtSignal(float) def __init__(self, parent): @@ -217,6 +218,7 @@ class ParamProgressBar(QProgressBar): if event.button() == Qt.LeftButton: self.handleMouseEventPos(event.pos()) self.fLeftClickDown = True + self.dragStateChanged.emit(True) else: self.fLeftClickDown = False @@ -236,6 +238,7 @@ class ParamProgressBar(QProgressBar): return self.fLeftClickDown = False + self.dragStateChanged.emit(False) QProgressBar.mouseReleaseEvent(self, event) def paintEvent(self, event): @@ -293,6 +296,8 @@ class ParamSpinBox(QAbstractSpinBox): self.customContextMenuRequested.connect(self.slot_showCustomMenu) self.fBar.valueChanged.connect(self.slot_progressBarValueChanged) + self.dragStateChanged = self.fBar.dragStateChanged + QTimer.singleShot(0, self.slot_updateProgressBarGeometry) def setDefault(self, value): diff --git a/source/frontend/widgets/pixmapdial.py b/source/frontend/widgets/pixmapdial.py index 00245bc9a..12b69eb4e 100644 --- a/source/frontend/widgets/pixmapdial.py +++ b/source/frontend/widgets/pixmapdial.py @@ -52,6 +52,7 @@ class PixmapDial(QDial): MODE_LINEAR = 1 # signals + dragStateChanged = pyqtSignal(bool) realValueChanged = pyqtSignal(float) def __init__(self, parent, index=0): @@ -305,6 +306,7 @@ class PixmapDial(QDial): self.fIsPressed = True self.fLastDragPos = event.pos() self.fLastDragValue = self.fRealValue + self.dragStateChanged.emit(True) def mouseMoveEvent(self, event): if self.fDialMode == self.MODE_DEFAULT: @@ -334,6 +336,7 @@ class PixmapDial(QDial): if self.fIsPressed: self.fIsPressed = False + self.dragStateChanged.emit(False) def paintEvent(self, event): painter = QPainter(self) diff --git a/source/includes/CarlaNative.h b/source/includes/CarlaNative.h index dade3b612..fb79b9b90 100644 --- a/source/includes/CarlaNative.h +++ b/source/includes/CarlaNative.h @@ -192,6 +192,7 @@ typedef struct { bool (*write_midi_event)(NativeHostHandle handle, const NativeMidiEvent* event); void (*ui_parameter_changed)(NativeHostHandle handle, uint32_t index, float value); + void (*ui_parameter_touch)(NativeHostHandle handle, uint32_t index, bool touch); void (*ui_midi_program_changed)(NativeHostHandle handle, uint8_t channel, uint32_t bank, uint32_t program); void (*ui_custom_data_changed)(NativeHostHandle handle, const char* key, const char* value); void (*ui_closed)(NativeHostHandle handle); diff --git a/source/includes/CarlaNative.hpp b/source/includes/CarlaNative.hpp index c87cc1217..0fb0f6de4 100644 --- a/source/includes/CarlaNative.hpp +++ b/source/includes/CarlaNative.hpp @@ -1,6 +1,6 @@ /* * Carla Native Plugin API (C++) - * Copyright (C) 2012-2014 Filipe Coelho + * Copyright (C) 2012-2019 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 @@ -113,6 +113,13 @@ protected: pHost->ui_parameter_changed(pHost->handle, index, value); } + void uiParameterTouch(const uint32_t index, const bool touch) const + { + CARLA_SAFE_ASSERT_RETURN(pHost != nullptr,); + + pHost->ui_parameter_touch(pHost->handle, index, touch); + } + void uiMidiProgramChanged(const uint8_t channel, const uint32_t bank, const uint32_t program) const { CARLA_SAFE_ASSERT_RETURN(pHost != nullptr,); diff --git a/source/modules/distrho/src/DistrhoPluginCarla.cpp b/source/modules/distrho/src/DistrhoPluginCarla.cpp index 0bbb3a504..491e94aab 100644 --- a/source/modules/distrho/src/DistrhoPluginCarla.cpp +++ b/source/modules/distrho/src/DistrhoPluginCarla.cpp @@ -98,9 +98,9 @@ public: // --------------------------------------------- protected: - void handleEditParameter(const uint32_t, const bool) + void handleEditParameter(const uint32_t index, const bool touch) { - // TODO + fHost->ui_parameter_touch(fHost->handle, rindex, touch); } void handleSetParameterValue(const uint32_t rindex, const float value) diff --git a/source/plugin/carla-lv2-export.cpp b/source/plugin/carla-lv2-export.cpp index e6de2eb26..ed38ccdc6 100644 --- a/source/plugin/carla-lv2-export.cpp +++ b/source/plugin/carla-lv2-export.cpp @@ -198,6 +198,7 @@ static void writePluginFile(const NativePluginDescriptor* const pluginDesc) hostDesc.get_time_info = nullptr; hostDesc.write_midi_event = nullptr; hostDesc.ui_parameter_changed = nullptr; + hostDesc.ui_parameter_touch = nullptr; hostDesc.ui_midi_program_changed = nullptr; hostDesc.ui_custom_data_changed = nullptr; hostDesc.ui_closed = nullptr; diff --git a/source/plugin/carla-lv2.cpp b/source/plugin/carla-lv2.cpp index c0fcf4b0d..e513bd636 100644 --- a/source/plugin/carla-lv2.cpp +++ b/source/plugin/carla-lv2.cpp @@ -94,6 +94,7 @@ public: fHost.get_time_info = host_get_time_info; fHost.write_midi_event = host_write_midi_event; fHost.ui_parameter_changed = host_ui_parameter_changed; + fHost.ui_parameter_touch = host_ui_parameter_touch; fHost.ui_custom_data_changed = host_ui_custom_data_changed; fHost.ui_closed = host_ui_closed; fHost.ui_open_file = host_ui_open_file; @@ -492,6 +493,11 @@ public: fUI.host = (const LV2_External_UI_Host*)features[i]->data; break; } + if (std::strcmp(features[i]->URI, LV2_UI__touch) == 0) + { + fUI.touch = (const LV2UI_Touch*)features[i]->data; + break; + } } if (fUI.host != nullptr) @@ -648,6 +654,12 @@ protected: fUI.writeFunction(fUI.controller, index+fPorts.indexOffset, sizeof(float), 0, &value); } + void handleUiParameterTouch(const uint32_t index, const bool touch) const + { + if (fUI.touch != nullptr && fUI.touch->touch != nullptr) + fUI.touch->touch(fUI.touch->handle, index+fPorts.indexOffset, touch); + } + void handleUiCustomDataChanged(const char* const key, const char* const value) const { carla_stdout("TODO: handleUiCustomDataChanged %s %s", key, value); @@ -668,6 +680,7 @@ protected: fUI.host->ui_closed(fUI.controller); fUI.host = nullptr; + fUI.touch = nullptr; fUI.writeFunction = nullptr; fUI.controller = nullptr; } @@ -784,6 +797,11 @@ private: handlePtr->handleUiParameterChanged(index, value); } + static void host_ui_parameter_touch(NativeHostHandle handle, uint32_t index, bool touch) + { + handlePtr->handleUiParameterTouch(index, touch); + } + static void host_ui_custom_data_changed(NativeHostHandle handle, const char* key, const char* value) { handlePtr->handleUiCustomDataChanged(key, value); diff --git a/source/plugin/carla-native-plugin.cpp b/source/plugin/carla-native-plugin.cpp index 8f5077a6b..474c89572 100644 --- a/source/plugin/carla-native-plugin.cpp +++ b/source/plugin/carla-native-plugin.cpp @@ -81,6 +81,7 @@ int main() nullptr, // write_midi_event nullptr, // ui_parameter_changed + nullptr, // ui_parameter_touch nullptr, // ui_midi_program_changed nullptr, // ui_custom_data_changed nullptr, // ui_closed diff --git a/source/plugin/carla-vst-export.cpp b/source/plugin/carla-vst-export.cpp index b89a13d9f..95a56d3c3 100644 --- a/source/plugin/carla-vst-export.cpp +++ b/source/plugin/carla-vst-export.cpp @@ -17,10 +17,8 @@ #include "carla-vst.hpp" -#ifndef CARLA_OS_LINUX -# include "ui_launcher.cpp" -# include "ui_launcher_res.cpp" -#endif +#include "ui_launcher.cpp" +#include "ui_launcher_res.cpp" #include diff --git a/source/plugin/carla-vst.cpp b/source/plugin/carla-vst.cpp index fe0ae22d3..01ad5ccf4 100644 --- a/source/plugin/carla-vst.cpp +++ b/source/plugin/carla-vst.cpp @@ -131,14 +131,15 @@ public: fHost.get_time_info = host_get_time_info; fHost.write_midi_event = host_write_midi_event; fHost.ui_parameter_changed = host_ui_parameter_changed; + fHost.ui_parameter_touch = host_ui_parameter_touch; fHost.ui_custom_data_changed = host_ui_custom_data_changed; fHost.ui_closed = host_ui_closed; fHost.ui_open_file = host_ui_open_file; fHost.ui_save_file = host_ui_save_file; fHost.dispatcher = host_dispatcher; - fVstRect.top = 0; - fVstRect.left = 0; + fVstRect.top = 0; + fVstRect.left = 0; if (kIsUsingUILauncher) { @@ -406,8 +407,12 @@ public: case effEditOpen: if (fDescriptor->ui_show != nullptr) { -#ifdef HAVE_X11 - if (! kIsUsingUILauncher) + if (kIsUsingUILauncher) + { + destoryUILauncher(fUiLauncher); + fUiLauncher = createUILauncher((intptr_t)ptr, fDescriptor, fHandle); + } + else { char strBuf[0xff+1]; std::snprintf(strBuf, 0xff, P_INTPTR, (intptr_t)ptr); @@ -422,12 +427,6 @@ public: // reset CARLA_PLUGIN_EMBED_WINID just in case carla_setenv("CARLA_PLUGIN_EMBED_WINID", "0"); } - else -#endif - { - destoryUILauncher(fUiLauncher); - fUiLauncher = createUILauncher((intptr_t)ptr, fDescriptor, fHandle); - } ret = 1; } break; @@ -435,16 +434,14 @@ public: case effEditClose: if (fDescriptor->ui_show != nullptr) { -#ifdef HAVE_X11 - if (! kIsUsingUILauncher) + if (kIsUsingUILauncher) { - fDescriptor->ui_show(fHandle, false); + destoryUILauncher(fUiLauncher); + fUiLauncher = nullptr; } else -#endif { - destoryUILauncher(fUiLauncher); - fUiLauncher = nullptr; + fDescriptor->ui_show(fHandle, false); } ret = 1; } @@ -726,6 +723,12 @@ protected: hostCallback(audioMasterAutomate, static_cast(index), 0, nullptr, normalizedValue); } + void handleUiParameterTouch(const uint32_t index, const bool touch) const + { + carla_stdout("VST handleUiParameterTouch %u %s", index, bool2str(touch)); + hostCallback(touch ? audioMasterBeginEdit : audioMasterEndEdit, static_cast(index)); + } + void handleUiCustomDataChanged(const char* const /*key*/, const char* const /*value*/) const { } @@ -877,6 +880,11 @@ private: handlePtr->handleUiParameterChanged(index, value); } + static void host_ui_parameter_touch(NativeHostHandle handle, uint32_t index, bool touch) + { + handlePtr->handleUiParameterTouch(index, touch); + } + static void host_ui_custom_data_changed(NativeHostHandle handle, const char* key, const char* value) { handlePtr->handleUiCustomDataChanged(key, value); diff --git a/source/plugin/carla-vst.hpp b/source/plugin/carla-vst.hpp index ffc932d57..bba23a566 100644 --- a/source/plugin/carla-vst.hpp +++ b/source/plugin/carla-vst.hpp @@ -15,11 +15,14 @@ * For a full copy of the GNU General Public License see the doc/GPL.txt file. */ +#ifndef CARLA_VST_HPP_INCLUDED +#define CARLA_VST_HPP_INCLUDED + #include "CarlaDefines.h" #include "CarlaNative.h" #include "vestige/vestige.h" -# include "ui_launcher_res.hpp" +#include "ui_launcher_res.hpp" struct CarlaUILauncher; class NativePlugin; @@ -44,3 +47,5 @@ float vst_getParameterCallback(AEffect* effect, int32_t index); void vst_setParameterCallback(AEffect* effect, int32_t index, float value); void vst_processCallback(AEffect* effect, float** inputs, float** outputs, int32_t sampleFrames); void vst_processReplacingCallback(AEffect* effect, float** inputs, float** outputs, int32_t sampleFrames); + +#endif // CARLA_VST_HPP_INCLUDED diff --git a/source/utils/CarlaLv2Utils.hpp b/source/utils/CarlaLv2Utils.hpp index 77544a537..d46272515 100644 --- a/source/utils/CarlaLv2Utils.hpp +++ b/source/utils/CarlaLv2Utils.hpp @@ -1137,6 +1137,7 @@ public: handleUiHide(); fUI.host = nullptr; + fUI.touch = nullptr; fUI.writeFunction = nullptr; fUI.controller = nullptr; } @@ -1535,12 +1536,14 @@ protected: struct UI { const LV2_External_UI_Host* host; + const LV2UI_Touch* touch; LV2UI_Write_Function writeFunction; LV2UI_Controller controller; bool isVisible; UI() : host(nullptr), + touch(nullptr), writeFunction(nullptr), controller(nullptr), isVisible(false) {}