| @@ -427,6 +427,16 @@ public: | |||
| */ | |||
| void loadSaveState(const SaveState& saveState); | |||
| /*! | |||
| * TODO | |||
| */ | |||
| bool saveStateToFile(const char* const filename); | |||
| /*! | |||
| * TODO | |||
| */ | |||
| bool loadStateFromFile(const char* const filename); | |||
| // ------------------------------------------------------------------- | |||
| // Set data (internal stuff) | |||
| @@ -178,8 +178,8 @@ CARLA_EXPORT bool carla_add_plugin(CarlaBinaryType btype, CarlaPluginType ptype, | |||
| CARLA_EXPORT bool carla_remove_plugin(unsigned int pluginId); | |||
| CARLA_EXPORT void carla_remove_all_plugins(); | |||
| //CARLA_EXPORT bool carla_load_plugin_state(unsigned int pluginId, const char* filename); | |||
| //CARLA_EXPORT bool carla_save_plugin_state(unsigned int pluginId, const char* filename); | |||
| CARLA_EXPORT bool carla_load_plugin_state(unsigned int pluginId, const char* filename); | |||
| CARLA_EXPORT bool carla_save_plugin_state(unsigned int pluginId, const char* filename); | |||
| CARLA_EXPORT const CarlaPluginInfo* carla_get_plugin_info(unsigned int pluginId); | |||
| CARLA_EXPORT const CarlaPortCountInfo* carla_get_audio_port_count_info(unsigned int pluginId); | |||
| @@ -17,6 +17,7 @@ | |||
| #include "CarlaEngineInternal.hpp" | |||
| #include "CarlaBackendUtils.hpp" | |||
| #include "CarlaStateUtils.hpp" | |||
| #include "CarlaMIDI.h" | |||
| #include <QtCore/QFile> | |||
| @@ -966,29 +967,66 @@ void CarlaEngine::__bridgePluginRegister(const unsigned short id, CarlaPlugin* c | |||
| bool CarlaEngine::loadProject(const char* const filename) | |||
| { | |||
| carla_debug("CarlaEngine::loadProject(\"%s\")", filename); | |||
| CARLA_ASSERT(filename != nullptr); | |||
| //QFile file(filename); | |||
| QFile file(filename); | |||
| if (! file.open(QIODevice::ReadOnly | QIODevice::Text)) | |||
| return false; | |||
| QDomDocument xml; | |||
| xml.setContent(file.readAll()); | |||
| file.close(); | |||
| QDomNode xmlNode(xml.documentElement()); | |||
| if (xmlNode.toElement().tagName() != "CARLA-PROJECT") | |||
| { | |||
| carla_stderr2("Not a valid Carla project file"); | |||
| return false; | |||
| } | |||
| std::vector<SaveState> saveStates; | |||
| { | |||
| QDomNode node(xmlNode.firstChild()); | |||
| while (! node.isNull()) | |||
| { | |||
| if (node.toElement().tagName() == "Plugin") | |||
| { | |||
| const SaveState& saveState = getSaveStateDictFromXML(node); | |||
| saveStates.push_back(saveState); | |||
| } | |||
| node = node.nextSibling(); | |||
| } | |||
| } | |||
| //if (! file.open(QIODevice::WriteOnly | QIODevice::Text)) | |||
| // return; | |||
| // TODO - add plugins as set in XML | |||
| // TODO - clear+free states | |||
| //getSaveStateDictFromXML | |||
| return true; | |||
| } | |||
| bool CarlaEngine::saveProject(const char* const filename) | |||
| { | |||
| carla_debug("CarlaEngine::saveProject(\"%s\")", filename); | |||
| CARLA_ASSERT(filename != nullptr); | |||
| #if 0 | |||
| QFile file(filename); | |||
| file.open(QIODevice::WriteOnly | QIODevice::Text); | |||
| if (! file.open(QIODevice::WriteOnly | QIODevice::Text)) | |||
| return false; | |||
| QTextStream out(&file); | |||
| out << "<?xml version='1.0' encoding='UTF-8'?>\n"; | |||
| out << "<!DOCTYPE CARLA-PRESET>\n"; | |||
| out << "<CARLA-PRESET VERSION='0.5.0'>\n"; | |||
| out << "<!DOCTYPE CARLA-PROJECT>\n"; | |||
| out << "<CARLA-PROJECT VERSION='1.0'>\n"; | |||
| bool firstPlugin = true; | |||
| char strBuf[STR_MAX]; | |||
| for (unsigned int i=0; i < kData->curPluginCount; i++) | |||
| { | |||
| @@ -996,16 +1034,25 @@ bool CarlaEngine::saveProject(const char* const filename) | |||
| if (plugin != nullptr && plugin->enabled()) | |||
| { | |||
| const SaveState& saveState = plugin->getSaveState(); | |||
| // TODO | |||
| if (! firstPlugin) | |||
| out << "\n"; | |||
| plugin->getRealName(strBuf); | |||
| if (*strBuf != 0) | |||
| out << QString(" <!-- %1 -->\n").arg(xmlSafeString(strBuf, true)); | |||
| out << " <Plugin>\n"; | |||
| out << getXMLFromSaveState(plugin->getSaveState()); | |||
| out << " </Plugin>\n"; | |||
| firstPlugin = false; | |||
| } | |||
| } | |||
| out << "</CARLA-PRESET>\n"; | |||
| out << "</CARLA-PROJECT>\n"; | |||
| file.close(); | |||
| #endif | |||
| return true; | |||
| } | |||
| @@ -19,6 +19,9 @@ | |||
| #include "CarlaLibUtils.hpp" | |||
| #include "CarlaMIDI.h" | |||
| #include <QtCore/QFile> | |||
| #include <QtCore/QTextStream> | |||
| //#include <QtGui/QtEvents> | |||
| // TODO - save&load options | |||
| @@ -477,22 +480,22 @@ const SaveState& CarlaPlugin::getSaveState() | |||
| if (paramData.type != PARAMETER_INPUT) | |||
| continue; | |||
| StateParameter stateParameter; | |||
| StateParameter* stateParameter(new StateParameter); | |||
| stateParameter.index = paramData.index; | |||
| stateParameter.midiCC = paramData.midiCC; | |||
| stateParameter.midiChannel = paramData.midiChannel + 1; | |||
| stateParameter->index = paramData.index; | |||
| stateParameter->midiCC = paramData.midiCC; | |||
| stateParameter->midiChannel = paramData.midiChannel + 1; | |||
| getParameterName(i, strBuf); | |||
| stateParameter.name = carla_strdup(strBuf); | |||
| stateParameter->name = carla_strdup(strBuf); | |||
| getParameterSymbol(i, strBuf); | |||
| stateParameter.symbol = carla_strdup(strBuf);; | |||
| stateParameter->symbol = carla_strdup(strBuf);; | |||
| stateParameter.value = getParameterValue(i); | |||
| stateParameter->value = getParameterValue(i); | |||
| if (paramData.hints & PARAMETER_USES_SAMPLERATE) | |||
| stateParameter.value /= sampleRate; | |||
| stateParameter->value /= sampleRate; | |||
| saveState.parameters.push_back(stateParameter); | |||
| } | |||
| @@ -507,11 +510,11 @@ const SaveState& CarlaPlugin::getSaveState() | |||
| if (cData.type == nullptr) | |||
| continue; | |||
| StateCustomData stateCustomData; | |||
| StateCustomData* stateCustomData(new StateCustomData); | |||
| stateCustomData.type = carla_strdup(cData.type); | |||
| stateCustomData.key = carla_strdup(cData.key); | |||
| stateCustomData.value = carla_strdup(cData.value); | |||
| stateCustomData->type = carla_strdup(cData.type); | |||
| stateCustomData->key = carla_strdup(cData.key); | |||
| stateCustomData->value = carla_strdup(cData.value); | |||
| saveState.customData.push_back(stateCustomData); | |||
| } | |||
| @@ -542,6 +545,53 @@ void CarlaPlugin::loadSaveState(const SaveState& saveState) | |||
| Q_UNUSED(saveState); | |||
| } | |||
| bool CarlaPlugin::saveStateToFile(const char* const filename) | |||
| { | |||
| carla_debug("CarlaPlugin::saveStateToFile(\"%s\")", filename); | |||
| CARLA_ASSERT(filename != nullptr); | |||
| QFile file(filename); | |||
| if (! file.open(QIODevice::WriteOnly | QIODevice::Text)) | |||
| return false; | |||
| QTextStream out(&file); | |||
| out << "<?xml version='1.0' encoding='UTF-8'?>\n"; | |||
| out << "<!DOCTYPE CARLA-PRESET>\n"; | |||
| out << "<CARLA-PRESET VERSION='1.0'>\n"; | |||
| out << getXMLFromSaveState(getSaveState()); | |||
| out << "</CARLA-PRESET>\n"; | |||
| file.close(); | |||
| return true; | |||
| } | |||
| bool CarlaPlugin::loadStateFromFile(const char* const filename) | |||
| { | |||
| carla_debug("CarlaPlugin::loadStateFromFile(\"%s\")", filename); | |||
| CARLA_ASSERT(filename != nullptr); | |||
| QFile file(filename); | |||
| if (! file.open(QIODevice::ReadOnly | QIODevice::Text)) | |||
| return false; | |||
| QDomDocument xml; | |||
| xml.setContent(file.readAll()); | |||
| file.close(); | |||
| QDomNode xmlNode(xml.documentElement()); | |||
| if (xmlNode.toElement().tagName() != "CARLA-PRESET") | |||
| { | |||
| carla_stderr2("Not a valid Carla preset file"); | |||
| return false; | |||
| } | |||
| loadSaveState(getSaveStateDictFromXML(xmlNode)); | |||
| return true; | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| // Set data (internal stuff) | |||
| @@ -541,6 +541,36 @@ void carla_remove_all_plugins() | |||
| standalone.engine->removeAllPlugins(); | |||
| } | |||
| bool carla_load_plugin_state(unsigned int pluginId, const char* filename) | |||
| { | |||
| carla_debug("carla_load_plugin_state(%i, \"%s\")", pluginId, filename); | |||
| CARLA_ASSERT(standalone.engine != nullptr); | |||
| if (standalone.engine == nullptr) | |||
| return false; | |||
| if (CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId)) | |||
| return plugin->loadStateFromFile(filename); | |||
| carla_stderr2("carla_load_plugin_state(%i, \"%s\") - could not find plugin", pluginId, filename); | |||
| return false; | |||
| } | |||
| bool carla_save_plugin_state(unsigned int pluginId, const char* filename) | |||
| { | |||
| carla_debug("carla_save_plugin_state(%i, \"%s\")", pluginId, filename); | |||
| CARLA_ASSERT(standalone.engine != nullptr); | |||
| if (standalone.engine == nullptr) | |||
| return false; | |||
| if (CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId)) | |||
| return plugin->saveStateToFile(filename); | |||
| carla_stderr2("carla_save_plugin_state(%i, \"%s\") - could not find plugin", pluginId, filename); | |||
| return false; | |||
| } | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| const CarlaPluginInfo* carla_get_plugin_info(unsigned int pluginId) | |||
| @@ -9,7 +9,7 @@ include ../Makefile.mk | |||
| # -------------------------------------------------------------- | |||
| # Common | |||
| LINK_FLAGS += $(shell pkg-config --libs liblo QtCore QtGui) | |||
| LINK_FLAGS += $(shell pkg-config --libs liblo QtCore QtGui QtXml) | |||
| # -------------------------------------------------------------- | |||
| # Engine | |||
| @@ -209,6 +209,12 @@ class Host(object): | |||
| self.lib.carla_remove_all_plugins.argtypes = None | |||
| self.lib.carla_remove_all_plugins.restype = None | |||
| self.lib.carla_load_plugin_state.argtypes = [c_uint, c_char_p] | |||
| self.lib.carla_load_plugin_state.restype = c_bool | |||
| self.lib.carla_save_plugin_state.argtypes = [c_uint, c_char_p] | |||
| self.lib.carla_save_plugin_state.restype = c_bool | |||
| self.lib.carla_get_plugin_info.argtypes = [c_uint] | |||
| self.lib.carla_get_plugin_info.restype = POINTER(CarlaPluginInfo) | |||
| @@ -423,6 +429,12 @@ class Host(object): | |||
| def remove_all_plugins(self): | |||
| self.lib.carla_remove_all_plugins() | |||
| def load_plugin_state(self, pluginId, filename): | |||
| return self.lib.carla_load_plugin_state(pluginId, filename.encode("utf-8")) | |||
| def save_plugin_state(self, pluginId, filename): | |||
| return self.lib.carla_save_plugin_state(pluginId, filename.encode("utf-8")) | |||
| def get_plugin_info(self, pluginId): | |||
| return structToDict(self.lib.carla_get_plugin_info(pluginId).contents) | |||
| @@ -1930,7 +1930,7 @@ class PluginEdit(QDialog): | |||
| askTry = QMessageBox.question(self, self.tr("Overwrite?"), self.tr("Overwrite previously created file?"), QMessageBox.Ok|QMessageBox.Cancel) | |||
| if askTry == QMessageBox.Ok: | |||
| return #self.saveState() | |||
| Carla.host.save_plugin_state(self.fPluginId, self.fCurrentStateFilename) | |||
| self.fCurrentStateFilename = None | |||
| @@ -1942,7 +1942,7 @@ class PluginEdit(QDialog): | |||
| filenameTry += ".carxs" | |||
| self.fCurrentStateFilename = filenameTry | |||
| #self.saveState() | |||
| Carla.host.save_plugin_state(self.fPluginId, self.fCurrentStateFilename) | |||
| @pyqtSlot() | |||
| def slot_loadState(self): | |||
| @@ -1951,7 +1951,7 @@ class PluginEdit(QDialog): | |||
| if filenameTry: | |||
| self.fCurrentStateFilename = filenameTry | |||
| #self.loadState() | |||
| Carla.host.load_plugin_state(self.fPluginId, self.fCurrentStateFilename) | |||
| @pyqtSlot(bool) | |||
| def slot_optionChanged(self, clicked): | |||
| @@ -366,9 +366,9 @@ void* getPointerFromAddress(uintptr_t& addr) | |||
| // ------------------------------------------------- | |||
| static inline | |||
| const char* getPluginTypeString(const PluginType& type) | |||
| const char* getPluginTypeAsString(const PluginType& type) | |||
| { | |||
| carla_debug("CarlaBackend::getPluginTypeString(%s)", PluginType2Str(type)); | |||
| carla_debug("CarlaBackend::getPluginTypeAsString(%s)", PluginType2Str(type)); | |||
| switch (type) | |||
| { | |||
| @@ -392,10 +392,44 @@ const char* getPluginTypeString(const PluginType& type) | |||
| return "SFZ"; | |||
| } | |||
| carla_stderr("CarlaBackend::getPluginTypeString(%i) - invalid type", type); | |||
| carla_stderr("CarlaBackend::getPluginTypeAsString(%i) - invalid type", type); | |||
| return "NONE"; | |||
| } | |||
| static inline | |||
| PluginType getPluginTypeFromString(const char* const stype) | |||
| { | |||
| carla_debug("CarlaBackend::getPluginTypeFromString(%s)", stype); | |||
| if (stype == nullptr) | |||
| { | |||
| carla_stderr("CarlaBackend::getPluginTypeFromString() - null string type"); | |||
| return PLUGIN_NONE; | |||
| } | |||
| if (std::strcmp(stype, "NONE") == 0) | |||
| return PLUGIN_NONE; | |||
| if (std::strcmp(stype, "INTERNAL") == 0 || std::strcmp(stype, "Internal") == 0) | |||
| return PLUGIN_INTERNAL; | |||
| if (std::strcmp(stype, "LADSPA") == 0) | |||
| return PLUGIN_LADSPA; | |||
| if (std::strcmp(stype, "DSSI") == 0) | |||
| return PLUGIN_DSSI; | |||
| if (std::strcmp(stype, "LV2") == 0) | |||
| return PLUGIN_LV2; | |||
| if (std::strcmp(stype, "VST") == 0) | |||
| return PLUGIN_VST; | |||
| if (std::strcmp(stype, "GIG") == 0) | |||
| return PLUGIN_GIG; | |||
| if (std::strcmp(stype, "SF2") == 0) | |||
| return PLUGIN_SF2; | |||
| if (std::strcmp(stype, "SFZ") == 0) | |||
| return PLUGIN_SFZ; | |||
| carla_stderr("CarlaBackend::getPluginTypeFromString(%s) - invalid string type", stype); | |||
| return PLUGIN_NONE; | |||
| } | |||
| // ------------------------------------------------- | |||
| static inline | |||
| @@ -18,8 +18,7 @@ | |||
| #ifndef __CARLA_STATE_UTILS_HPP__ | |||
| #define __CARLA_STATE_UTILS_HPP__ | |||
| #include "CarlaBackend.hpp" | |||
| #include "CarlaUtils.hpp" | |||
| #include "CarlaBackendUtils.hpp" | |||
| #include <QtXml/QDomNode> | |||
| #include <vector> | |||
| @@ -27,7 +26,6 @@ | |||
| CARLA_BACKEND_START_NAMESPACE | |||
| // ------------------------------------------------- | |||
| // Carla GUI stuff | |||
| struct StateParameter { | |||
| uint32_t index; | |||
| @@ -75,8 +73,8 @@ struct StateCustomData { | |||
| } | |||
| }; | |||
| typedef std::vector<StateParameter> StateParameterVector; | |||
| typedef std::vector<StateCustomData> StateCustomDataVector; | |||
| typedef std::vector<StateParameter*> StateParameterVector; | |||
| typedef std::vector<StateCustomData*> StateCustomDataVector; | |||
| struct SaveState { | |||
| const char* type; | |||
| @@ -173,13 +171,24 @@ struct SaveState { | |||
| currentMidiBank = -1; | |||
| currentMidiProgram = -1; | |||
| for (auto it = parameters.begin(); it != parameters.end(); ++it) | |||
| { | |||
| StateParameter* stateParameter = *it; | |||
| delete stateParameter; | |||
| } | |||
| for (auto it = customData.begin(); it != customData.end(); ++it) | |||
| { | |||
| StateCustomData* stateCustomData = *it; | |||
| delete stateCustomData; | |||
| } | |||
| parameters.clear(); | |||
| customData.clear(); | |||
| } | |||
| }; | |||
| // ------------------------------------------------- | |||
| // Carla XML helpers (xml to state) | |||
| static inline | |||
| QString xmlSafeString(const QString& string, const bool toXml) | |||
| @@ -198,6 +207,8 @@ const char* xmlSafeStringChar(const QString& string, const bool toXml) | |||
| return carla_strdup(xmlSafeString(string, toXml).toUtf8().constData()); | |||
| } | |||
| // ------------------------------------------------- | |||
| static inline | |||
| const SaveState& getSaveStateDictFromXML(const QDomNode& xmlNode) | |||
| { | |||
| @@ -261,27 +272,33 @@ const SaveState& getSaveStateDictFromXML(const QDomNode& xmlNode) | |||
| else if (tag == "DryWet") | |||
| { | |||
| bool ok; | |||
| double value = text.toDouble(&ok); | |||
| float value = text.toFloat(&ok); | |||
| if (ok) saveState.dryWet = value; | |||
| } | |||
| else if (tag == "Volume") | |||
| { | |||
| bool ok; | |||
| double value = text.toDouble(&ok); | |||
| float value = text.toFloat(&ok); | |||
| if (ok) saveState.volume = value; | |||
| } | |||
| else if (tag == "Balance-Left") | |||
| { | |||
| bool ok; | |||
| double value = text.toDouble(&ok); | |||
| float value = text.toFloat(&ok); | |||
| if (ok) saveState.balanceLeft = value; | |||
| } | |||
| else if (tag == "Balance-Right") | |||
| { | |||
| bool ok; | |||
| double value = text.toDouble(&ok); | |||
| float value = text.toFloat(&ok); | |||
| if (ok) saveState.balanceRight = value; | |||
| } | |||
| else if (tag == "Panning") | |||
| { | |||
| bool ok; | |||
| float value = text.toFloat(&ok); | |||
| if (ok) saveState.panning = value; | |||
| } | |||
| // ---------------------------------------------- | |||
| // Program (current) | |||
| @@ -318,7 +335,7 @@ const SaveState& getSaveStateDictFromXML(const QDomNode& xmlNode) | |||
| else if (tag == "Parameter") | |||
| { | |||
| StateParameter stateParameter; | |||
| StateParameter* stateParameter(new StateParameter); | |||
| QDomNode xmlSubData(xmlData.toElement().firstChild()); | |||
| @@ -327,39 +344,39 @@ const SaveState& getSaveStateDictFromXML(const QDomNode& xmlNode) | |||
| const QString pTag = xmlSubData.toElement().tagName(); | |||
| const QString pText = xmlSubData.toElement().text(); //.strip(); | |||
| if (pTag == "index") | |||
| if (pTag == "Index") | |||
| { | |||
| bool ok; | |||
| uint index = pText.toUInt(&ok); | |||
| if (ok) stateParameter.index = index; | |||
| if (ok) stateParameter->index = index; | |||
| } | |||
| else if (pTag == "name") | |||
| else if (pTag == "Name") | |||
| { | |||
| stateParameter.name = xmlSafeStringChar(pText, false); | |||
| stateParameter->name = xmlSafeStringChar(pText, false); | |||
| } | |||
| else if (pTag == "symbol") | |||
| else if (pTag == "Symbol") | |||
| { | |||
| stateParameter.symbol = xmlSafeStringChar(pText, false); | |||
| stateParameter->symbol = xmlSafeStringChar(pText, false); | |||
| } | |||
| else if (pTag == "value") | |||
| else if (pTag == "Value") | |||
| { | |||
| bool ok; | |||
| double value = pText.toDouble(&ok); | |||
| if (ok) stateParameter.value = value; | |||
| float value = text.toFloat(&ok); | |||
| if (ok) stateParameter->value = value; | |||
| } | |||
| else if (pTag == "midiChannel") | |||
| else if (pTag == "MidiChannel") | |||
| { | |||
| bool ok; | |||
| uint channel = pText.toUInt(&ok); | |||
| if (ok && channel < 16) | |||
| stateParameter.midiChannel = static_cast<uint8_t>(channel); | |||
| stateParameter->midiChannel = static_cast<uint8_t>(channel); | |||
| } | |||
| else if (pTag == "midiCC") | |||
| else if (pTag == "MidiCC") | |||
| { | |||
| bool ok; | |||
| int cc = pText.toInt(&ok); | |||
| if (ok && cc < INT16_MAX) | |||
| stateParameter.midiCC = static_cast<int16_t>(cc); | |||
| stateParameter->midiCC = static_cast<int16_t>(cc); | |||
| } | |||
| xmlSubData = xmlSubData.nextSibling(); | |||
| @@ -373,7 +390,7 @@ const SaveState& getSaveStateDictFromXML(const QDomNode& xmlNode) | |||
| else if (tag == "CustomData") | |||
| { | |||
| StateCustomData stateCustomData; | |||
| StateCustomData* stateCustomData(new StateCustomData); | |||
| QDomNode xmlSubData(xmlData.toElement().firstChild()); | |||
| @@ -382,12 +399,12 @@ const SaveState& getSaveStateDictFromXML(const QDomNode& xmlNode) | |||
| const QString cTag = xmlSubData.toElement().tagName(); | |||
| const QString cText = xmlSubData.toElement().text(); //.strip(); | |||
| if (cTag == "type") | |||
| stateCustomData.type = xmlSafeStringChar(cText, false); | |||
| else if (cTag == "key") | |||
| stateCustomData.key = xmlSafeStringChar(cText, false); | |||
| else if (cTag == "value") | |||
| stateCustomData.value = xmlSafeStringChar(cText, false); | |||
| if (cTag == "Type") | |||
| stateCustomData->type = xmlSafeStringChar(cText, false); | |||
| else if (cTag == "Key") | |||
| stateCustomData->key = xmlSafeStringChar(cText, false); | |||
| else if (cTag == "Value") | |||
| stateCustomData->value = xmlSafeStringChar(cText, false); | |||
| xmlSubData = xmlSubData.nextSibling(); | |||
| } | |||
| @@ -417,17 +434,151 @@ const SaveState& getSaveStateDictFromXML(const QDomNode& xmlNode) | |||
| return saveState; | |||
| } | |||
| // ------------------------------------------------- | |||
| static inline | |||
| QString getXMLFromSaveState(const SaveState& saveState) | |||
| { | |||
| return ""; | |||
| QString content; | |||
| // TODO | |||
| (void)saveState; | |||
| } | |||
| { | |||
| QString info(" <Info>\n"); | |||
| // ------------------------------------------------- | |||
| // Carla XML helpers (state to xml) | |||
| info += QString(" <Type>%1</Type>\n").arg(saveState.type); | |||
| info += QString(" <Name>%1</Name>\n").arg(xmlSafeString(saveState.name, true)); | |||
| switch (getPluginTypeFromString(saveState.type)) | |||
| { | |||
| case PLUGIN_NONE: | |||
| break; | |||
| case PLUGIN_INTERNAL: | |||
| info += QString(" <Label>%1</Label>\n").arg(xmlSafeString(saveState.label, true)); | |||
| break; | |||
| case PLUGIN_LADSPA: | |||
| info += QString(" <Binary>%1</Binary>\n").arg(xmlSafeString(saveState.binary, true)); | |||
| info += QString(" <Label>%1</Label>\n").arg(xmlSafeString(saveState.label, true)); | |||
| info += QString(" <UniqueID>%1</UniqueID>\n").arg(saveState.uniqueID); | |||
| break; | |||
| case PLUGIN_DSSI: | |||
| info += QString(" <Binary>%1</Binary>\n").arg(xmlSafeString(saveState.binary, true)); | |||
| info += QString(" <Label>%1</Label>\n").arg(xmlSafeString(saveState.label, true)); | |||
| break; | |||
| case PLUGIN_LV2: | |||
| info += QString(" <URI>%1</URI>\n").arg(xmlSafeString(saveState.label, true)); | |||
| break; | |||
| case PLUGIN_VST: | |||
| info += QString(" <Binary>%1</Binary>\n").arg(xmlSafeString(saveState.binary, true)); | |||
| info += QString(" <UniqueID>%1</UniqueID>\n").arg(saveState.uniqueID); | |||
| break; | |||
| case PLUGIN_GIG: | |||
| case PLUGIN_SF2: | |||
| case PLUGIN_SFZ: | |||
| info += QString(" <Binary>%1</Binary>\n").arg(xmlSafeString(saveState.binary, true)); | |||
| break; | |||
| } | |||
| info += " </Info>\n\n"; | |||
| content += info; | |||
| } | |||
| { | |||
| QString data(" <Data>\n"); | |||
| data += QString(" <Active>%1</Active>\n").arg(saveState.active ? "Yes" : "No"); | |||
| if (saveState.dryWet != 1.0f) | |||
| data += QString(" <DryWet>%1</DryWet>\n").arg(saveState.dryWet); | |||
| if (saveState.volume != 1.0f) | |||
| data += QString(" <Volume>%1</Volume>\n").arg(saveState.volume); | |||
| if (saveState.balanceLeft != -1.0f) | |||
| data += QString(" <Balance-Left>%1</Balance-Left>\n").arg(saveState.balanceLeft); | |||
| if (saveState.balanceRight != 1.0f) | |||
| data += QString(" <Balance-Right>%1</Balance-Right>\n").arg(saveState.balanceRight); | |||
| if (saveState.panning != 0.0f) | |||
| data += QString(" <Panning>%1</Panning>\n").arg(saveState.panning); | |||
| content += data; | |||
| } | |||
| for (auto it = saveState.parameters.begin(); it != saveState.parameters.end(); ++it) | |||
| { | |||
| StateParameter* stateParameter = *it; | |||
| QString parameter("\n"" <Parameter>\n"); | |||
| parameter += QString(" <Index>%1</Index>\n").arg(stateParameter->index); | |||
| parameter += QString(" <Name>%1</Name>\n").arg(xmlSafeString(stateParameter->name, true)); | |||
| if (stateParameter->symbol != nullptr && *stateParameter->symbol != 0) | |||
| parameter += QString(" <Symbol>%1</Symbol>\n").arg(xmlSafeString(stateParameter->symbol, true)); | |||
| parameter += QString(" <Value>%1</Value>\n").arg(stateParameter->value); | |||
| if (stateParameter->midiCC > 0) | |||
| { | |||
| parameter += QString(" <MidiCC>%1</MidiCC>\n").arg(stateParameter->midiCC); | |||
| parameter += QString(" <MidiChannel>%1</MidiChannel>\n").arg(stateParameter->midiChannel); | |||
| } | |||
| parameter += " </Parameter>\n"; | |||
| content += parameter; | |||
| } | |||
| if (saveState.currentProgramIndex >= 0) | |||
| { | |||
| QString program("\n"); | |||
| program += QString(" <CurrentProgramIndex>%1</CurrentProgramIndex>\n").arg(saveState.currentProgramIndex); | |||
| program += QString(" <CurrentProgramName>%1</CurrentProgramName>\n").arg(xmlSafeString(saveState.currentProgramName, true)); | |||
| content += program; | |||
| } | |||
| if (saveState.currentMidiBank >= 0 && saveState.currentMidiProgram >= 0) | |||
| { | |||
| QString midiProgram("\n"); | |||
| midiProgram += QString(" <CurrentMidiBank>%1</CurrentMidiBank>\n").arg(saveState.currentMidiBank); | |||
| midiProgram += QString(" <CurrentMidiProgram>%1</CurrentMidiProgram>\n").arg(saveState.currentMidiProgram); | |||
| content += midiProgram; | |||
| } | |||
| for (auto it = saveState.customData.begin(); it != saveState.customData.end(); ++it) | |||
| { | |||
| StateCustomData* stateCustomData = *it; | |||
| QString customData("\n"" <CustomData>\n"); | |||
| customData += QString(" <Type>%1</Type>\n").arg(xmlSafeString(stateCustomData->type, true)); | |||
| customData += QString(" <Key>%1</Key>\n").arg(xmlSafeString(stateCustomData->key, true)); | |||
| if (std::strcmp(stateCustomData->type, CUSTOM_DATA_CHUNK) == 0) | |||
| { | |||
| customData += " <Value>\n"; | |||
| customData += QString("%1\n").arg(xmlSafeString(stateCustomData->value, true)); | |||
| customData += " </Value>\n"; | |||
| } | |||
| else | |||
| customData += QString(" <Value>%1</Value>\n").arg(xmlSafeString(stateCustomData->value, true)); | |||
| customData += " </CustomData>\n"; | |||
| content += customData; | |||
| } | |||
| if (saveState.chunk != nullptr && *saveState.chunk != 0) | |||
| { | |||
| QString chunk("\n"" <Chunk>\n"); | |||
| chunk += QString("%1\n").arg(saveState.chunk); | |||
| chunk += " </Chunk>\n"; | |||
| content += chunk; | |||
| } | |||
| content += " </Data>\n"; | |||
| return content; | |||
| } | |||
| // ------------------------------------------------- | |||