|
|
@@ -22,12 +22,10 @@ |
|
|
|
#include "CarlaMIDI.h" |
|
|
|
#include "RtList.hpp" |
|
|
|
|
|
|
|
#if 0 |
|
|
|
# include <QtXml/QDomNode> |
|
|
|
#else |
|
|
|
# include "juce_core.h" |
|
|
|
#include "juce_core.h" |
|
|
|
|
|
|
|
using juce::String; |
|
|
|
#endif |
|
|
|
using juce::XmlElement; |
|
|
|
|
|
|
|
CARLA_BACKEND_START_NAMESPACE |
|
|
|
|
|
|
@@ -218,24 +216,6 @@ struct SaveState { |
|
|
|
|
|
|
|
// ----------------------------------------------------------------------- |
|
|
|
|
|
|
|
#if 0 |
|
|
|
static inline |
|
|
|
QString xmlSafeString(const QString& string, const bool toXml) |
|
|
|
{ |
|
|
|
QString newString(string); |
|
|
|
|
|
|
|
if (toXml) |
|
|
|
return newString.replace("&","&").replace("<","<").replace(">",">").replace("'","'").replace("\"","""); |
|
|
|
else |
|
|
|
return newString.replace("&","&").replace("<","<").replace(">",">").replace("'","'").replace(""","\""); |
|
|
|
} |
|
|
|
|
|
|
|
static inline |
|
|
|
const char* xmlSafeStringCharDup(const QString& string, const bool toXml) |
|
|
|
{ |
|
|
|
return carla_strdup(xmlSafeString(string, toXml).toUtf8().constData()); |
|
|
|
} |
|
|
|
#else |
|
|
|
static inline |
|
|
|
String xmlSafeString(const String& string, const bool toXml) |
|
|
|
{ |
|
|
@@ -252,112 +232,91 @@ const char* xmlSafeStringCharDup(const String& string, const bool toXml) |
|
|
|
{ |
|
|
|
return carla_strdup(xmlSafeString(string, toXml).toRawUTF8()); |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
// ----------------------------------------------------------------------- |
|
|
|
|
|
|
|
#if 0 |
|
|
|
static inline |
|
|
|
void fillSaveStateFromXmlNode(SaveState& saveState, const QDomNode& xmlNode) |
|
|
|
void fillSaveStateFromXmlElement(SaveState& saveState, const XmlElement& xmlElement) |
|
|
|
{ |
|
|
|
if (xmlNode.isNull()) |
|
|
|
return; |
|
|
|
|
|
|
|
for (QDomNode node = xmlNode.firstChild(); ! node.isNull(); node = node.nextSibling()) |
|
|
|
for (XmlElement* elem = xmlElement.getFirstChildElement(); elem != nullptr; elem = elem->getNextElement()) |
|
|
|
{ |
|
|
|
// --------------------------------------------------------------- |
|
|
|
// Info |
|
|
|
|
|
|
|
if (node.toElement().tagName().compare("Info", Qt::CaseInsensitive) == 0) |
|
|
|
if (elem->getTagName().equalsIgnoreCase("info")) |
|
|
|
{ |
|
|
|
for (QDomNode xmlInfo = node.toElement().firstChild(); ! xmlInfo.isNull(); xmlInfo = xmlInfo.nextSibling()) |
|
|
|
for (XmlElement* xmlInfo = elem->getFirstChildElement(); xmlInfo != nullptr; xmlInfo = xmlInfo->getNextElement()) |
|
|
|
{ |
|
|
|
const QString tag(xmlInfo.toElement().tagName()); |
|
|
|
const QString text(xmlInfo.toElement().text().trimmed()); |
|
|
|
const String& tag(xmlInfo->getTagName()); |
|
|
|
const String text(xmlInfo->getAllSubText().trim()); |
|
|
|
|
|
|
|
if (tag.compare("Type", Qt::CaseInsensitive) == 0) |
|
|
|
if (tag.equalsIgnoreCase("type")) |
|
|
|
saveState.type = xmlSafeStringCharDup(text, false); |
|
|
|
else if (tag.compare("Name", Qt::CaseInsensitive) == 0) |
|
|
|
else if (tag.equalsIgnoreCase("name")) |
|
|
|
saveState.name = xmlSafeStringCharDup(text, false); |
|
|
|
else if (tag.compare("Label", Qt::CaseInsensitive) == 0 || tag.compare("URI", Qt::CaseInsensitive) == 0) |
|
|
|
else if (tag.equalsIgnoreCase("label") || tag.equalsIgnoreCase("uri")) |
|
|
|
saveState.label = xmlSafeStringCharDup(text, false); |
|
|
|
else if (tag.compare("Binary", Qt::CaseInsensitive) == 0) |
|
|
|
else if (tag.equalsIgnoreCase("binary") || tag.equalsIgnoreCase("filename")) |
|
|
|
saveState.binary = xmlSafeStringCharDup(text, false); |
|
|
|
else if (tag.compare("UniqueID", Qt::CaseInsensitive) == 0) |
|
|
|
{ |
|
|
|
bool ok; |
|
|
|
const long uniqueID(text.toLong(&ok)); |
|
|
|
if (ok) saveState.uniqueID = uniqueID; |
|
|
|
} |
|
|
|
else if (tag.equalsIgnoreCase("uniqueid")) |
|
|
|
saveState.uniqueID = text.getLargeIntValue(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// --------------------------------------------------------------- |
|
|
|
// Data |
|
|
|
|
|
|
|
else if (node.toElement().tagName().compare("Data", Qt::CaseInsensitive) == 0) |
|
|
|
else if (elem->getTagName().equalsIgnoreCase("data")) |
|
|
|
{ |
|
|
|
for (QDomNode xmlData = node.toElement().firstChild(); ! xmlData.isNull(); xmlData = xmlData.nextSibling()) |
|
|
|
for (XmlElement* xmlData = elem->getFirstChildElement(); xmlData != nullptr; xmlData = xmlData->getNextElement()) |
|
|
|
{ |
|
|
|
const QString tag(xmlData.toElement().tagName()); |
|
|
|
const QString text(xmlData.toElement().text().trimmed()); |
|
|
|
const String& tag(xmlData->getTagName()); |
|
|
|
const String text(xmlData->getAllSubText().trim()); |
|
|
|
|
|
|
|
// ------------------------------------------------------- |
|
|
|
// Internal Data |
|
|
|
|
|
|
|
if (tag.compare("Active", Qt::CaseInsensitive) == 0) |
|
|
|
if (tag.equalsIgnoreCase("active")) |
|
|
|
{ |
|
|
|
saveState.active = (text.compare("Yes", Qt::CaseInsensitive) == 0); |
|
|
|
saveState.active = (text.equalsIgnoreCase("yes")); |
|
|
|
} |
|
|
|
else if (tag.compare("DryWet", Qt::CaseInsensitive) == 0) |
|
|
|
else if (tag.equalsIgnoreCase("drywet")) |
|
|
|
{ |
|
|
|
bool ok; |
|
|
|
const float value(text.toFloat(&ok)); |
|
|
|
if (ok) saveState.dryWet = carla_fixValue(0.0f, 1.0f, value); |
|
|
|
saveState.dryWet = carla_fixValue(0.0f, 1.0f, text.getFloatValue()); |
|
|
|
} |
|
|
|
else if (tag.compare("Volume", Qt::CaseInsensitive) == 0) |
|
|
|
else if (tag.equalsIgnoreCase("volume")) |
|
|
|
{ |
|
|
|
bool ok; |
|
|
|
const float value(text.toFloat(&ok)); |
|
|
|
if (ok) saveState.volume = carla_fixValue(0.0f, 1.27f, value); |
|
|
|
saveState.volume = carla_fixValue(0.0f, 1.27f, text.getFloatValue()); |
|
|
|
} |
|
|
|
else if (tag.compare("Balance-Left", Qt::CaseInsensitive) == 0) |
|
|
|
else if (tag.equalsIgnoreCase("balanceleft") || tag.equalsIgnoreCase("balance-left")) |
|
|
|
{ |
|
|
|
bool ok; |
|
|
|
const float value(text.toFloat(&ok)); |
|
|
|
if (ok) saveState.balanceLeft = carla_fixValue(-1.0f, 1.0f, value); |
|
|
|
saveState.balanceLeft = carla_fixValue(-1.0f, 1.0f, text.getFloatValue()); |
|
|
|
} |
|
|
|
else if (tag.compare("Balance-Right", Qt::CaseInsensitive) == 0) |
|
|
|
else if (tag.equalsIgnoreCase("balanceright") || tag.equalsIgnoreCase("balance-right")) |
|
|
|
{ |
|
|
|
bool ok; |
|
|
|
const float value(text.toFloat(&ok)); |
|
|
|
if (ok) saveState.balanceRight = carla_fixValue(-1.0f, 1.0f, value); |
|
|
|
saveState.balanceRight = carla_fixValue(-1.0f, 1.0f, text.getFloatValue()); |
|
|
|
} |
|
|
|
else if (tag.compare("Panning", Qt::CaseInsensitive) == 0) |
|
|
|
else if (tag.equalsIgnoreCase("panning")) |
|
|
|
{ |
|
|
|
bool ok; |
|
|
|
const float value(text.toFloat(&ok)); |
|
|
|
if (ok) saveState.panning = carla_fixValue(-1.0f, 1.0f, value); |
|
|
|
saveState.panning = carla_fixValue(-1.0f, 1.0f, text.getFloatValue()); |
|
|
|
} |
|
|
|
else if (tag.compare("ControlChannel", Qt::CaseInsensitive) == 0) |
|
|
|
else if (tag.equalsIgnoreCase("controlchannel") || tag.equalsIgnoreCase("control-channel")) |
|
|
|
{ |
|
|
|
bool ok; |
|
|
|
const short value(text.toShort(&ok)); |
|
|
|
if (ok && value >= 1 && value <= MAX_MIDI_CHANNELS) |
|
|
|
const int value(text.getIntValue()); |
|
|
|
if (value >= 1 && value <= MAX_MIDI_CHANNELS) |
|
|
|
saveState.ctrlChannel = static_cast<int8_t>(value-1); |
|
|
|
} |
|
|
|
|
|
|
|
// ------------------------------------------------------- |
|
|
|
// Program (current) |
|
|
|
|
|
|
|
else if (tag.compare("CurrentProgramIndex", Qt::CaseInsensitive) == 0) |
|
|
|
else if (tag.equalsIgnoreCase("currentprogramindex") || tag.equalsIgnoreCase("current-program-index")) |
|
|
|
{ |
|
|
|
bool ok; |
|
|
|
const int value(text.toInt(&ok)); |
|
|
|
if (ok && value >= 1) |
|
|
|
const int value(text.getIntValue()); |
|
|
|
if (value >= 1) |
|
|
|
saveState.currentProgramIndex = value-1; |
|
|
|
} |
|
|
|
else if (tag.compare("CurrentProgramName", Qt::CaseInsensitive) == 0) |
|
|
|
else if (tag.equalsIgnoreCase("currentprogramname") || tag.equalsIgnoreCase("current-program-name")) |
|
|
|
{ |
|
|
|
saveState.currentProgramName = xmlSafeStringCharDup(text, false); |
|
|
|
} |
|
|
@@ -365,65 +324,59 @@ void fillSaveStateFromXmlNode(SaveState& saveState, const QDomNode& xmlNode) |
|
|
|
// ------------------------------------------------------- |
|
|
|
// Midi Program (current) |
|
|
|
|
|
|
|
else if (tag.compare("CurrentMidiBank", Qt::CaseInsensitive) == 0) |
|
|
|
else if (tag.equalsIgnoreCase("currentmidibank") || tag.equalsIgnoreCase("current-midi-bank")) |
|
|
|
{ |
|
|
|
bool ok; |
|
|
|
const int value(text.toInt(&ok)); |
|
|
|
if (ok && value >= 1) |
|
|
|
const int value(text.getIntValue()); |
|
|
|
if (value >= 1) |
|
|
|
saveState.currentMidiBank = value-1; |
|
|
|
} |
|
|
|
else if (tag.compare("CurrentMidiProgram", Qt::CaseInsensitive) == 0) |
|
|
|
else if (tag.equalsIgnoreCase("currentmidiprogram") || tag.equalsIgnoreCase("current-midi-program")) |
|
|
|
{ |
|
|
|
bool ok; |
|
|
|
const int value(text.toInt(&ok)); |
|
|
|
if (ok && value >= 1) |
|
|
|
const int value(text.getIntValue()); |
|
|
|
if (value >= 1) |
|
|
|
saveState.currentMidiProgram = value-1; |
|
|
|
} |
|
|
|
|
|
|
|
// ------------------------------------------------------- |
|
|
|
// Parameters |
|
|
|
|
|
|
|
else if (tag.compare("Parameter", Qt::CaseInsensitive) == 0) |
|
|
|
else if (tag.equalsIgnoreCase("parameter")) |
|
|
|
{ |
|
|
|
StateParameter* const stateParameter(new StateParameter()); |
|
|
|
|
|
|
|
for (QDomNode xmlSubData = xmlData.toElement().firstChild(); ! xmlSubData.isNull(); xmlSubData = xmlSubData.nextSibling()) |
|
|
|
for (XmlElement* xmlSubData = xmlData->getFirstChildElement(); xmlSubData != nullptr; xmlSubData = xmlSubData->getNextElement()) |
|
|
|
{ |
|
|
|
const QString pTag(xmlSubData.toElement().tagName()); |
|
|
|
const QString pText(xmlSubData.toElement().text().trimmed()); |
|
|
|
const String& pTag(xmlSubData->getTagName()); |
|
|
|
const String pText(xmlSubData->getAllSubText().trim()); |
|
|
|
|
|
|
|
if (pTag.compare("Index", Qt::CaseInsensitive) == 0) |
|
|
|
if (pTag.equalsIgnoreCase("index")) |
|
|
|
{ |
|
|
|
bool ok; |
|
|
|
const uint index(pText.toUInt(&ok)); |
|
|
|
if (ok) stateParameter->index = index; |
|
|
|
const int index(pText.getIntValue()); |
|
|
|
if (index >= 0) |
|
|
|
stateParameter->index = index; |
|
|
|
} |
|
|
|
else if (pTag.compare("Name", Qt::CaseInsensitive) == 0) |
|
|
|
else if (pTag.equalsIgnoreCase("name")) |
|
|
|
{ |
|
|
|
stateParameter->name = xmlSafeStringCharDup(pText, false); |
|
|
|
} |
|
|
|
else if (pTag.compare("Symbol", Qt::CaseInsensitive) == 0) |
|
|
|
else if (pTag.equalsIgnoreCase("symbol")) |
|
|
|
{ |
|
|
|
stateParameter->symbol = xmlSafeStringCharDup(pText, false); |
|
|
|
} |
|
|
|
else if (pTag.compare("Value", Qt::CaseInsensitive) == 0) |
|
|
|
else if (pTag.equalsIgnoreCase("value")) |
|
|
|
{ |
|
|
|
bool ok; |
|
|
|
const float value(pText.toFloat(&ok)); |
|
|
|
if (ok) stateParameter->value = value; |
|
|
|
stateParameter->value = pText.getFloatValue(); |
|
|
|
} |
|
|
|
else if (pTag.compare("MidiChannel", Qt::CaseInsensitive) == 0) |
|
|
|
else if (pTag.equalsIgnoreCase("midichannel") || pTag.equalsIgnoreCase("midi-channel")) |
|
|
|
{ |
|
|
|
bool ok; |
|
|
|
const ushort channel(pText.toUShort(&ok)); |
|
|
|
if (ok && channel >= 1 && channel <= MAX_MIDI_CHANNELS) |
|
|
|
const int channel(pText.getIntValue()); |
|
|
|
if (channel >= 1 && channel <= MAX_MIDI_CHANNELS) |
|
|
|
stateParameter->midiChannel = static_cast<uint8_t>(channel-1); |
|
|
|
} |
|
|
|
else if (pTag.compare("MidiCC", Qt::CaseInsensitive) == 0) |
|
|
|
else if (pTag.equalsIgnoreCase("midicc") || pTag.equalsIgnoreCase("midi-cc")) |
|
|
|
{ |
|
|
|
bool ok; |
|
|
|
const int cc(pText.toInt(&ok)); |
|
|
|
if (ok && cc >= 1 && cc < 0x5F) |
|
|
|
const int cc(pText.getIntValue()); |
|
|
|
if (cc >= 1 && cc < 0x5F) |
|
|
|
stateParameter->midiCC = static_cast<int16_t>(cc); |
|
|
|
} |
|
|
|
} |
|
|
@@ -434,20 +387,20 @@ void fillSaveStateFromXmlNode(SaveState& saveState, const QDomNode& xmlNode) |
|
|
|
// ------------------------------------------------------- |
|
|
|
// Custom Data |
|
|
|
|
|
|
|
else if (tag.compare("CustomData", Qt::CaseInsensitive) == 0) |
|
|
|
else if (tag.equalsIgnoreCase("customdata") || tag.equalsIgnoreCase("custom-data")) |
|
|
|
{ |
|
|
|
StateCustomData* const stateCustomData(new StateCustomData()); |
|
|
|
|
|
|
|
for (QDomNode xmlSubData = xmlData.toElement().firstChild(); ! xmlSubData.isNull(); xmlSubData = xmlSubData.nextSibling()) |
|
|
|
for (XmlElement* xmlSubData = xmlData->getFirstChildElement(); xmlSubData != nullptr; xmlSubData = xmlSubData->getNextElement()) |
|
|
|
{ |
|
|
|
const QString cTag(xmlSubData.toElement().tagName()); |
|
|
|
const QString cText(xmlSubData.toElement().text().trimmed()); |
|
|
|
const String& cTag(xmlSubData->getTagName()); |
|
|
|
const String cText(xmlSubData->getAllSubText().trim()); |
|
|
|
|
|
|
|
if (cTag.compare("Type", Qt::CaseInsensitive) == 0) |
|
|
|
if (cTag.equalsIgnoreCase("type")) |
|
|
|
stateCustomData->type = xmlSafeStringCharDup(cText, false); |
|
|
|
else if (cTag.compare("Key", Qt::CaseInsensitive) == 0) |
|
|
|
else if (cTag.equalsIgnoreCase("key")) |
|
|
|
stateCustomData->key = xmlSafeStringCharDup(cText, false); |
|
|
|
else if (cTag.compare("Value", Qt::CaseInsensitive) == 0) |
|
|
|
else if (cTag.equalsIgnoreCase("value")) |
|
|
|
stateCustomData->value = xmlSafeStringCharDup(cText, false); |
|
|
|
} |
|
|
|
|
|
|
@@ -457,7 +410,7 @@ void fillSaveStateFromXmlNode(SaveState& saveState, const QDomNode& xmlNode) |
|
|
|
// ------------------------------------------------------- |
|
|
|
// Chunk |
|
|
|
|
|
|
|
else if (tag.compare("Chunk", Qt::CaseInsensitive) == 0) |
|
|
|
else if (tag.equalsIgnoreCase("chunk")) |
|
|
|
{ |
|
|
|
saveState.chunk = xmlSafeStringCharDup(text, false); |
|
|
|
} |
|
|
@@ -465,7 +418,6 @@ void fillSaveStateFromXmlNode(SaveState& saveState, const QDomNode& xmlNode) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
// ----------------------------------------------------------------------- |
|
|
|
|
|
|
@@ -510,7 +462,7 @@ void fillXmlStringFromSaveState(String& content, const SaveState& saveState) |
|
|
|
case PLUGIN_GIG: |
|
|
|
case PLUGIN_SF2: |
|
|
|
case PLUGIN_SFZ: |
|
|
|
info << " <Binary>" << xmlSafeString(saveState.binary, true) << "</Binary>\n"; |
|
|
|
info << " <Filename>" << xmlSafeString(saveState.binary, true) << "</Filename>\n"; |
|
|
|
info << " <Label>" << xmlSafeString(saveState.label, true) << "</Label>\n"; |
|
|
|
break; |
|
|
|
} |
|
|
@@ -553,7 +505,7 @@ void fillXmlStringFromSaveState(String& content, const SaveState& saveState) |
|
|
|
parameter << " <Index>" << (long)stateParameter->index << "</Index>\n"; // FIXME |
|
|
|
parameter << " <Name>" << xmlSafeString(stateParameter->name, true) << "</Name>\n"; |
|
|
|
|
|
|
|
if (stateParameter->symbol != nullptr && *stateParameter->symbol != '\0') |
|
|
|
if (stateParameter->symbol != nullptr && stateParameter->symbol[0] != '\0') |
|
|
|
parameter << " <Symbol>" << xmlSafeString(stateParameter->symbol, true) << "</Symbol>\n"; |
|
|
|
|
|
|
|
parameter << " <Value>" << stateParameter->value << "</Value>\n"; |
|
|
@@ -604,24 +556,19 @@ void fillXmlStringFromSaveState(String& content, const SaveState& saveState) |
|
|
|
customData << " <Key>" << xmlSafeString(stateCustomData->key, true) << "</Key>\n"; |
|
|
|
|
|
|
|
if (std::strcmp(stateCustomData->type, CUSTOM_DATA_CHUNK) == 0 || std::strlen(stateCustomData->value) >= 128) |
|
|
|
{ |
|
|
|
customData << " <Value>\n"; |
|
|
|
customData << "" << xmlSafeString(stateCustomData->value, true) << "\n"; |
|
|
|
customData << " </Value>\n"; |
|
|
|
} |
|
|
|
customData << " <Value>\n" << xmlSafeString(stateCustomData->value, true) << "\n </Value>\n"; |
|
|
|
else |
|
|
|
customData << " <Value>" << xmlSafeString(stateCustomData->value, true) << "</Value>\n"; |
|
|
|
customData << " <Value>" << xmlSafeString(stateCustomData->value, true) << "</Value>\n"; |
|
|
|
|
|
|
|
customData << " </CustomData>\n"; |
|
|
|
|
|
|
|
content << customData; |
|
|
|
} |
|
|
|
|
|
|
|
if (saveState.chunk != nullptr && *saveState.chunk != '\0') |
|
|
|
if (saveState.chunk != nullptr && saveState.chunk[0] != '\0') |
|
|
|
{ |
|
|
|
String chunk("\n"" <Chunk>\n"); |
|
|
|
chunk << "" << saveState.chunk << "\n"; |
|
|
|
chunk << " </Chunk>\n"; |
|
|
|
chunk << saveState.chunk << "\n </Chunk>\n"; |
|
|
|
|
|
|
|
content << chunk; |
|
|
|
} |
|
|
|