| @@ -427,6 +427,16 @@ public: | |||||
| */ | */ | ||||
| void loadSaveState(const SaveState& saveState); | void loadSaveState(const SaveState& saveState); | ||||
| /*! | |||||
| * TODO | |||||
| */ | |||||
| bool saveStateToFile(const char* const filename); | |||||
| /*! | |||||
| * TODO | |||||
| */ | |||||
| bool loadStateFromFile(const char* const filename); | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| // Set data (internal stuff) | // 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 bool carla_remove_plugin(unsigned int pluginId); | ||||
| CARLA_EXPORT void carla_remove_all_plugins(); | 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 CarlaPluginInfo* carla_get_plugin_info(unsigned int pluginId); | ||||
| CARLA_EXPORT const CarlaPortCountInfo* carla_get_audio_port_count_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 "CarlaEngineInternal.hpp" | ||||
| #include "CarlaBackendUtils.hpp" | #include "CarlaBackendUtils.hpp" | ||||
| #include "CarlaStateUtils.hpp" | |||||
| #include "CarlaMIDI.h" | #include "CarlaMIDI.h" | ||||
| #include <QtCore/QFile> | #include <QtCore/QFile> | ||||
| @@ -966,29 +967,66 @@ void CarlaEngine::__bridgePluginRegister(const unsigned short id, CarlaPlugin* c | |||||
| bool CarlaEngine::loadProject(const char* const filename) | bool CarlaEngine::loadProject(const char* const filename) | ||||
| { | { | ||||
| carla_debug("CarlaEngine::loadProject(\"%s\")", filename); | |||||
| CARLA_ASSERT(filename != nullptr); | 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; | return true; | ||||
| } | } | ||||
| bool CarlaEngine::saveProject(const char* const filename) | bool CarlaEngine::saveProject(const char* const filename) | ||||
| { | { | ||||
| carla_debug("CarlaEngine::saveProject(\"%s\")", filename); | |||||
| CARLA_ASSERT(filename != nullptr); | CARLA_ASSERT(filename != nullptr); | ||||
| #if 0 | |||||
| QFile file(filename); | QFile file(filename); | ||||
| file.open(QIODevice::WriteOnly | QIODevice::Text); | |||||
| if (! file.open(QIODevice::WriteOnly | QIODevice::Text)) | |||||
| return false; | |||||
| QTextStream out(&file); | QTextStream out(&file); | ||||
| out << "<?xml version='1.0' encoding='UTF-8'?>\n"; | 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++) | 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()) | 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(); | file.close(); | ||||
| #endif | |||||
| return true; | return true; | ||||
| } | } | ||||
| @@ -19,6 +19,9 @@ | |||||
| #include "CarlaLibUtils.hpp" | #include "CarlaLibUtils.hpp" | ||||
| #include "CarlaMIDI.h" | #include "CarlaMIDI.h" | ||||
| #include <QtCore/QFile> | |||||
| #include <QtCore/QTextStream> | |||||
| //#include <QtGui/QtEvents> | //#include <QtGui/QtEvents> | ||||
| // TODO - save&load options | // TODO - save&load options | ||||
| @@ -477,22 +480,22 @@ const SaveState& CarlaPlugin::getSaveState() | |||||
| if (paramData.type != PARAMETER_INPUT) | if (paramData.type != PARAMETER_INPUT) | ||||
| continue; | 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); | getParameterName(i, strBuf); | ||||
| stateParameter.name = carla_strdup(strBuf); | |||||
| stateParameter->name = carla_strdup(strBuf); | |||||
| getParameterSymbol(i, 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) | if (paramData.hints & PARAMETER_USES_SAMPLERATE) | ||||
| stateParameter.value /= sampleRate; | |||||
| stateParameter->value /= sampleRate; | |||||
| saveState.parameters.push_back(stateParameter); | saveState.parameters.push_back(stateParameter); | ||||
| } | } | ||||
| @@ -507,11 +510,11 @@ const SaveState& CarlaPlugin::getSaveState() | |||||
| if (cData.type == nullptr) | if (cData.type == nullptr) | ||||
| continue; | 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); | saveState.customData.push_back(stateCustomData); | ||||
| } | } | ||||
| @@ -542,6 +545,53 @@ void CarlaPlugin::loadSaveState(const SaveState& saveState) | |||||
| Q_UNUSED(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) | // Set data (internal stuff) | ||||
| @@ -541,6 +541,36 @@ void carla_remove_all_plugins() | |||||
| standalone.engine->removeAllPlugins(); | 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) | const CarlaPluginInfo* carla_get_plugin_info(unsigned int pluginId) | ||||
| @@ -9,7 +9,7 @@ include ../Makefile.mk | |||||
| # -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
| # Common | # Common | ||||
| LINK_FLAGS += $(shell pkg-config --libs liblo QtCore QtGui) | |||||
| LINK_FLAGS += $(shell pkg-config --libs liblo QtCore QtGui QtXml) | |||||
| # -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
| # Engine | # Engine | ||||
| @@ -209,6 +209,12 @@ class Host(object): | |||||
| self.lib.carla_remove_all_plugins.argtypes = None | self.lib.carla_remove_all_plugins.argtypes = None | ||||
| self.lib.carla_remove_all_plugins.restype = 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.argtypes = [c_uint] | ||||
| self.lib.carla_get_plugin_info.restype = POINTER(CarlaPluginInfo) | self.lib.carla_get_plugin_info.restype = POINTER(CarlaPluginInfo) | ||||
| @@ -423,6 +429,12 @@ class Host(object): | |||||
| def remove_all_plugins(self): | def remove_all_plugins(self): | ||||
| self.lib.carla_remove_all_plugins() | 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): | def get_plugin_info(self, pluginId): | ||||
| return structToDict(self.lib.carla_get_plugin_info(pluginId).contents) | 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) | askTry = QMessageBox.question(self, self.tr("Overwrite?"), self.tr("Overwrite previously created file?"), QMessageBox.Ok|QMessageBox.Cancel) | ||||
| if askTry == QMessageBox.Ok: | if askTry == QMessageBox.Ok: | ||||
| return #self.saveState() | |||||
| Carla.host.save_plugin_state(self.fPluginId, self.fCurrentStateFilename) | |||||
| self.fCurrentStateFilename = None | self.fCurrentStateFilename = None | ||||
| @@ -1942,7 +1942,7 @@ class PluginEdit(QDialog): | |||||
| filenameTry += ".carxs" | filenameTry += ".carxs" | ||||
| self.fCurrentStateFilename = filenameTry | self.fCurrentStateFilename = filenameTry | ||||
| #self.saveState() | |||||
| Carla.host.save_plugin_state(self.fPluginId, self.fCurrentStateFilename) | |||||
| @pyqtSlot() | @pyqtSlot() | ||||
| def slot_loadState(self): | def slot_loadState(self): | ||||
| @@ -1951,7 +1951,7 @@ class PluginEdit(QDialog): | |||||
| if filenameTry: | if filenameTry: | ||||
| self.fCurrentStateFilename = filenameTry | self.fCurrentStateFilename = filenameTry | ||||
| #self.loadState() | |||||
| Carla.host.load_plugin_state(self.fPluginId, self.fCurrentStateFilename) | |||||
| @pyqtSlot(bool) | @pyqtSlot(bool) | ||||
| def slot_optionChanged(self, clicked): | def slot_optionChanged(self, clicked): | ||||
| @@ -366,9 +366,9 @@ void* getPointerFromAddress(uintptr_t& addr) | |||||
| // ------------------------------------------------- | // ------------------------------------------------- | ||||
| static inline | 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) | switch (type) | ||||
| { | { | ||||
| @@ -392,10 +392,44 @@ const char* getPluginTypeString(const PluginType& type) | |||||
| return "SFZ"; | return "SFZ"; | ||||
| } | } | ||||
| carla_stderr("CarlaBackend::getPluginTypeString(%i) - invalid type", type); | |||||
| carla_stderr("CarlaBackend::getPluginTypeAsString(%i) - invalid type", type); | |||||
| return "NONE"; | 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 | static inline | ||||
| @@ -18,8 +18,7 @@ | |||||
| #ifndef __CARLA_STATE_UTILS_HPP__ | #ifndef __CARLA_STATE_UTILS_HPP__ | ||||
| #define __CARLA_STATE_UTILS_HPP__ | #define __CARLA_STATE_UTILS_HPP__ | ||||
| #include "CarlaBackend.hpp" | |||||
| #include "CarlaUtils.hpp" | |||||
| #include "CarlaBackendUtils.hpp" | |||||
| #include <QtXml/QDomNode> | #include <QtXml/QDomNode> | ||||
| #include <vector> | #include <vector> | ||||
| @@ -27,7 +26,6 @@ | |||||
| CARLA_BACKEND_START_NAMESPACE | CARLA_BACKEND_START_NAMESPACE | ||||
| // ------------------------------------------------- | // ------------------------------------------------- | ||||
| // Carla GUI stuff | |||||
| struct StateParameter { | struct StateParameter { | ||||
| uint32_t index; | 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 { | struct SaveState { | ||||
| const char* type; | const char* type; | ||||
| @@ -173,13 +171,24 @@ struct SaveState { | |||||
| currentMidiBank = -1; | currentMidiBank = -1; | ||||
| currentMidiProgram = -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(); | parameters.clear(); | ||||
| customData.clear(); | customData.clear(); | ||||
| } | } | ||||
| }; | }; | ||||
| // ------------------------------------------------- | // ------------------------------------------------- | ||||
| // Carla XML helpers (xml to state) | |||||
| static inline | static inline | ||||
| QString xmlSafeString(const QString& string, const bool toXml) | 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()); | return carla_strdup(xmlSafeString(string, toXml).toUtf8().constData()); | ||||
| } | } | ||||
| // ------------------------------------------------- | |||||
| static inline | static inline | ||||
| const SaveState& getSaveStateDictFromXML(const QDomNode& xmlNode) | const SaveState& getSaveStateDictFromXML(const QDomNode& xmlNode) | ||||
| { | { | ||||
| @@ -261,27 +272,33 @@ const SaveState& getSaveStateDictFromXML(const QDomNode& xmlNode) | |||||
| else if (tag == "DryWet") | else if (tag == "DryWet") | ||||
| { | { | ||||
| bool ok; | bool ok; | ||||
| double value = text.toDouble(&ok); | |||||
| float value = text.toFloat(&ok); | |||||
| if (ok) saveState.dryWet = value; | if (ok) saveState.dryWet = value; | ||||
| } | } | ||||
| else if (tag == "Volume") | else if (tag == "Volume") | ||||
| { | { | ||||
| bool ok; | bool ok; | ||||
| double value = text.toDouble(&ok); | |||||
| float value = text.toFloat(&ok); | |||||
| if (ok) saveState.volume = value; | if (ok) saveState.volume = value; | ||||
| } | } | ||||
| else if (tag == "Balance-Left") | else if (tag == "Balance-Left") | ||||
| { | { | ||||
| bool ok; | bool ok; | ||||
| double value = text.toDouble(&ok); | |||||
| float value = text.toFloat(&ok); | |||||
| if (ok) saveState.balanceLeft = value; | if (ok) saveState.balanceLeft = value; | ||||
| } | } | ||||
| else if (tag == "Balance-Right") | else if (tag == "Balance-Right") | ||||
| { | { | ||||
| bool ok; | bool ok; | ||||
| double value = text.toDouble(&ok); | |||||
| float value = text.toFloat(&ok); | |||||
| if (ok) saveState.balanceRight = value; | if (ok) saveState.balanceRight = value; | ||||
| } | } | ||||
| else if (tag == "Panning") | |||||
| { | |||||
| bool ok; | |||||
| float value = text.toFloat(&ok); | |||||
| if (ok) saveState.panning = value; | |||||
| } | |||||
| // ---------------------------------------------- | // ---------------------------------------------- | ||||
| // Program (current) | // Program (current) | ||||
| @@ -318,7 +335,7 @@ const SaveState& getSaveStateDictFromXML(const QDomNode& xmlNode) | |||||
| else if (tag == "Parameter") | else if (tag == "Parameter") | ||||
| { | { | ||||
| StateParameter stateParameter; | |||||
| StateParameter* stateParameter(new StateParameter); | |||||
| QDomNode xmlSubData(xmlData.toElement().firstChild()); | QDomNode xmlSubData(xmlData.toElement().firstChild()); | ||||
| @@ -327,39 +344,39 @@ const SaveState& getSaveStateDictFromXML(const QDomNode& xmlNode) | |||||
| const QString pTag = xmlSubData.toElement().tagName(); | const QString pTag = xmlSubData.toElement().tagName(); | ||||
| const QString pText = xmlSubData.toElement().text(); //.strip(); | const QString pText = xmlSubData.toElement().text(); //.strip(); | ||||
| if (pTag == "index") | |||||
| if (pTag == "Index") | |||||
| { | { | ||||
| bool ok; | bool ok; | ||||
| uint index = pText.toUInt(&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; | 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; | bool ok; | ||||
| uint channel = pText.toUInt(&ok); | uint channel = pText.toUInt(&ok); | ||||
| if (ok && channel < 16) | 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; | bool ok; | ||||
| int cc = pText.toInt(&ok); | int cc = pText.toInt(&ok); | ||||
| if (ok && cc < INT16_MAX) | if (ok && cc < INT16_MAX) | ||||
| stateParameter.midiCC = static_cast<int16_t>(cc); | |||||
| stateParameter->midiCC = static_cast<int16_t>(cc); | |||||
| } | } | ||||
| xmlSubData = xmlSubData.nextSibling(); | xmlSubData = xmlSubData.nextSibling(); | ||||
| @@ -373,7 +390,7 @@ const SaveState& getSaveStateDictFromXML(const QDomNode& xmlNode) | |||||
| else if (tag == "CustomData") | else if (tag == "CustomData") | ||||
| { | { | ||||
| StateCustomData stateCustomData; | |||||
| StateCustomData* stateCustomData(new StateCustomData); | |||||
| QDomNode xmlSubData(xmlData.toElement().firstChild()); | QDomNode xmlSubData(xmlData.toElement().firstChild()); | ||||
| @@ -382,12 +399,12 @@ const SaveState& getSaveStateDictFromXML(const QDomNode& xmlNode) | |||||
| const QString cTag = xmlSubData.toElement().tagName(); | const QString cTag = xmlSubData.toElement().tagName(); | ||||
| const QString cText = xmlSubData.toElement().text(); //.strip(); | 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(); | xmlSubData = xmlSubData.nextSibling(); | ||||
| } | } | ||||
| @@ -417,17 +434,151 @@ const SaveState& getSaveStateDictFromXML(const QDomNode& xmlNode) | |||||
| return saveState; | return saveState; | ||||
| } | } | ||||
| // ------------------------------------------------- | |||||
| static inline | static inline | ||||
| QString getXMLFromSaveState(const SaveState& saveState) | 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; | |||||
| } | |||||
| // ------------------------------------------------- | // ------------------------------------------------- | ||||