@@ -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; | |||
} | |||
// ------------------------------------------------- | |||