| @@ -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; | |||
| @@ -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. | |||
| @@ -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. | |||
| @@ -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 | |||
| @@ -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<uint>(groupId), icon, pluginId, 0.0f, groupName); | |||
| #if 0 | |||
| if (pluginId >= 0) | |||
| { | |||
| CarlaPlugin* const plugin(getPlugin(static_cast<uint32_t>(pluginId))); | |||
| @@ -1970,10 +1969,15 @@ private: | |||
| plugin->getParameterName(j, strBuf); | |||
| callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, static_cast<uint>(groupId), static_cast<int>(j)-1, static_cast<int>(canvasPortFlags), 0.0f, strBuf); | |||
| const int pluginPortId = -static_cast<int>(j)-1; | |||
| const float pluginValue = plugin->getParameterRanges(j).getNormalizedValue(plugin->getParameterValue(j)); | |||
| callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, static_cast<uint>(groupId), pluginPortId, static_cast<int>(canvasPortFlags), 0.0f, strBuf); | |||
| callback(ENGINE_CALLBACK_PATCHBAY_PORT_VALUE_CHANGED, static_cast<uint>(groupId), pluginPortId, 0, pluginValue, nullptr); | |||
| } | |||
| } | |||
| } | |||
| #endif | |||
| } | |||
| bool portIsInput = (jackPortFlags & JackPortIsInput); | |||
| @@ -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) | |||
| { | |||
| @@ -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"; | |||
| @@ -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() | |||
| # ----------------------------------------------------------------- | |||
| @@ -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): | |||
| @@ -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] | |||
| @@ -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) | |||
| @@ -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: | |||
| @@ -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) | |||
| @@ -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: | |||