From a4603ef1598a361117f42361303fab6833325b22 Mon Sep 17 00:00:00 2001 From: falkTX Date: Mon, 3 Mar 2014 04:49:23 +0000 Subject: [PATCH] In-canvas parameters experiment --- source/backend/CarlaBackend.h | 32 +++-- source/backend/CarlaEngine.hpp | 2 +- source/backend/CarlaHost.h | 8 +- source/backend/engine/CarlaEngine.cpp | 71 ++++++++--- source/backend/engine/CarlaEngineJack.cpp | 18 +-- source/backend/engine/CarlaEngineNative.cpp | 6 +- source/backend/standalone/CarlaStandalone.cpp | 7 +- source/carla | 5 + source/carla-plugin | 4 +- source/carla_backend.py | 42 ++++--- source/carla_host.py | 7 +- source/carla_patchbay.py | 119 ++++++++++++++++-- source/patchcanvas.py | 92 +++++++++++--- source/utils/CarlaBackendUtils.hpp | 2 + 14 files changed, 321 insertions(+), 94 deletions(-) diff --git a/source/backend/CarlaBackend.h b/source/backend/CarlaBackend.h index 5cef7dace..04512a432 100644 --- a/source/backend/CarlaBackend.h +++ b/source/backend/CarlaBackend.h @@ -858,18 +858,26 @@ typedef enum { */ ENGINE_CALLBACK_PATCHBAY_PORT_RENAMED = 25, + /*! + * A patchbay port value has changed. + * @param pluginId Client Id + * @param value1 Port Id + * @param value3 New port value + */ + ENGINE_CALLBACK_PATCHBAY_PORT_VALUE_CHANGED = 26, + /*! * A patchbay connection has been added. * @param pluginId Connection Id * @param valueStr Out group, port plus in group and port, in "og:op:ig:ip" syntax. */ - ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED = 26, + ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED = 27, /*! * A patchbay connection has been removed. * @param pluginId Connection Id */ - ENGINE_CALLBACK_PATCHBAY_CONNECTION_REMOVED = 27, + ENGINE_CALLBACK_PATCHBAY_CONNECTION_REMOVED = 28, /*! * Engine started. @@ -879,62 +887,62 @@ typedef enum { * @see EngineProcessMode * @see EngineTransportMode */ - ENGINE_CALLBACK_ENGINE_STARTED = 28, + ENGINE_CALLBACK_ENGINE_STARTED = 29, /*! * Engine stopped. */ - ENGINE_CALLBACK_ENGINE_STOPPED = 29, + ENGINE_CALLBACK_ENGINE_STOPPED = 30, /*! * Engine process mode has changed. * @param value1 New process mode * @see EngineProcessMode */ - ENGINE_CALLBACK_PROCESS_MODE_CHANGED = 30, + ENGINE_CALLBACK_PROCESS_MODE_CHANGED = 31, /*! * Engine transport mode has changed. * @param value1 New transport mode * @see EngineTransportMode */ - ENGINE_CALLBACK_TRANSPORT_MODE_CHANGED = 31, + ENGINE_CALLBACK_TRANSPORT_MODE_CHANGED = 32, /*! * Engine buffer-size changed. * @param value1 New buffer size */ - ENGINE_CALLBACK_BUFFER_SIZE_CHANGED = 32, + ENGINE_CALLBACK_BUFFER_SIZE_CHANGED = 33, /*! * Engine sample-rate changed. * @param value3 New sample rate */ - ENGINE_CALLBACK_SAMPLE_RATE_CHANGED = 33, + ENGINE_CALLBACK_SAMPLE_RATE_CHANGED = 34, /*! * Idle frontend.\n * This is used by the engine during long operations that might block the frontend, * giving it the possibility to idle while the operation is still in place. */ - ENGINE_CALLBACK_IDLE = 34, + ENGINE_CALLBACK_IDLE = 35, /*! * Show a message as information. * @param valueStr The message */ - ENGINE_CALLBACK_INFO = 35, + ENGINE_CALLBACK_INFO = 36, /*! * Show a message as an error. * @param valueStr The message */ - ENGINE_CALLBACK_ERROR = 36, + ENGINE_CALLBACK_ERROR = 37, /*! * The engine has crashed or malfunctioned and will no longer work. */ - ENGINE_CALLBACK_QUIT = 37 + ENGINE_CALLBACK_QUIT = 38 } EngineCallbackOpcode; diff --git a/source/backend/CarlaEngine.hpp b/source/backend/CarlaEngine.hpp index cddce4212..d40975011 100644 --- a/source/backend/CarlaEngine.hpp +++ b/source/backend/CarlaEngine.hpp @@ -892,7 +892,7 @@ public: /*! * Connect patchbay ports \a portA and \a portB. */ - virtual bool patchbayConnect(const int portA, const int portB); + virtual bool patchbayConnect(const int groupA, const int portA, const int groupB, const int portB); /*! * Disconnect patchbay connection \a connectionId. diff --git a/source/backend/CarlaHost.h b/source/backend/CarlaHost.h index a00b4eecb..578bc489a 100644 --- a/source/backend/CarlaHost.h +++ b/source/backend/CarlaHost.h @@ -492,11 +492,13 @@ CARLA_EXPORT bool carla_save_project(const char* filename); #ifndef BUILD_BRIDGE /*! * Connect two patchbay ports. - * @param portIdA Output port - * @param portIdB Input port + * @param groupIdA Output group + * @param portIdA Output port + * @param groupIdB Input group + * @param portIdB Input port * @see ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED */ -CARLA_EXPORT bool carla_patchbay_connect(int portIdA, int portIdB); +CARLA_EXPORT bool carla_patchbay_connect(int groupIdA, int portIdA, int groupIdB, int portIdB); /*! * Disconnect two patchbay ports. diff --git a/source/backend/engine/CarlaEngine.cpp b/source/backend/engine/CarlaEngine.cpp index 280540d5d..e221db02c 100644 --- a/source/backend/engine/CarlaEngine.cpp +++ b/source/backend/engine/CarlaEngine.cpp @@ -1663,7 +1663,7 @@ void CarlaEngine::setFileCallback(const FileCallbackFunc func, void* const ptr) // ----------------------------------------------------------------------- // Patchbay -bool CarlaEngine::patchbayConnect(const int portA, const int portB) +bool CarlaEngine::patchbayConnect(const int /*groupA*/, const int portA, const int /*groupB*/, const int portB) { CARLA_SAFE_ASSERT_RETURN(pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK || pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY, false); CARLA_SAFE_ASSERT_RETURN(pData->bufAudio.isReady, false); @@ -2179,36 +2179,75 @@ void CarlaEngine::restorePatchbayConnection(const char* const connSource, const } else { - int sourcePort, targetPort; + int sourceGroup, targetGroup; + int sourcePort, targetPort; if (std::strncmp(connSource, "Carla:", 6) == 0) - sourcePort = getCarlaPortIdFromName(connSource+6); + { + sourceGroup = RACK_PATCHBAY_GROUP_CARLA; + sourcePort = getCarlaPortIdFromName(connSource+6); + } else if (std::strncmp(connSource, "AudioIn:", 8) == 0) - sourcePort = std::atoi(connSource+8) + RACK_PATCHBAY_GROUP_AUDIO_IN*1000 - 1; + { + sourceGroup = RACK_PATCHBAY_GROUP_AUDIO_IN; + sourcePort = std::atoi(connSource+8) - 1; + } else if (std::strncmp(connSource, "AudioOut:", 9) == 0) - sourcePort = std::atoi(connSource+9) + RACK_PATCHBAY_GROUP_AUDIO_OUT*1000 - 1; + { + sourceGroup = RACK_PATCHBAY_GROUP_AUDIO_OUT; + sourcePort = std::atoi(connSource+9) - 1; + } else if (std::strncmp(connSource, "MidiIn:", 7) == 0) - sourcePort = std::atoi(connSource+7) + RACK_PATCHBAY_GROUP_MIDI_IN*1000 - 1; + { + sourceGroup = RACK_PATCHBAY_GROUP_MIDI_IN; + sourcePort = std::atoi(connSource+7) - 1; + } else if (std::strncmp(connSource, "MidiOut:", 8) == 0) - sourcePort = std::atoi(connSource+8) + RACK_PATCHBAY_GROUP_MIDI_OUT*1000 - 1; + { + sourceGroup = RACK_PATCHBAY_GROUP_MIDI_OUT; + sourcePort = std::atoi(connSource+8) - 1; + } else - sourcePort = RACK_PATCHBAY_PORT_MAX; + { + sourceGroup = RACK_PATCHBAY_GROUP_MAX; + sourcePort = RACK_PATCHBAY_PORT_MAX; + } if (std::strncmp(connTarget, "Carla:", 6) == 0) - targetPort = getCarlaPortIdFromName(connTarget+6); + { + targetGroup = RACK_PATCHBAY_GROUP_CARLA; + targetPort = getCarlaPortIdFromName(connTarget+6); + } else if (std::strncmp(connTarget, "AudioIn:", 8) == 0) - targetPort = std::atoi(connTarget+8) + RACK_PATCHBAY_GROUP_AUDIO_IN*1000 - 1; + { + targetGroup = RACK_PATCHBAY_GROUP_AUDIO_IN; + targetPort = std::atoi(connTarget+8) - 1; + } else if (std::strncmp(connTarget, "AudioOut:", 9) == 0) - targetPort = std::atoi(connTarget+9) + RACK_PATCHBAY_GROUP_AUDIO_OUT*1000 - 1; + { + targetGroup = RACK_PATCHBAY_GROUP_AUDIO_OUT; + targetPort = std::atoi(connTarget+9) - 1; + } else if (std::strncmp(connTarget, "MidiIn:", 7) == 0) - targetPort = std::atoi(connTarget+7) + RACK_PATCHBAY_GROUP_MIDI_IN*1000 - 1; + { + targetGroup = RACK_PATCHBAY_GROUP_MIDI_IN; + targetPort = std::atoi(connTarget+7) - 1; + } else if (std::strncmp(connTarget, "MidiOut:", 8) == 0) - targetPort = std::atoi(connTarget+8) + RACK_PATCHBAY_GROUP_MIDI_OUT*1000 - 1; + { + targetGroup = RACK_PATCHBAY_GROUP_MIDI_OUT; + targetPort = std::atoi(connTarget+8) - 1; + } else - targetPort = RACK_PATCHBAY_PORT_MAX; + { + targetGroup = RACK_PATCHBAY_GROUP_MAX; + targetPort = RACK_PATCHBAY_PORT_MAX; + } + + CARLA_SAFE_ASSERT_RETURN(sourceGroup == RACK_PATCHBAY_GROUP_MAX || sourcePort == RACK_PATCHBAY_PORT_MAX,); + CARLA_SAFE_ASSERT_RETURN(targetGroup == RACK_PATCHBAY_GROUP_MAX || targetPort == RACK_PATCHBAY_PORT_MAX,); - if (sourcePort != RACK_PATCHBAY_PORT_MAX && targetPort != RACK_PATCHBAY_PORT_MAX) - patchbayConnect(targetPort, sourcePort); + patchbayConnect(targetGroup, targetPort, sourceGroup, sourcePort); } } #endif diff --git a/source/backend/engine/CarlaEngineJack.cpp b/source/backend/engine/CarlaEngineJack.cpp index a48716d54..b99005bf5 100644 --- a/source/backend/engine/CarlaEngineJack.cpp +++ b/source/backend/engine/CarlaEngineJack.cpp @@ -948,7 +948,7 @@ public: // ------------------------------------------------------------------- // Patchbay - bool patchbayConnect(int portA, int portB) override + bool patchbayConnect(const int groupA, const int portA, const int groupB, const int portB) override { CARLA_SAFE_ASSERT_RETURN(fClient != nullptr, false); @@ -963,16 +963,14 @@ public: // both must be < 0 CARLA_SAFE_ASSERT_RETURN(portA < 0 && portB < 0, false); -#if 0 ConnectionToId connectionToId; - connectionToId.setData(fLastConnectionId++, portIdA.groupId, portIdA.portId, portIdB.groupId, portIdB.portId); + connectionToId.setData(fLastConnectionId++, groupA, portA, groupB, portB); fUsedConnections.append(connectionToId); char strBuf[STR_MAX+1]; - std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i", portIdA.groupId, portIdA.portId, portIdB.groupId, portIdB.portId); + std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i", groupA, portA, groupB, portB); callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, connectionToId.id, 0, 0, 0.0f, strBuf); -#endif return true; } @@ -991,7 +989,7 @@ public: return true; } - bool patchbayDisconnect(uint connectionId) override + bool patchbayDisconnect(const uint connectionId) override { CARLA_SAFE_ASSERT_RETURN(fClient != nullptr, false); @@ -1949,6 +1947,7 @@ private: callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, static_cast(groupId), icon, pluginId, 0.0f, groupName); +#if 0 if (pluginId >= 0) { CarlaPlugin* const plugin(getPlugin(static_cast(pluginId))); @@ -1970,10 +1969,15 @@ private: plugin->getParameterName(j, strBuf); - callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, static_cast(groupId), static_cast(j)-1, static_cast(canvasPortFlags), 0.0f, strBuf); + const int pluginPortId = -static_cast(j)-1; + const float pluginValue = plugin->getParameterRanges(j).getNormalizedValue(plugin->getParameterValue(j)); + + callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, static_cast(groupId), pluginPortId, static_cast(canvasPortFlags), 0.0f, strBuf); + callback(ENGINE_CALLBACK_PATCHBAY_PORT_VALUE_CHANGED, static_cast(groupId), pluginPortId, 0, pluginValue, nullptr); } } } +#endif } bool portIsInput = (jackPortFlags & JackPortIsInput); diff --git a/source/backend/engine/CarlaEngineNative.cpp b/source/backend/engine/CarlaEngineNative.cpp index 549d759f2..b0459303f 100644 --- a/source/backend/engine/CarlaEngineNative.cpp +++ b/source/backend/engine/CarlaEngineNative.cpp @@ -113,12 +113,14 @@ protected: } else if (std::strcmp(msg, "patchbay_connect") == 0) { - int32_t portA, portB; + int32_t groupA, portA, groupB, portB; + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(groupA), true); CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(portA), true); + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(groupB), true); CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(portB), true); - ok = fEngine->patchbayConnect(portA, portB); + ok = fEngine->patchbayConnect(groupA, portA, groupB, portB); } else if (std::strcmp(msg, "patchbay_disconnect") == 0) { diff --git a/source/backend/standalone/CarlaStandalone.cpp b/source/backend/standalone/CarlaStandalone.cpp index 89f0dccc3..d25508c2d 100644 --- a/source/backend/standalone/CarlaStandalone.cpp +++ b/source/backend/standalone/CarlaStandalone.cpp @@ -927,13 +927,12 @@ bool carla_save_project(const char* filename) #ifndef BUILD_BRIDGE // ------------------------------------------------------------------------------------------------------------------- -bool carla_patchbay_connect(int portIdA, int portIdB) +bool carla_patchbay_connect(int groupIdA, int portIdA, int groupIdB, int portIdB) { - CARLA_SAFE_ASSERT_RETURN(portIdA != portIdB, false); - carla_debug("carla_patchbay_connect(%i, %i)", portIdA, portIdB); + carla_debug("carla_patchbay_connect(%i, %i, %i, %i)", groupIdA, portIdA, groupIdB, portIdB); if (gStandalone.engine != nullptr) - return gStandalone.engine->patchbayConnect(portIdA, portIdB); + return gStandalone.engine->patchbayConnect(groupIdA, portIdA, groupIdB, portIdB); carla_stderr2("Engine is not running"); gStandalone.lastError = "Engine is not running"; diff --git a/source/carla b/source/carla index e2bf29aa8..71b31c044 100755 --- a/source/carla +++ b/source/carla @@ -80,6 +80,7 @@ class CarlaMultiW(QTabWidget): parent.ui.act_settings_configure.triggered.connect(self.fPatchbay.slot_configureCarla) parent.ParameterValueChangedCallback.connect(self.fRack.slot_handleParameterValueChangedCallback) + parent.ParameterValueChangedCallback.connect(self.fPatchbay.slot_handleParameterValueChangedCallback) parent.ParameterDefaultChangedCallback.connect(self.fRack.slot_handleParameterDefaultChangedCallback) parent.ParameterMidiChannelChangedCallback.connect(self.fRack.slot_handleParameterMidiChannelChangedCallback) parent.ParameterMidiCcChangedCallback.connect(self.fRack.slot_handleParameterMidiCcChangedCallback) @@ -93,8 +94,10 @@ class CarlaMultiW(QTabWidget): parent.UpdateCallback.connect(self.fRack.slot_handleUpdateCallback) parent.ReloadInfoCallback.connect(self.fRack.slot_handleReloadInfoCallback) parent.ReloadParametersCallback.connect(self.fRack.slot_handleReloadParametersCallback) + parent.ReloadParametersCallback.connect(self.fPatchbay.slot_handleReloadParametersCallback) parent.ReloadProgramsCallback.connect(self.fRack.slot_handleReloadProgramsCallback) parent.ReloadAllCallback.connect(self.fRack.slot_handleReloadAllCallback) + parent.ReloadAllCallback.connect(self.fPatchbay.slot_handleReloadAllCallback) parent.PatchbayClientAddedCallback.connect(self.fPatchbay.slot_handlePatchbayClientAddedCallback) parent.PatchbayClientRemovedCallback.connect(self.fPatchbay.slot_handlePatchbayClientRemovedCallback) @@ -103,6 +106,7 @@ class CarlaMultiW(QTabWidget): parent.PatchbayPortAddedCallback.connect(self.fPatchbay.slot_handlePatchbayPortAddedCallback) parent.PatchbayPortRemovedCallback.connect(self.fPatchbay.slot_handlePatchbayPortRemovedCallback) parent.PatchbayPortRenamedCallback.connect(self.fPatchbay.slot_handlePatchbayPortRenamedCallback) + parent.PatchbayPortValueChangedCallback.connect(self.fPatchbay.slot_handlePatchbayPortValueChangedCallback) parent.PatchbayConnectionAddedCallback.connect(self.fPatchbay.slot_handlePatchbayConnectionAddedCallback) parent.PatchbayConnectionRemovedCallback.connect(self.fPatchbay.slot_handlePatchbayConnectionRemovedCallback) @@ -154,6 +158,7 @@ class CarlaMultiW(QTabWidget): def idleSlow(self): self.fRack.idleSlow() + self.fPatchbay.idleSlow() # ----------------------------------------------------------------- diff --git a/source/carla-plugin b/source/carla-plugin index 44f26a345..645de8a52 100755 --- a/source/carla-plugin +++ b/source/carla-plugin @@ -261,8 +261,8 @@ class PluginHost(object): # ------------------------------------------------------------------- - def patchbay_connect(self, portIdA, portIdB): - gCarla.gui.send(["patchbay_connect", portIdA, portIdB]) + def patchbay_connect(self, groupIdA, portIdA, groupIdB, portIdB): + gCarla.gui.send(["patchbay_connect", groupIdA, portIdA, groupIdB, portIdB]) return True def patchbay_disconnect(self, connectionId): diff --git a/source/carla_backend.py b/source/carla_backend.py index c66c17934..2d2172428 100644 --- a/source/carla_backend.py +++ b/source/carla_backend.py @@ -648,14 +648,20 @@ ENGINE_CALLBACK_PATCHBAY_PORT_REMOVED = 24 # @param valueStr New port name ENGINE_CALLBACK_PATCHBAY_PORT_RENAMED = 25 +# A patchbay port value has changed. +# @param pluginId Client Id +# @param value1 Port Id +# @param value3 New port value +ENGINE_CALLBACK_PATCHBAY_PORT_VALUE_CHANGED = 26 + # A patchbay connection has been added. # @param pluginId Connection Id # @param valueStr Out group, port plus in group and port, in "og:op:ig:ip" syntax. -ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED = 26 +ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED = 27 # A patchbay connection has been removed. # @param pluginId Connection Id -ENGINE_CALLBACK_PATCHBAY_CONNECTION_REMOVED = 27 +ENGINE_CALLBACK_PATCHBAY_CONNECTION_REMOVED = 28 # Engine started. # @param value1 Process mode @@ -663,44 +669,44 @@ ENGINE_CALLBACK_PATCHBAY_CONNECTION_REMOVED = 27 # @param valuestr Engine driver # @see EngineProcessMode # @see EngineTransportMode -ENGINE_CALLBACK_ENGINE_STARTED = 28 +ENGINE_CALLBACK_ENGINE_STARTED = 29 # Engine stopped. -ENGINE_CALLBACK_ENGINE_STOPPED = 29 +ENGINE_CALLBACK_ENGINE_STOPPED = 30 # Engine process mode has changed. # @param value1 New process mode # @see EngineProcessMode -ENGINE_CALLBACK_PROCESS_MODE_CHANGED = 30 +ENGINE_CALLBACK_PROCESS_MODE_CHANGED = 31 # Engine transport mode has changed. # @param value1 New transport mode # @see EngineTransportMode -ENGINE_CALLBACK_TRANSPORT_MODE_CHANGED = 31 +ENGINE_CALLBACK_TRANSPORT_MODE_CHANGED = 32 # Engine buffer-size changed. # @param value1 New buffer size -ENGINE_CALLBACK_BUFFER_SIZE_CHANGED = 32 +ENGINE_CALLBACK_BUFFER_SIZE_CHANGED = 33 # Engine sample-rate changed. # @param value3 New sample rate -ENGINE_CALLBACK_SAMPLE_RATE_CHANGED = 33 +ENGINE_CALLBACK_SAMPLE_RATE_CHANGED = 34 # Idle frontend. # This is used by the engine during long operations that might block the frontend, # giving it the possibility to idle while the operation is still in place. -ENGINE_CALLBACK_IDLE = 34 +ENGINE_CALLBACK_IDLE = 35 # Show a message as information. # @param valueStr The message -ENGINE_CALLBACK_INFO = 35 +ENGINE_CALLBACK_INFO = 36 # Show a message as an error. # @param valueStr The message -ENGINE_CALLBACK_ERROR = 36 +ENGINE_CALLBACK_ERROR = 37 # The engine has crashed or malfunctioned and will no longer work. -ENGINE_CALLBACK_QUIT = 37 +ENGINE_CALLBACK_QUIT = 38 # ------------------------------------------------------------------------------------------------------------ # Engine Option @@ -1345,11 +1351,13 @@ class Host(object): return bool(self.lib.carla_save_project(filename.encode("utf-8"))) # Connect two patchbay ports. - # @param portIdA Output port - # @param portIdB Input port + # @param groupIdA Output group + # @param portIdA Output port + # @param groupIdB Input group + # @param portIdB Input port # @see ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED - def patchbay_connect(self, portIdA, portIdB): - return bool(self.lib.carla_patchbay_connect(portIdA, portIdB)) + def patchbay_connect(self, groupIdA, portIdA, groupIdB, portIdB): + return bool(self.lib.carla_patchbay_connect(groupIdA, portIdA, groupIdB, portIdB)) # Disconnect two patchbay ports. # @param connectionId Connection Id @@ -1798,7 +1806,7 @@ class Host(object): self.lib.carla_save_project.argtypes = [c_char_p] self.lib.carla_save_project.restype = c_bool - self.lib.carla_patchbay_connect.argtypes = [c_int, c_int] + self.lib.carla_patchbay_connect.argtypes = [c_int, c_int, c_int, c_int] self.lib.carla_patchbay_connect.restype = c_bool self.lib.carla_patchbay_disconnect.argtypes = [c_uint] diff --git a/source/carla_host.py b/source/carla_host.py index 3757589ce..fe1fbcfa0 100644 --- a/source/carla_host.py +++ b/source/carla_host.py @@ -149,6 +149,7 @@ class HostWindow(QMainWindow): PatchbayPortAddedCallback = pyqtSignal(int, int, int, str) PatchbayPortRemovedCallback = pyqtSignal(int, int) PatchbayPortRenamedCallback = pyqtSignal(int, int, str) + PatchbayPortValueChangedCallback = pyqtSignal(int, int, float) PatchbayConnectionAddedCallback = pyqtSignal(int, int, int, int, int) PatchbayConnectionRemovedCallback = pyqtSignal(int, int, int) EngineStartedCallback = pyqtSignal(int, int, str) @@ -741,7 +742,7 @@ class HostWindow(QMainWindow): if self.fIdleTimerSlow != 0: self.killTimer(self.fIdleTimerSlow) - self.fIdleTimerSlow = self.startTimer(self.fSavedSettings[CARLA_KEY_MAIN_REFRESH_INTERVAL]*2) + self.fIdleTimerSlow = self.startTimer(self.fSavedSettings[CARLA_KEY_MAIN_REFRESH_INTERVAL]*4) def saveSettings(self): settings = QSettings() @@ -1088,7 +1089,7 @@ class HostWindow(QMainWindow): if self.fIdleTimerFast == 0: self.fIdleTimerFast = self.startTimer(self.fSavedSettings[CARLA_KEY_MAIN_REFRESH_INTERVAL]) if self.fIdleTimerSlow == 0: - self.fIdleTimerSlow = self.startTimer(self.fSavedSettings[CARLA_KEY_MAIN_REFRESH_INTERVAL]*2) + self.fIdleTimerSlow = self.startTimer(self.fSavedSettings[CARLA_KEY_MAIN_REFRESH_INTERVAL]*4) @pyqtSlot() def slot_handleEngineStoppedCallback(self): @@ -1277,6 +1278,8 @@ def engineCallback(ptr, action, pluginId, value1, value2, value3, valueStr): gCarla.gui.PatchbayPortRemovedCallback.emit(pluginId, value1) elif action == ENGINE_CALLBACK_PATCHBAY_PORT_RENAMED: gCarla.gui.PatchbayPortRenamedCallback.emit(pluginId, value1, valueStr) + elif action == ENGINE_CALLBACK_PATCHBAY_PORT_VALUE_CHANGED: + gCarla.gui.PatchbayPortValueChangedCallback.emit(pluginId, value1, value3) elif action == ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED: gOut, pOut, gIn, pIn = [int(i) for i in valueStr.split(":")] gCarla.gui.PatchbayConnectionAddedCallback.emit(pluginId, gOut, pOut, gIn, pIn) diff --git a/source/carla_patchbay.py b/source/carla_patchbay.py index 152cce722..4dbd8e536 100644 --- a/source/carla_patchbay.py +++ b/source/carla_patchbay.py @@ -60,6 +60,94 @@ except: CARLA_DEFAULT_CANVAS_SIZE_WIDTH = 3100 CARLA_DEFAULT_CANVAS_SIZE_HEIGHT = 2400 +# ------------------------------------------------------------------------------------------------ +# Patchbay info class, used in main carla as replacement for PluginEdit + +class PluginInfo(object): + def __init__(self, parent, pluginId): + object.__init__(self) + + self.fGroupId = None + self.fPluginId = pluginId + + self.fParameterList = [] # type, index, min, max + + self.reloadParameters() + + def close(self): + for paramType, paramIndex, paramMin, paramMax in self.fParameterList: + patchcanvas.removePort(self.fGroupId, -paramIndex-1) + + #------------------------------------------------------------------ + + def reloadAll(self): + self.reloadParameters() + + def reloadParameters(self): + # Remove all previous parameters + self.close() + + hasGroup, groupId = patchcanvas.getPluginAsGroup(self.fPluginId) + + if not hasGroup: + self.fGroupId = None + return + + self.fGroupId = groupId + + # Reset + self.fParameterList = [] + + if gCarla.host is None: + return + + parameterCount = gCarla.host.get_parameter_count(self.fPluginId) + + if parameterCount <= 0 or parameterCount > 25: + return + + for i in range(parameterCount): + paramInfo = gCarla.host.get_parameter_info(self.fPluginId, i) + paramData = gCarla.host.get_parameter_data(self.fPluginId, i) + paramRanges = gCarla.host.get_parameter_ranges(self.fPluginId, i) + paramValue = gCarla.host.get_current_parameter_value(self.fPluginId, i) + + if paramData['type'] not in (PARAMETER_INPUT, PARAMETER_OUTPUT): + #if paramData['type'] != PARAMETER_INPUT: + continue + if (paramData['hints'] & PARAMETER_IS_AUTOMABLE) == 0: + continue + + portId = -i-1 + portMode = patchcanvas.PORT_MODE_OUTPUT if paramData['type'] == PARAMETER_OUTPUT else patchcanvas.PORT_MODE_INPUT + portValue = (paramValue - paramRanges['min']) / (paramRanges['max'] - paramRanges['min']) + patchcanvas.addPort(groupId, portId, paramInfo['name'], portMode, patchcanvas.PORT_TYPE_PARAMETER) + patchcanvas.setPortValue(groupId, portId, portValue) + + self.fParameterList.append((paramData['type'], i, paramRanges['min'], paramRanges['max'])) + + #------------------------------------------------------------------ + + def setId(self, idx): + self.fPluginId = idx + + def setParameterValue(self, parameterId, value): + if self.fGroupId is None: + return + + paramRanges = gCarla.host.get_parameter_ranges(self.fPluginId, parameterId) + portValue = (value - paramRanges['min']) / (paramRanges['max'] - paramRanges['min']) + patchcanvas.setPortValue(self.fGroupId, -parameterId-1, portValue) + + #------------------------------------------------------------------ + + def idleSlow(self): + # Update parameter outputs + for paramType, paramIndex, paramMin, paramMax in self.fParameterList: + if paramType == PARAMETER_OUTPUT: + portValue = (gCarla.host.get_current_parameter_value(self.fPluginId, paramIndex) - paramMin) / (paramMax - paramMin) + patchcanvas.setPortValue(self.fGroupId, -paramIndex-1, portValue) + # ------------------------------------------------------------------------------------------------ # Patchbay widget @@ -208,6 +296,7 @@ class CarlaPatchbayW(QFrame): parent.PatchbayPortAddedCallback.connect(self.slot_handlePatchbayPortAddedCallback) parent.PatchbayPortRemovedCallback.connect(self.slot_handlePatchbayPortRemovedCallback) parent.PatchbayPortRenamedCallback.connect(self.slot_handlePatchbayPortRenamedCallback) + parent.PatchbayPortValueChangedCallback.connect(self.slot_handlePatchbayPortValueChangedCallback) parent.PatchbayConnectionAddedCallback.connect(self.slot_handlePatchbayConnectionAddedCallback) parent.PatchbayConnectionRemovedCallback.connect(self.slot_handlePatchbayConnectionRemovedCallback) @@ -219,16 +308,15 @@ class CarlaPatchbayW(QFrame): # ----------------------------------------------------------------- def addPlugin(self, pluginId, isProjectLoading): - if not self.fIsOnlyPatchbay: - self.fPluginCount += 1 - return - - pitem = PluginEdit(self, pluginId) + if self.fIsOnlyPatchbay: + pitem = PluginEdit(self, pluginId) + else: + pitem = PluginInfo(self, pluginId) self.fPluginList.append(pitem) self.fPluginCount += 1 - if not isProjectLoading: + if self.fIsOnlyPatchbay and not isProjectLoading: gCarla.host.set_active(pluginId, True) def removePlugin(self, pluginId): @@ -237,10 +325,6 @@ class CarlaPatchbayW(QFrame): if pluginId in self.fSelectedPlugins: self.clearSideStuff() - if not self.fIsOnlyPatchbay: - self.fPluginCount -= 1 - return - if pluginId >= self.fPluginCount: return @@ -887,6 +971,10 @@ class CarlaPatchbayW(QFrame): patchcanvas.renamePort(groupId, portId, newPortName) QTimer.singleShot(0, self.fMiniCanvasPreview.update) + @pyqtSlot(int, int, float) + def slot_handlePatchbayPortValueChangedCallback(self, groupId, portId, value): + patchcanvas.setPortValue(groupId, portId, value) + @pyqtSlot(int, int, int, int, int) def slot_handlePatchbayConnectionAddedCallback(self, connectionId, groupOutId, portOutId, groupInId, portInId): patchcanvas.connectPorts(connectionId, groupOutId, portOutId, groupInId, portInId) @@ -909,6 +997,12 @@ class CarlaPatchbayW(QFrame): patchcanvas.clear() if gCarla.host.is_engine_running(): gCarla.host.patchbay_refresh() + + for pitem in self.fPluginList: + if pitem is None: + break + pitem.reloadAll() + QTimer.singleShot(1000 if self.fParent.fSavedSettings[CARLA_KEY_CANVAS_EYE_CANDY] else 0, self.fMiniCanvasPreview.update) @pyqtSlot() @@ -999,10 +1093,9 @@ def canvasCallback(action, value1, value2, valueStr): pass elif action == patchcanvas.ACTION_PORTS_CONNECT: - portIdA = value1 - portIdB = value2 + gOut, pOut, gIn, pIn = [int(i) for i in valueStr.split(":")] - if not gCarla.host.patchbay_connect(portIdA, portIdB): + if not gCarla.host.patchbay_connect(gOut, pOut, gIn, pIn): print("Connection failed:", gCarla.host.get_last_error()) elif action == patchcanvas.ACTION_PORTS_DISCONNECT: diff --git a/source/patchcanvas.py b/source/patchcanvas.py index aef662333..5674db579 100644 --- a/source/patchcanvas.py +++ b/source/patchcanvas.py @@ -70,7 +70,7 @@ ACTION_GROUP_SPLIT = 2 # group_id, N, N ACTION_GROUP_JOIN = 3 # group_id, N, N ACTION_PORT_INFO = 4 # port_id, N, N ACTION_PORT_RENAME = 5 # port_id, N, new_name -ACTION_PORTS_CONNECT = 6 # out_id, in_id, N +ACTION_PORTS_CONNECT = 6 # N, N, "outG:outP:inG:inP" ACTION_PORTS_DISCONNECT = 7 # conn_id, N, N ACTION_PLUGIN_CLONE = 8 # plugin_id, N, N ACTION_PLUGIN_EDIT = 9 # plugin_id, N, N @@ -140,6 +140,7 @@ class group_dict_t(object): 'group_name', 'split', 'icon', + 'plugin_id', 'widgets' ] @@ -444,6 +445,7 @@ def addGroup(group_id, group_name, split=SPLIT_UNDEF, icon=ICON_APPLICATION): group_dict.group_name = group_name group_dict.split = bool(split == SPLIT_YES) group_dict.icon = icon + group_dict.plugin_id = -1 group_dict.widgets = [group_box, None] if split == SPLIT_YES: @@ -759,12 +761,24 @@ def setGroupIcon(group_id, icon): qCritical("PatchCanvas::setGroupIcon(%i, %s) - unable to find group to change icon" % (group_id, icon2str(icon))) +def getPluginAsGroup(plugin_id): + if canvas.debug: + qDebug("PatchCanvas::getPluginAsGroup(%i)" % plugin_id) + + for group in canvas.group_list: + if group.plugin_id == plugin_id: + return (True, group.group_id) + + qCritical("PatchCanvas::getPluginAsGroup(%i) - no such plugin" % plugin_id) + return (False, -1) + def setGroupAsPlugin(group_id, plugin_id, hasUi): if canvas.debug: qDebug("PatchCanvas::setGroupAsPlugin(%i, %i, %s)" % (group_id, plugin_id, bool2str(hasUi))) for group in canvas.group_list: if group.group_id == group_id: + group.plugin_id = plugin_id group.widgets[0].setAsPlugin(plugin_id, hasUi) if group.split and group.widgets[1]: @@ -849,6 +863,17 @@ def renamePort(group_id, port_id, new_port_name): qCritical("PatchCanvas::renamePort(%i, %i, %s) - Unable to find port to rename" % (group_id, port_id, new_port_name.encode())) +def setPortValue(group_id, port_id, value): + if canvas.debug: + qDebug("PatchCanvas::setPortValue(%i, %i, %f)" % (group_id, port_id, value)) + + for port in canvas.port_list: + if port.group_id == group_id and port.port_id == port_id: + port.widget.setPortValue(value) + return + + qCritical("PatchCanvas::setPortValue(%i, %i, %f) - Unable to find port" % (group_id, port_id, value)) + def connectPorts(connection_id, group_out_id, port_out_id, group_in_id, port_in_id): if canvas.debug: qDebug("PatchCanvas::connectPorts(%i, %i, %i, %i, %i)" % (connection_id, group_out_id, port_out_id, group_in_id, port_in_id)) @@ -971,9 +996,10 @@ def handlePluginRemoved(plugin_id): qDebug("PatchCanvas::handlePluginRemoved(%i)" % plugin_id) for group in canvas.group_list: - if group.widgets[0].m_plugin_id < plugin_id: + if group.plugin_id < plugin_id: continue + group.plugin_id -= 1 group.widgets[0].m_plugin_id -= 1 if group.split and group.widgets[1]: @@ -1761,6 +1787,8 @@ class CanvasPort(QGraphicsItem): self.m_port_font.setPointSize(canvas.theme.port_font_size) self.m_port_font.setWeight(canvas.theme.port_font_state) + self.m_port_value = 1.0 + self.m_line_mov = None self.m_hover_item = None self.m_last_selected_state = False @@ -1770,6 +1798,9 @@ class CanvasPort(QGraphicsItem): self.setFlags(QGraphicsItem.ItemIsSelectable) + def getGroupId(self): + return self.m_group_id + def getPortId(self): return self.m_port_id @@ -1799,6 +1830,13 @@ class CanvasPort(QGraphicsItem): self.m_port_type = port_type self.update() + def setPortValue(self, value): + if self.m_port_value == value: + return + + self.m_port_value = value + self.update() + def setPortName(self, port_name): if QFontMetrics(self.m_port_font).width(port_name) < QFontMetrics(self.m_port_font).width(self.m_port_name): QTimer.singleShot(0, canvas.scene.update) @@ -1881,19 +1919,19 @@ class CanvasPort(QGraphicsItem): connection.widget.setLocked(False) if self.m_hover_item: - check = False + # TODO: a better way to check already existing connection for connection in canvas.connection_list: if ( (connection.port_out_id == self.m_port_id and connection.port_in_id == self.m_hover_item.getPortId()) or (connection.port_out_id == self.m_hover_item.getPortId() and connection.port_in_id == self.m_port_id) ): canvas.callback(ACTION_PORTS_DISCONNECT, connection.connection_id, 0, "") - check = True break - - if not check: + else: if self.m_port_mode == PORT_MODE_OUTPUT: - canvas.callback(ACTION_PORTS_CONNECT, self.m_port_id, self.m_hover_item.getPortId(), "") + conn = "%i:%i:%i:%i" % (self.m_group_id, self.m_port_id, self.m_hover_item.getGroupId(), self.m_hover_item.getPortId()) + canvas.callback(ACTION_PORTS_CONNECT, 0, 0, conn) else: - canvas.callback(ACTION_PORTS_CONNECT, self.m_hover_item.getPortId(), self.m_port_id, "") + conn = "%i:%i:%i:%i" % (self.m_hover_item.getGroupId(), self.m_hover_item.getPortId(), self.m_group_id, self.m_port_id) + canvas.callback(ACTION_PORTS_CONNECT, 0, 0, conn) canvas.scene.clearSelection() @@ -2043,15 +2081,39 @@ class CanvasPort(QGraphicsItem): polygon += QPointF(poly_locx[3], canvas.theme.port_height) polygon += QPointF(poly_locx[4], canvas.theme.port_height) - if canvas.theme.port_bg_pixmap: - portRect = polygon.boundingRect() - portPos = portRect.topLeft() - painter.drawTiledPixmap(portRect, canvas.theme.port_bg_pixmap, portPos) + if self.m_port_value == 1.0 or canvas.theme.port_bg_pixmap: + # normal paint + if canvas.theme.port_bg_pixmap: + portRect = polygon.boundingRect() + portPos = portRect.topLeft() + painter.drawTiledPixmap(portRect, canvas.theme.port_bg_pixmap, portPos) + else: + painter.setBrush(poly_color) #.lighter(200)) + + painter.setPen(poly_pen) + painter.drawPolygon(polygon) + else: - painter.setBrush(poly_color) + # incomplete paint + painter.setPen(poly_pen) + painter.drawPolygon(polygon) - painter.setPen(poly_pen) - painter.drawPolygon(polygon) + sub = QPolygonF() + + if self.m_port_mode == PORT_MODE_INPUT: + sub += QPointF(poly_locx[0], 0) + sub += QPointF(poly_locx[2]*self.m_port_value, 0) + sub += QPointF(poly_locx[2]*self.m_port_value, canvas.theme.port_height) + sub += QPointF(poly_locx[0], canvas.theme.port_height) + else: + sub += QPointF(poly_locx[2], 0) + sub += QPointF(poly_locx[0]*self.m_port_value, 0) + sub += QPointF(poly_locx[0]*self.m_port_value, canvas.theme.port_height) + sub += QPointF(poly_locx[2], canvas.theme.port_height) + + painter.setBrush(poly_color) + painter.setPen(poly_pen) + painter.drawPolygon(polygon.intersected(sub)) painter.setPen(text_pen) painter.setFont(self.m_port_font) diff --git a/source/utils/CarlaBackendUtils.hpp b/source/utils/CarlaBackendUtils.hpp index 651581efd..7bfba2dec 100644 --- a/source/utils/CarlaBackendUtils.hpp +++ b/source/utils/CarlaBackendUtils.hpp @@ -255,6 +255,8 @@ const char* EngineCallbackOpcode2Str(const EngineCallbackOpcode opcode) noexcept return "ENGINE_CALLBACK_PATCHBAY_PORT_REMOVED"; case ENGINE_CALLBACK_PATCHBAY_PORT_RENAMED: return "ENGINE_CALLBACK_PATCHBAY_PORT_RENAMED"; + case ENGINE_CALLBACK_PATCHBAY_PORT_VALUE_CHANGED: + return "ENGINE_CALLBACK_PATCHBAY_PORT_VALUE_CHANGED"; case ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED: return "ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED"; case ENGINE_CALLBACK_PATCHBAY_CONNECTION_REMOVED: