From f7bc330102530c446346e352fb7a3c8748857267 Mon Sep 17 00:00:00 2001 From: falkTX Date: Sun, 8 Feb 2015 03:58:53 +0000 Subject: [PATCH] Allow custom properties per plugin, use it to save is-skin-compact --- source/backend/CarlaBackend.h | 10 ++--- source/backend/engine/CarlaEngineNative.cpp | 40 +++++++++++++++++++ source/backend/plugin/CarlaPlugin.cpp | 8 +++- source/backend/plugin/CarlaPluginBridge.cpp | 3 ++ source/backend/plugin/CarlaPluginDSSI.cpp | 3 ++ .../backend/plugin/CarlaPluginFluidSynth.cpp | 3 ++ source/backend/plugin/CarlaPluginLV2.cpp | 3 ++ .../plugin/CarlaPluginLinuxSampler.cpp | 3 ++ source/backend/plugin/CarlaPluginNative.cpp | 3 ++ source/carla_backend.py | 25 +++++++++++- source/carla_host.py | 29 +++++++++++++- source/native-plugins/resources/carla-plugin | 24 +++++------ source/widgets/racklistwidget.py | 17 +++++++- 13 files changed, 146 insertions(+), 25 deletions(-) diff --git a/source/backend/CarlaBackend.h b/source/backend/CarlaBackend.h index c782a4997..e37af3607 100644 --- a/source/backend/CarlaBackend.h +++ b/source/backend/CarlaBackend.h @@ -352,6 +352,11 @@ static const char* const CUSTOM_DATA_TYPE_BOOLEAN = "http://kxstudio.sf.net/ns/c */ static const char* const CUSTOM_DATA_TYPE_CHUNK = "http://kxstudio.sf.net/ns/carla/chunk"; +/*! + * Property type URI. + */ +static const char* const CUSTOM_DATA_TYPE_PROPERTY = "http://kxstudio.sf.net/ns/carla/property"; + /*! * String type URI. */ @@ -370,11 +375,6 @@ static const char* const CUSTOM_DATA_TYPE_STRING = "http://kxstudio.sf.net/ns/ca * @{ */ -/*! - * Plugin options key. - */ -static const char* const CUSTOM_DATA_KEY_PLUGIN_OPTIONS = "CarlaPluginOptions"; - /*! * UI position key. */ diff --git a/source/backend/engine/CarlaEngineNative.cpp b/source/backend/engine/CarlaEngineNative.cpp index e7629bb18..ba12689e2 100644 --- a/source/backend/engine/CarlaEngineNative.cpp +++ b/source/backend/engine/CarlaEngineNative.cpp @@ -889,6 +889,35 @@ protected: fUiServer.flushMessages(); } + void uiServerSendPluginProperties(CarlaPlugin* const plugin) + { + const CarlaMutexLocker cml(fUiServer.getPipeLock()); + + const uint pluginId(plugin->getId()); + + uint32_t count = plugin->getCustomDataCount(); + std::sprintf(fTmpBuf, "CUSTOM_DATA_COUNT_%i:%i\n", pluginId, count); + fUiServer.writeMessage(fTmpBuf); + + for (uint32_t i=0; igetCustomData(i)); + CARLA_SAFE_ASSERT_CONTINUE(customData.isValid()); + + if (std::strcmp(customData.type, CUSTOM_DATA_TYPE_PROPERTY) != 0) + continue; + + std::sprintf(fTmpBuf, "CUSTOM_DATA_%i:%i\n", pluginId, i); + fUiServer.writeMessage(fTmpBuf); + + fUiServer.writeAndFixMessage(customData.type); + fUiServer.writeAndFixMessage(customData.key); + fUiServer.writeAndFixMessage(customData.value); + } + + fUiServer.flushMessages(); + } + void uiServerCallback(const EngineCallbackOpcode action, const uint pluginId, const int value1, const int value2, const float value3, const char* const valueStr) { if (! fIsRunning) @@ -900,6 +929,16 @@ protected: switch (action) { + case ENGINE_CALLBACK_UPDATE: + plugin = getPlugin(pluginId); + + if (plugin != nullptr && plugin->isEnabled()) + { + CARLA_SAFE_ASSERT_BREAK(plugin->getId() == pluginId); + uiServerSendPluginProperties(plugin); + } + break; + case ENGINE_CALLBACK_RELOAD_INFO: plugin = getPlugin(pluginId); @@ -940,6 +979,7 @@ protected: uiServerSendPluginInfo(plugin); uiServerSendPluginParameters(plugin); uiServerSendPluginPrograms(plugin); + uiServerSendPluginProperties(plugin); } break; diff --git a/source/backend/plugin/CarlaPlugin.cpp b/source/backend/plugin/CarlaPlugin.cpp index 5e97ab8c2..e41b3603c 100644 --- a/source/backend/plugin/CarlaPlugin.cpp +++ b/source/backend/plugin/CarlaPlugin.cpp @@ -622,6 +622,7 @@ void CarlaPlugin::loadStateSave(const CarlaStateSave& stateSave) CARLA_SAFE_ASSERT_CONTINUE(stateCustomData != nullptr); CARLA_SAFE_ASSERT_CONTINUE(stateCustomData->isValid()); + const char* const type(stateCustomData->type); const char* const key(stateCustomData->key); if (getType() == PLUGIN_DSSI && (std::strcmp(key, "reloadprograms") == 0 || std::strcmp(key, "load") == 0 || std::strncmp(key, "patches", 7) == 0)) @@ -629,7 +630,7 @@ void CarlaPlugin::loadStateSave(const CarlaStateSave& stateSave) if (usesMultiProgs && std::strcmp(key, "midiPrograms") == 0) continue; - setCustomData(stateCustomData->type, stateCustomData->key, stateCustomData->value, true); + setCustomData(type, key, stateCustomData->value, true); } // --------------------------------------------------------------- @@ -797,6 +798,7 @@ void CarlaPlugin::loadStateSave(const CarlaStateSave& stateSave) CARLA_SAFE_ASSERT_CONTINUE(stateCustomData != nullptr); CARLA_SAFE_ASSERT_CONTINUE(stateCustomData->isValid()); + const char* const type(stateCustomData->type); const char* const key(stateCustomData->key); if (getType() == PLUGIN_DSSI && (std::strcmp(key, "reloadprograms") == 0 || std::strcmp(key, "load") == 0 || std::strncmp(key, "patches", 7) == 0)) @@ -804,7 +806,7 @@ void CarlaPlugin::loadStateSave(const CarlaStateSave& stateSave) if (usesMultiProgs && std::strcmp(key, "midiPrograms") == 0) continue; - setCustomData(stateCustomData->type, stateCustomData->key, stateCustomData->value, true); + setCustomData(type, key, stateCustomData->value, true); } // --------------------------------------------------------------- @@ -845,6 +847,8 @@ void CarlaPlugin::loadStateSave(const CarlaStateSave& stateSave) setCtrlChannel(stateSave.ctrlChannel, true, true); setActive(stateSave.active, true, true); #endif + + pData->engine->callback(ENGINE_CALLBACK_UPDATE, pData->id, 0, 0, 0.0f, nullptr); } bool CarlaPlugin::saveStateToFile(const char* const filename) diff --git a/source/backend/plugin/CarlaPluginBridge.cpp b/source/backend/plugin/CarlaPluginBridge.cpp index 6c965089f..bc1d923ad 100644 --- a/source/backend/plugin/CarlaPluginBridge.cpp +++ b/source/backend/plugin/CarlaPluginBridge.cpp @@ -1080,6 +1080,9 @@ public: CARLA_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',); CARLA_SAFE_ASSERT_RETURN(value != nullptr,); + if (std::strcmp(type, CUSTOM_DATA_TYPE_PROPERTY) == 0) + return CarlaPlugin::setCustomData(type, key, value, sendGui); + if (std::strcmp(type, CUSTOM_DATA_TYPE_STRING) == 0 && std::strcmp(key, "__CarlaPingOnOff__") == 0) { const CarlaMutexLocker _cml(fShmNonRtClientControl.mutex); diff --git a/source/backend/plugin/CarlaPluginDSSI.cpp b/source/backend/plugin/CarlaPluginDSSI.cpp index 6397bcf69..789eb00eb 100644 --- a/source/backend/plugin/CarlaPluginDSSI.cpp +++ b/source/backend/plugin/CarlaPluginDSSI.cpp @@ -567,6 +567,9 @@ public: CARLA_SAFE_ASSERT_RETURN(value != nullptr,); carla_debug("CarlaPluginDSSI::setCustomData(%s, %s, %s, %s)", type, key, value, bool2str(sendGui)); + if (std::strcmp(type, CUSTOM_DATA_TYPE_PROPERTY) == 0) + return CarlaPlugin::setCustomData(type, key, value, sendGui); + if (std::strcmp(type, CUSTOM_DATA_TYPE_STRING) != 0) return carla_stderr2("CarlaPluginDSSI::setCustomData(\"%s\", \"%s\", \"%s\", %s) - type is not string", type, key, value, bool2str(sendGui)); diff --git a/source/backend/plugin/CarlaPluginFluidSynth.cpp b/source/backend/plugin/CarlaPluginFluidSynth.cpp index cecd7c262..0640355ca 100644 --- a/source/backend/plugin/CarlaPluginFluidSynth.cpp +++ b/source/backend/plugin/CarlaPluginFluidSynth.cpp @@ -462,6 +462,9 @@ public: CARLA_SAFE_ASSERT_RETURN(value != nullptr && value[0] != '\0',); carla_debug("CarlaPluginFluidSynth::setCustomData(%s, \"%s\", \"%s\", %s)", type, key, value, bool2str(sendGui)); + if (std::strcmp(type, CUSTOM_DATA_TYPE_PROPERTY) == 0) + return CarlaPlugin::setCustomData(type, key, value, sendGui); + if (std::strcmp(type, CUSTOM_DATA_TYPE_STRING) != 0) return carla_stderr2("CarlaPluginFluidSynth::setCustomData(\"%s\", \"%s\", \"%s\", %s) - type is not string", type, key, value, bool2str(sendGui)); diff --git a/source/backend/plugin/CarlaPluginLV2.cpp b/source/backend/plugin/CarlaPluginLV2.cpp index aeacb64c4..010069817 100644 --- a/source/backend/plugin/CarlaPluginLV2.cpp +++ b/source/backend/plugin/CarlaPluginLV2.cpp @@ -1135,6 +1135,9 @@ public: CARLA_SAFE_ASSERT_RETURN(value != nullptr,); carla_debug("CarlaPluginLV2::setCustomData(%s, %s, %s, %s)", type, key, value, bool2str(sendGui)); + if (std::strcmp(type, CUSTOM_DATA_TYPE_PROPERTY) == 0) + return CarlaPlugin::setCustomData(type, key, value, sendGui); + // we should only call state restore once // so inject this in CarlaPlugin::loadSaveState if (std::strcmp(type, CUSTOM_DATA_TYPE_STRING) == 0 && std::strcmp(key, "CarlaLoadLv2StateNow") == 0 && std::strcmp(value, "true") == 0) diff --git a/source/backend/plugin/CarlaPluginLinuxSampler.cpp b/source/backend/plugin/CarlaPluginLinuxSampler.cpp index 9a8e1ad82..961740429 100644 --- a/source/backend/plugin/CarlaPluginLinuxSampler.cpp +++ b/source/backend/plugin/CarlaPluginLinuxSampler.cpp @@ -429,6 +429,9 @@ public: CARLA_SAFE_ASSERT_RETURN(value != nullptr && value[0] != '\0',); carla_debug("CarlaPluginLinuxSampler::setCustomData(%s, \"%s\", \"%s\", %s)", type, key, value, bool2str(sendGui)); + if (std::strcmp(type, CUSTOM_DATA_TYPE_PROPERTY) == 0) + return CarlaPlugin::setCustomData(type, key, value, sendGui); + if (std::strcmp(type, CUSTOM_DATA_TYPE_STRING) != 0) return carla_stderr2("CarlaPluginLinuxSampler::setCustomData(\"%s\", \"%s\", \"%s\", %s) - type is not string", type, key, value, bool2str(sendGui)); diff --git a/source/backend/plugin/CarlaPluginNative.cpp b/source/backend/plugin/CarlaPluginNative.cpp index 5651ce48f..317f76bff 100644 --- a/source/backend/plugin/CarlaPluginNative.cpp +++ b/source/backend/plugin/CarlaPluginNative.cpp @@ -607,6 +607,9 @@ public: CARLA_SAFE_ASSERT_RETURN(value != nullptr,); carla_debug("CarlaPluginNative::setCustomData(%s, %s, %s, %s)", type, key, value, bool2str(sendGui)); + if (std::strcmp(type, CUSTOM_DATA_TYPE_PROPERTY) == 0) + return CarlaPlugin::setCustomData(type, key, value, sendGui); + if (std::strcmp(type, CUSTOM_DATA_TYPE_STRING) != 0 && std::strcmp(type, CUSTOM_DATA_TYPE_CHUNK) != 0) return carla_stderr2("CarlaPluginNative::setCustomData(\"%s\", \"%s\", \"%s\", %s) - type is invalid", type, key, value, bool2str(sendGui)); diff --git a/source/carla_backend.py b/source/carla_backend.py index 24d9ea1ae..777291b6c 100644 --- a/source/carla_backend.py +++ b/source/carla_backend.py @@ -312,6 +312,9 @@ CUSTOM_DATA_TYPE_BOOLEAN = "http://kxstudio.sf.net/ns/carla/boolean" # Chunk type URI. CUSTOM_DATA_TYPE_CHUNK = "http://kxstudio.sf.net/ns/carla/chunk" +# Property type URI. +CUSTOM_DATA_TYPE_PROPERTY = "http://kxstudio.sf.net/ns/carla/property" + # String type URI. CUSTOM_DATA_TYPE_STRING = "http://kxstudio.sf.net/ns/carla/string" @@ -2641,6 +2644,8 @@ class PluginStoreInfo(object): 'midiProgramCount', 'midiProgramCurrent', 'midiProgramData', + 'customDataCount', + 'customData', 'peaks' ] @@ -2814,7 +2819,7 @@ class CarlaHostPlugin(CarlaHostMeta): return self.fPluginsInfo[pluginId].midiProgramData[midiProgramId] def get_custom_data(self, pluginId, customDataId): - return PyCustomData + return self.fPluginsInfo[pluginId].customData[customDataId] def get_chunk_data(self, pluginId): return "" @@ -2829,7 +2834,7 @@ class CarlaHostPlugin(CarlaHostMeta): return self.fPluginsInfo[pluginId].midiProgramCount def get_custom_data_count(self, pluginId): - return 0 + return self.fPluginsInfo[pluginId].customDataCount def get_parameter_text(self, pluginId, parameterId): return "" @@ -2978,6 +2983,8 @@ class CarlaHostPlugin(CarlaHostMeta): info.midiProgramCount = 0 info.midiProgramCurrent = -1 info.midiProgramData = [] + info.customDataCount = 0 + info.customData = [] info.peaks = [0.0, 0.0, 0.0, 0.0] self.fPluginsInfo.append(info) @@ -3037,6 +3044,16 @@ class CarlaHostPlugin(CarlaHostMeta): for x in range(count): self.fPluginsInfo[pluginId].midiProgramData.append(PyMidiProgramData) + def _set_customDataCount(self, pluginId, count): + self.fPluginsInfo[pluginId].customDataCount = count + + # clear + self.fPluginsInfo[pluginId].customData = [] + + # add placeholders + for x in range(count): + self.fPluginsInfo[pluginId].customData.append(PyCustomData) + def _set_parameterInfo(self, pluginId, paramIndex, info): if pluginId < len(self.fPluginsInfo) and paramIndex < self.fPluginsInfo[pluginId].parameterCount: self.fPluginsInfo[pluginId].parameterInfo[paramIndex] = info @@ -3079,6 +3096,10 @@ class CarlaHostPlugin(CarlaHostMeta): if mpIndex < self.fPluginsInfo[pluginId].midiProgramCount: self.fPluginsInfo[pluginId].midiProgramData[mpIndex] = data + def _set_customData(self, pluginId, cdIndex, data): + if cdIndex < self.fPluginsInfo[pluginId].customDataCount: + self.fPluginsInfo[pluginId].customData[cdIndex] = data + def _set_peaks(self, pluginId, in1, in2, out1, out2): self.fPluginsInfo[pluginId].peaks = [in1, in2, out1, out2] diff --git a/source/carla_host.py b/source/carla_host.py index b2cc0a57e..b2ec09432 100644 --- a/source/carla_host.py +++ b/source/carla_host.py @@ -386,6 +386,8 @@ class HostWindow(QMainWindow): host.NoteOnCallback.connect(self.slot_handleNoteOnCallback) host.NoteOffCallback.connect(self.slot_handleNoteOffCallback) + host.UpdateCallback.connect(self.slot_handleUpdateCallback) + host.PatchbayClientAddedCallback.connect(self.slot_handlePatchbayClientAddedCallback) host.PatchbayClientRemovedCallback.connect(self.slot_handlePatchbayClientRemovedCallback) host.PatchbayClientRenamedCallback.connect(self.slot_handlePatchbayClientRenamedCallback) @@ -1495,6 +1497,32 @@ class HostWindow(QMainWindow): if pluginId in self.fSelectedPlugins: self.ui.keyboard.sendNoteOff(note, False) + # -------------------------------------------------------------------------------------------------------- + + @pyqtSlot(int) + def slot_handleUpdateCallback(self, pluginId): + pitem = self.getPluginItem(pluginId) + + if pitem is None: + return + + wasCompacted = pitem.isCompacted() + isCompacted = wasCompacted + + for i in range(self.host.get_custom_data_count(pluginId)): + cdata = self.host.get_custom_data(pluginId, i) + + if cdata['type'] == CUSTOM_DATA_TYPE_PROPERTY and cdata['key'] == "CarlaSkinIsCompacted": + isCompacted = bool(cdata['value'] == "true") + break + else: + return + + if wasCompacted == isCompacted: + return + + pitem.recreateWidget(True) + # -------------------------------------------------------------------------------------------------------- # MiniCanvas stuff @@ -1581,7 +1609,6 @@ class HostWindow(QMainWindow): if pitem is None: return - self.ui.listWidget.customClearSelection() pitem.recreateWidget() # -------------------------------------------------------------------------------------------------------- diff --git a/source/native-plugins/resources/carla-plugin b/source/native-plugins/resources/carla-plugin index be4f5bbb9..132b7ff78 100755 --- a/source/native-plugins/resources/carla-plugin +++ b/source/native-plugins/resources/carla-plugin @@ -312,19 +312,17 @@ class CarlaMiniW(ExternalUI, HostWindow): name = self.readlineblock().replace("\r", "\n") self.host._set_midiProgramData(pluginId, midiProgId, {'bank': bank, 'program': program, 'name': name}) - elif msg == "complete-license": - license = self.readlineblock().replace("\r", "\n") - self.host.fCompleteLicenseText = license - - elif msg == "juce-version": - version = self.readlineblock().replace("\r", "\n") - self.host.fJuceVersion = version - - elif msg == "file-exts": - exts = self.readlineblock().replace("\r", "\n") - self.host.fSupportedFileExts = exts - # only now we know the supported extensions - self.fDirModel.setNameFilters(exts.split(";")) + elif msg.startswith("CUSTOM_DATA_COUNT_"): + pluginId, count = [int(i) for i in msg.replace("CUSTOM_DATA_COUNT_", "").split(":")] + self.host._set_customDataCount(pluginId, count) + + elif msg.startswith("CUSTOM_DATA_"): + pluginId, customDataId = [int(i) for i in msg.replace("CUSTOM_DATA_", "").split(":")] + + type_ = self.readlineblock().replace("\r", "\n") + key = self.readlineblock().replace("\r", "\n") + value = self.readlineblock().replace("\r", "\n") + self.host._set_customData(pluginId, customDataId, {'type': type_, 'key': key, 'value': value}) elif msg == "max-plugin-number": maxnum = int(self.readlineblock()) diff --git a/source/widgets/racklistwidget.py b/source/widgets/racklistwidget.py index 57df287e8..b6dbb28ea 100644 --- a/source/widgets/racklistwidget.py +++ b/source/widgets/racklistwidget.py @@ -67,13 +67,19 @@ class RackListItem(QListWidgetItem): 'useSkins': useSkins } + for i in range(self.host.get_custom_data_count(pluginId)): + cdata = self.host.get_custom_data(pluginId, i) + if cdata['type'] == CUSTOM_DATA_TYPE_PROPERTY and cdata['key'] == "CarlaSkinIsCompacted": + self.fOptions['compact'] = bool(cdata['value'] == "true") + break + self.setFlags(Qt.ItemIsSelectable|Qt.ItemIsEnabled) #self.setFlags(Qt.ItemIsSelectable|Qt.ItemIsEnabled|Qt.ItemIsDragEnabled) # ---------------------------------------------------------------------------------------------------- # Set-up GUI - self.recreateWidget() + self.recreateWidget(firstInit = True) # -------------------------------------------------------------------------------------------------------- @@ -97,6 +103,9 @@ class RackListItem(QListWidgetItem): widget.deleteLater() del widget + def isCompacted(self): + return self.fOptions['compact'] + def getEditDialog(self): if self.fWidget is None: return None @@ -125,7 +134,7 @@ class RackListItem(QListWidgetItem): # -------------------------------------------------------------------------------------------------------- - def recreateWidget(self, invertCompactOption = False): + def recreateWidget(self, invertCompactOption = False, firstInit = False): if invertCompactOption: self.fOptions['compact'] = not self.fOptions['compact'] @@ -138,6 +147,10 @@ class RackListItem(QListWidgetItem): self.fParent.setItemWidget(self, self.fWidget) + if not firstInit: + self.host.set_custom_data(self.fPluginId, CUSTOM_DATA_TYPE_PROPERTY, + "CarlaSkinIsCompacted", "true" if self.fOptions['compact'] else "false") + # ------------------------------------------------------------------------------------------------------------ # Rack Widget