Browse Source

Make state utils calls part of StateSave struct

tags/1.9.4
falkTX 11 years ago
parent
commit
52babe107e
9 changed files with 340 additions and 338 deletions
  1. +5
    -5
      source/backend/CarlaPlugin.hpp
  2. +9
    -12
      source/backend/engine/CarlaEngine.cpp
  3. +2
    -2
      source/backend/engine/CarlaEngineJack.cpp
  4. +8
    -11
      source/backend/engine/CarlaEngineNative.cpp
  5. +46
    -50
      source/backend/plugin/CarlaPlugin.cpp
  6. +1
    -1
      source/backend/plugin/CarlaPluginInternal.hpp
  7. +2
    -4
      source/tests/CarlaUtils4.cpp
  8. +256
    -244
      source/utils/CarlaStateUtils.cpp
  9. +11
    -9
      source/utils/CarlaStateUtils.hpp

+ 5
- 5
source/backend/CarlaPlugin.hpp View File

@@ -49,7 +49,7 @@ class CarlaEngineAudioPort;
/*!
* Save state data.
*/
struct SaveState;
struct StateSave;

// -----------------------------------------------------------------------

@@ -382,16 +382,16 @@ public:
* Get the plugin's save state.\n
* The plugin will automatically call prepareForSave() as needed.
*
* \see loadSaveState()
* \see loadStateSave()
*/
const SaveState& getSaveState();
const StateSave& getStateSave();

/*!
* Get the plugin's save state.
*
* \see getSaveState()
* \see getStateSave()
*/
void loadSaveState(const SaveState& saveState);
void loadStateSave(const StateSave& stateSave);

/*!
* Save the current plugin state to \a filename.


+ 9
- 12
source/backend/engine/CarlaEngine.cpp View File

@@ -1353,7 +1353,7 @@ bool CarlaEngine::clonePlugin(const uint id)
CARLA_SAFE_ASSERT_RETURN_ERR(pluginCountBefore+1 == pData->curPluginCount, "No new plugin found");

if (CarlaPlugin* const newPlugin = pData->plugins[pluginCountBefore].plugin)
newPlugin->loadSaveState(plugin->getSaveState());
newPlugin->loadStateSave(plugin->getStateSave());

return true;
}
@@ -1680,21 +1680,21 @@ bool CarlaEngine::loadProject(const char* const filename)
{
if (isPreset || node.toElement().tagName().compare("plugin", Qt::CaseInsensitive) == 0)
{
SaveState saveState;
fillSaveStateFromXmlNode(saveState, isPreset ? xmlNode : node);
StateSave stateSave;
stateSave.fillFromXmlNode(isPreset ? xmlNode : node);

callback(ENGINE_CALLBACK_IDLE, 0, 0, 0, 0.0f, nullptr);

CARLA_SAFE_ASSERT_CONTINUE(saveState.type != nullptr);
CARLA_SAFE_ASSERT_CONTINUE(stateSave.type != nullptr);

const void* extraStuff = nullptr;

// check if using GIG, SF2 or SFZ 16outs
static const char kUse16OutsSuffix[] = " (16 outs)";

const PluginType ptype(getPluginTypeFromString(saveState.type));
const PluginType ptype(getPluginTypeFromString(stateSave.type));

if (CarlaString(saveState.label).endsWith(kUse16OutsSuffix))
if (CarlaString(stateSave.label).endsWith(kUse16OutsSuffix))
{
if (ptype == PLUGIN_FILE_GIG || ptype == PLUGIN_FILE_SF2)
extraStuff = "true";
@@ -1702,10 +1702,10 @@ bool CarlaEngine::loadProject(const char* const filename)

// TODO - proper find&load plugins

if (addPlugin(ptype, saveState.binary, saveState.name, saveState.label, saveState.uniqueId, extraStuff))
if (addPlugin(ptype, stateSave.binary, stateSave.name, stateSave.label, stateSave.uniqueId, extraStuff))
{
if (CarlaPlugin* const plugin = getPlugin(pData->curPluginCount-1))
plugin->loadSaveState(saveState);
plugin->loadStateSave(stateSave);
}
else
carla_stderr2("Failed to load a plugin, error was:%s\n", getLastError());
@@ -1796,11 +1796,8 @@ bool CarlaEngine::saveProject(const char* const filename)
//if (strBuf[0] != '\0')
// out << QString(" <!-- %1 -->\n").arg(xmlSafeString(strBuf, true));

QString content;
fillXmlStringFromSaveState(content, plugin->getSaveState());

out << " <Plugin>\n";
out << content;
out << plugin->getStateSave().toString();
out << " </Plugin>\n";

firstPlugin = false;


+ 2
- 2
source/backend/engine/CarlaEngineJack.cpp View File

@@ -1156,9 +1156,9 @@ public:
if (needsReinit)
{
// reload plugin to recreate its ports
const SaveState& saveState(plugin->getSaveState());
const StateSave& saveState(plugin->getStateSave());
plugin->reload();
plugin->loadSaveState(saveState);
plugin->loadStateSave(saveState);
}

return plugin->getName();


+ 8
- 11
source/backend/engine/CarlaEngineNative.cpp View File

@@ -1313,11 +1313,8 @@ protected:
//if (strBuf[0] != '\0')
// out << QString(" <!-- %1 -->\n").arg(xmlSafeString(strBuf, true));

QString content;
fillXmlStringFromSaveState(content, plugin->getSaveState());

out << " <Plugin>\n";
out << content;
out << plugin->getStateSave().toString();
out << " </Plugin>\n";

firstPlugin = false;
@@ -1348,19 +1345,19 @@ protected:
{
if (node.toElement().tagName().compare("plugin", Qt::CaseInsensitive) == 0)
{
SaveState saveState;
fillSaveStateFromXmlNode(saveState, node);
StateSave stateSave;
stateSave.fillFromXmlNode(node);

CARLA_SAFE_ASSERT_CONTINUE(saveState.type != nullptr);
CARLA_SAFE_ASSERT_CONTINUE(stateSave.type != nullptr);

const void* extraStuff = nullptr;

// check if using GIG, SF2 or SFZ 16outs
static const char kUse16OutsSuffix[] = " (16 outs)";

const PluginType ptype(getPluginTypeFromString(saveState.type));
const PluginType ptype(getPluginTypeFromString(stateSave.type));

if (CarlaString(saveState.label).endsWith(kUse16OutsSuffix))
if (CarlaString(stateSave.label).endsWith(kUse16OutsSuffix))
{
if (ptype == PLUGIN_FILE_GIG || ptype == PLUGIN_FILE_SF2)
extraStuff = "true";
@@ -1368,10 +1365,10 @@ protected:

// TODO - proper find&load plugins

if (addPlugin(ptype, saveState.binary, saveState.name, saveState.label, saveState.uniqueId, extraStuff))
if (addPlugin(ptype, stateSave.binary, stateSave.name, stateSave.label, stateSave.uniqueId, extraStuff))
{
if (CarlaPlugin* const plugin = getPlugin(pData->curPluginCount-1))
plugin->loadSaveState(saveState);
plugin->loadStateSave(stateSave);
}

//pluginsAdded = true;


+ 46
- 50
source/backend/plugin/CarlaPlugin.cpp View File

@@ -41,7 +41,7 @@ static const CustomData kCustomDataNull = { nullptr, nullptr, nullptr
static bool gIsLoadingProject = false;

// -------------------------------------------------------------------
// ParamSymbol struct, needed for CarlaPlugin::loadSaveState()
// ParamSymbol struct, needed for CarlaPlugin::loadStateSave()

struct ParamSymbol {
int32_t index;
@@ -507,9 +507,9 @@ void CarlaPlugin::randomizeParameters() noexcept
}
}

const SaveState& CarlaPlugin::getSaveState()
const StateSave& CarlaPlugin::getStateSave()
{
pData->saveState.reset();
pData->stateSave.clear();
prepareForSave();

char strBuf[STR_MAX+1];
@@ -519,26 +519,26 @@ const SaveState& CarlaPlugin::getSaveState()

getLabel(strBuf);

pData->saveState.type = carla_strdup(getPluginTypeAsString(getType()));
pData->saveState.name = carla_strdup(pData->name);
pData->saveState.label = carla_strdup(strBuf);
pData->saveState.uniqueId = getUniqueId();
pData->stateSave.type = carla_strdup(getPluginTypeAsString(getType()));
pData->stateSave.name = carla_strdup(pData->name);
pData->stateSave.label = carla_strdup(strBuf);
pData->stateSave.uniqueId = getUniqueId();

if (pData->filename != nullptr)
pData->saveState.binary = carla_strdup(pData->filename);
pData->stateSave.binary = carla_strdup(pData->filename);

// ---------------------------------------------------------------
// Internals

pData->saveState.active = pData->active;
pData->stateSave.active = pData->active;

#ifndef BUILD_BRIDGE
pData->saveState.dryWet = pData->postProc.dryWet;
pData->saveState.volume = pData->postProc.volume;
pData->saveState.balanceLeft = pData->postProc.balanceLeft;
pData->saveState.balanceRight = pData->postProc.balanceRight;
pData->saveState.panning = pData->postProc.panning;
pData->saveState.ctrlChannel = pData->ctrlChannel;
pData->stateSave.dryWet = pData->postProc.dryWet;
pData->stateSave.volume = pData->postProc.volume;
pData->stateSave.balanceLeft = pData->postProc.balanceLeft;
pData->stateSave.balanceRight = pData->postProc.balanceRight;
pData->stateSave.panning = pData->postProc.panning;
pData->stateSave.ctrlChannel = pData->ctrlChannel;
#endif

// ---------------------------------------------------------------
@@ -551,10 +551,10 @@ const SaveState& CarlaPlugin::getSaveState()

if (data != nullptr && dataSize > 0)
{
pData->saveState.chunk = carla_strdup(QByteArray((char*)data, dataSize).toBase64().constData());
pData->stateSave.chunk = carla_strdup(QByteArray((char*)data, dataSize).toBase64().constData());

// Don't save anything else if using chunks
return pData->saveState;
return pData->stateSave;
}
}

@@ -563,8 +563,8 @@ const SaveState& CarlaPlugin::getSaveState()

if (pData->prog.current >= 0 && getType() != PLUGIN_LV2)
{
pData->saveState.currentProgramIndex = pData->prog.current;
pData->saveState.currentProgramName = carla_strdup(pData->prog.names[pData->prog.current]);
pData->stateSave.currentProgramIndex = pData->prog.current;
pData->stateSave.currentProgramName = carla_strdup(pData->prog.names[pData->prog.current]);
}

// ---------------------------------------------------------------
@@ -574,8 +574,8 @@ const SaveState& CarlaPlugin::getSaveState()
{
const MidiProgramData& mpData(pData->midiprog.getCurrent());

pData->saveState.currentMidiBank = static_cast<int32_t>(mpData.bank);
pData->saveState.currentMidiProgram = static_cast<int32_t>(mpData.program);
pData->stateSave.currentMidiBank = static_cast<int32_t>(mpData.bank);
pData->stateSave.currentMidiProgram = static_cast<int32_t>(mpData.program);
}

// ---------------------------------------------------------------
@@ -608,7 +608,7 @@ const SaveState& CarlaPlugin::getSaveState()
if (paramData.hints & PARAMETER_USES_SAMPLERATE)
stateParameter->value /= sampleRate;

pData->saveState.parameters.append(stateParameter);
pData->stateSave.parameters.append(stateParameter);
}

// ---------------------------------------------------------------
@@ -624,13 +624,13 @@ const SaveState& CarlaPlugin::getSaveState()
stateCustomData->key = carla_strdup(cData.key);
stateCustomData->value = carla_strdup(cData.value);

pData->saveState.customData.append(stateCustomData);
pData->stateSave.customData.append(stateCustomData);
}

return pData->saveState;
return pData->stateSave;
}

void CarlaPlugin::loadSaveState(const SaveState& saveState)
void CarlaPlugin::loadStateSave(const StateSave& stateSave)
{
char strBuf[STR_MAX+1];
const bool usesMultiProgs(pData->extraHints & PLUGIN_EXTRA_HINT_USES_MULTI_PROGS);
@@ -641,7 +641,7 @@ void CarlaPlugin::loadSaveState(const SaveState& saveState)
// ---------------------------------------------------------------
// Part 1 - PRE-set custom data (only that which reload programs)

for (LinkedList<StateCustomData*>::Itenerator it = saveState.customData.begin(); it.valid(); it.next())
for (LinkedList<StateCustomData*>::Itenerator it = stateSave.customData.begin(); it.valid(); it.next())
{
const StateCustomData* const stateCustomData(it.getValue());
const char* const key(stateCustomData->key);
@@ -660,14 +660,14 @@ void CarlaPlugin::loadSaveState(const SaveState& saveState)
// ---------------------------------------------------------------
// Part 2 - set program

if (saveState.currentProgramIndex >= 0 && saveState.currentProgramName != nullptr)
if (stateSave.currentProgramIndex >= 0 && stateSave.currentProgramName != nullptr)
{
int32_t programId = -1;

// index < count
if (saveState.currentProgramIndex < static_cast<int32_t>(pData->prog.count))
if (stateSave.currentProgramIndex < static_cast<int32_t>(pData->prog.count))
{
programId = saveState.currentProgramIndex;
programId = stateSave.currentProgramIndex;
}
// index not valid, try to find by name
else
@@ -677,7 +677,7 @@ void CarlaPlugin::loadSaveState(const SaveState& saveState)
strBuf[0] = '\0';
getProgramName(i, strBuf);

if (strBuf[0] != '\0' && std::strcmp(saveState.currentProgramName, strBuf) == 0)
if (strBuf[0] != '\0' && std::strcmp(stateSave.currentProgramName, strBuf) == 0)
{
programId = static_cast<int32_t>(i);
break;
@@ -693,8 +693,8 @@ void CarlaPlugin::loadSaveState(const SaveState& saveState)
// ---------------------------------------------------------------
// Part 3 - set midi program

if (saveState.currentMidiBank >= 0 && saveState.currentMidiProgram >= 0 && ! usesMultiProgs)
setMidiProgramById(static_cast<uint32_t>(saveState.currentMidiBank), static_cast<uint32_t>(saveState.currentMidiProgram), true, true, true);
if (stateSave.currentMidiBank >= 0 && stateSave.currentMidiProgram >= 0 && ! usesMultiProgs)
setMidiProgramById(static_cast<uint32_t>(stateSave.currentMidiBank), static_cast<uint32_t>(stateSave.currentMidiProgram), true, true, true);

// ---------------------------------------------------------------
// Part 4a - get plugin parameter symbols
@@ -721,7 +721,7 @@ void CarlaPlugin::loadSaveState(const SaveState& saveState)

const float sampleRate(static_cast<float>(pData->engine->getSampleRate()));

for (LinkedList<StateParameter*>::Itenerator it = saveState.parameters.begin(); it.valid(); it.next())
for (LinkedList<StateParameter*>::Itenerator it = stateSave.parameters.begin(); it.valid(); it.next())
{
StateParameter* const stateParameter(it.getValue());

@@ -811,7 +811,7 @@ void CarlaPlugin::loadSaveState(const SaveState& saveState)
// ---------------------------------------------------------------
// Part 5 - set custom data

for (LinkedList<StateCustomData*>::Itenerator it = saveState.customData.begin(); it.valid(); it.next())
for (LinkedList<StateCustomData*>::Itenerator it = stateSave.customData.begin(); it.valid(); it.next())
{
const StateCustomData* const stateCustomData(it.getValue());
const char* const key(stateCustomData->key);
@@ -833,22 +833,22 @@ void CarlaPlugin::loadSaveState(const SaveState& saveState)
// ---------------------------------------------------------------
// Part 6 - set chunk

if (saveState.chunk != nullptr && (pData->options & PLUGIN_OPTION_USE_CHUNKS) != 0)
setChunkData(saveState.chunk);
if (stateSave.chunk != nullptr && (pData->options & PLUGIN_OPTION_USE_CHUNKS) != 0)
setChunkData(stateSave.chunk);

// ---------------------------------------------------------------
// Part 6 - set internal stuff

#ifndef BUILD_BRIDGE
setDryWet(saveState.dryWet, true, true);
setVolume(saveState.volume, true, true);
setBalanceLeft(saveState.balanceLeft, true, true);
setBalanceRight(saveState.balanceRight, true, true);
setPanning(saveState.panning, true, true);
setCtrlChannel(saveState.ctrlChannel, true, true);
setDryWet(stateSave.dryWet, true, true);
setVolume(stateSave.volume, true, true);
setBalanceLeft(stateSave.balanceLeft, true, true);
setBalanceRight(stateSave.balanceRight, true, true);
setPanning(stateSave.panning, true, true);
setCtrlChannel(stateSave.ctrlChannel, true, true);
#endif

setActive(saveState.active, true, true);
setActive(stateSave.active, true, true);
}

bool CarlaPlugin::saveStateToFile(const char* const filename)
@@ -861,14 +861,11 @@ bool CarlaPlugin::saveStateToFile(const char* const filename)
if (! file.open(QIODevice::WriteOnly | QIODevice::Text))
return false;

QString content;
fillXmlStringFromSaveState(content, getSaveState());

QTextStream out(&file);
out << "<?xml version='1.0' encoding='UTF-8'?>\n";
out << "<!DOCTYPE CARLA-PRESET>\n";
out << "<CARLA-PRESET VERSION='2.0'>\n";
out << content;
out << getStateSave().toString();
out << "</CARLA-PRESET>\n";

file.close();
@@ -897,9 +894,8 @@ bool CarlaPlugin::loadStateFromFile(const char* const filename)
return false;
}

pData->saveState.reset();
fillSaveStateFromXmlNode(pData->saveState, xmlNode);
loadSaveState(pData->saveState);
pData->stateSave.fillFromXmlNode(xmlNode);
loadStateSave(pData->stateSave);

return true;
}


+ 1
- 1
source/backend/plugin/CarlaPluginInternal.hpp View File

@@ -257,7 +257,7 @@ struct CarlaPlugin::ProtectedData {
PluginMidiProgramData midiprog;
LinkedList<CustomData> custom;

SaveState saveState;
StateSave stateSave;

CarlaMutex masterMutex; // global master lock
CarlaMutex singleMutex; // small lock used only in processSingle()


+ 2
- 4
source/tests/CarlaUtils4.cpp View File

@@ -50,13 +50,11 @@ int main()
{
state_juce::StateSave jsave;
jsave.type = carla_strdup("NONE");
juce::String js;
state_juce::fillXmlStringFromStateSave(js, jsave);
carla_stdout(jsave.toString().toRawUTF8());

state_qt::StateSave qsave;
qsave.type = carla_strdup("NONE");
QString qs;
state_qt::fillXmlStringFromStateSave(qs, qsave);
carla_stdout(qsave.toString().toUtf8().constData());

return 0;
}


+ 256
- 244
source/utils/CarlaStateUtils.cpp View File

@@ -32,6 +32,46 @@ using juce::XmlElement;

CARLA_BACKEND_START_NAMESPACE

// -----------------------------------------------------------------------
// xmlSafeString

#ifdef HAVE_JUCE_LATER
static String xmlSafeString(const String& string, const bool toXml)
{
String newString(string);

if (toXml)
return newString.replace("&","&amp;").replace("<","&lt;").replace(">","&gt;").replace("'","&apos;").replace("\"","&quot;");
else
return newString.replace("&lt;","<").replace("&gt;",">").replace("&apos;","'").replace("&quot;","\"").replace("&amp;","&");
}
#else
static QString xmlSafeString(const QString& string, const bool toXml)
{
QString newString(string);

if (toXml)
return newString.replace("&","&amp;").replace("<","&lt;").replace(">","&gt;").replace("'","&apos;").replace("\"","&quot;");
else
return newString.replace("&lt;","<").replace("&gt;",">").replace("&apos;","'").replace("&quot;","\"").replace("&amp;","&");
}
#endif

// -----------------------------------------------------------------------
// xmlSafeStringCharDup

#ifdef HAVE_JUCE_LATER
static const char* xmlSafeStringCharDup(const String& string, const bool toXml)
{
return carla_strdup(xmlSafeString(string, toXml).toRawUTF8());
}
#else
static const char* xmlSafeStringCharDup(const QString& string, const bool toXml)
{
return carla_strdup(xmlSafeString(string, toXml).toUtf8().constData());
}
#endif

// -----------------------------------------------------------------------
// StateParameter

@@ -109,10 +149,10 @@ StateSave::StateSave() noexcept

StateSave::~StateSave() noexcept
{
reset();
clear();
}

void StateSave::reset() noexcept
void StateSave::clear() noexcept
{
if (type != nullptr)
{
@@ -174,51 +214,13 @@ void StateSave::reset() noexcept
}

// -----------------------------------------------------------------------
// xmlSafeString

#ifdef HAVE_JUCE_LATER
static String xmlSafeString(const String& string, const bool toXml)
{
String newString(string);

if (toXml)
return newString.replace("&","&amp;").replace("<","&lt;").replace(">","&gt;").replace("'","&apos;").replace("\"","&quot;");
else
return newString.replace("&lt;","<").replace("&gt;",">").replace("&apos;","'").replace("&quot;","\"").replace("&amp;","&");
}
#else
static QString xmlSafeString(const QString& string, const bool toXml)
{
QString newString(string);

if (toXml)
return newString.replace("&","&amp;").replace("<","&lt;").replace(">","&gt;").replace("'","&apos;").replace("\"","&quot;");
else
return newString.replace("&lt;","<").replace("&gt;",">").replace("&apos;","'").replace("&quot;","\"").replace("&amp;","&");
}
#endif

// -----------------------------------------------------------------------
// xmlSafeStringCharDup
// fillFromXmlElement

#ifdef HAVE_JUCE_LATER
static const char* xmlSafeStringCharDup(const String& string, const bool toXml)
{
return carla_strdup(xmlSafeString(string, toXml).toRawUTF8());
}
#else
static const char* xmlSafeStringCharDup(const QString& string, const bool toXml)
void StateSave::fillFromXmlElement(const XmlElement* const xmlElement)
{
return carla_strdup(xmlSafeString(string, toXml).toUtf8().constData());
}
#endif

// -----------------------------------------------------------------------
// fillStateSaveFromXmlNode
clear();

#ifdef HAVE_JUCE_LATER
void fillStateSaveFromXmlElement(StateSave& stateSave, const XmlElement* const xmlElement)
{
CARLA_SAFE_ASSERT_RETURN(xmlElement != nullptr,);

for (XmlElement* elem = xmlElement->getFirstChildElement(); elem != nullptr; elem = elem->getNextElement())
@@ -236,15 +238,15 @@ void fillStateSaveFromXmlElement(StateSave& stateSave, const XmlElement* const x
const String text(xmlInfo->getAllSubText().trim());

if (tag.equalsIgnoreCase("type"))
stateSave.type = xmlSafeStringCharDup(text, false);
type = xmlSafeStringCharDup(text, false);
else if (tag.equalsIgnoreCase("name"))
stateSave.name = xmlSafeStringCharDup(text, false);
name = xmlSafeStringCharDup(text, false);
else if (tag.equalsIgnoreCase("label") || tag.equalsIgnoreCase("uri"))
stateSave.label = xmlSafeStringCharDup(text, false);
label = xmlSafeStringCharDup(text, false);
else if (tag.equalsIgnoreCase("binary") || tag.equalsIgnoreCase("bundle") || tag.equalsIgnoreCase("filename"))
stateSave.binary = xmlSafeStringCharDup(text, false);
binary = xmlSafeStringCharDup(text, false);
else if (tag.equalsIgnoreCase("uniqueid"))
stateSave.uniqueId = text.getLargeIntValue();
uniqueId = text.getLargeIntValue();
}
}

@@ -263,33 +265,33 @@ void fillStateSaveFromXmlElement(StateSave& stateSave, const XmlElement* const x

if (tag.equalsIgnoreCase("active"))
{
stateSave.active = (text.equalsIgnoreCase("yes") || text.equalsIgnoreCase("true"));
active = (text.equalsIgnoreCase("yes") || text.equalsIgnoreCase("true"));
}
else if (tag.equalsIgnoreCase("drywet"))
{
stateSave.dryWet = carla_fixValue(0.0f, 1.0f, text.getFloatValue());
dryWet = carla_fixValue(0.0f, 1.0f, text.getFloatValue());
}
else if (tag.equalsIgnoreCase("volume"))
{
stateSave.volume = carla_fixValue(0.0f, 1.27f, text.getFloatValue());
volume = carla_fixValue(0.0f, 1.27f, text.getFloatValue());
}
else if (tag.equalsIgnoreCase("balanceleft") || tag.equalsIgnoreCase("balance-left"))
{
stateSave.balanceLeft = carla_fixValue(-1.0f, 1.0f, text.getFloatValue());
balanceLeft = carla_fixValue(-1.0f, 1.0f, text.getFloatValue());
}
else if (tag.equalsIgnoreCase("balanceright") || tag.equalsIgnoreCase("balance-right"))
{
stateSave.balanceRight = carla_fixValue(-1.0f, 1.0f, text.getFloatValue());
balanceRight = carla_fixValue(-1.0f, 1.0f, text.getFloatValue());
}
else if (tag.equalsIgnoreCase("panning"))
{
stateSave.panning = carla_fixValue(-1.0f, 1.0f, text.getFloatValue());
panning = carla_fixValue(-1.0f, 1.0f, text.getFloatValue());
}
else if (tag.equalsIgnoreCase("controlchannel") || tag.equalsIgnoreCase("control-channel"))
{
const int value(text.getIntValue());
if (value >= 1 && value <= MAX_MIDI_CHANNELS)
stateSave.ctrlChannel = static_cast<int8_t>(value-1);
ctrlChannel = static_cast<int8_t>(value-1);
}

// -------------------------------------------------------
@@ -299,11 +301,11 @@ void fillStateSaveFromXmlElement(StateSave& stateSave, const XmlElement* const x
{
const int value(text.getIntValue());
if (value >= 1)
stateSave.currentProgramIndex = value-1;
currentProgramIndex = value-1;
}
else if (tag.equalsIgnoreCase("currentprogramname") || tag.equalsIgnoreCase("current-program-name"))
{
stateSave.currentProgramName = xmlSafeStringCharDup(text, false);
currentProgramName = xmlSafeStringCharDup(text, false);
}

// -------------------------------------------------------
@@ -313,13 +315,13 @@ void fillStateSaveFromXmlElement(StateSave& stateSave, const XmlElement* const x
{
const int value(text.getIntValue());
if (value >= 1)
stateSave.currentMidiBank = value-1;
currentMidiBank = value-1;
}
else if (tag.equalsIgnoreCase("currentmidiprogram") || tag.equalsIgnoreCase("current-midi-program"))
{
const int value(text.getIntValue());
if (value >= 1)
stateSave.currentMidiProgram = value-1;
currentMidiProgram = value-1;
}

// -------------------------------------------------------
@@ -366,7 +368,7 @@ void fillStateSaveFromXmlElement(StateSave& stateSave, const XmlElement* const x
}
}

stateSave.parameters.append(stateParameter);
parameters.append(stateParameter);
}

// -------------------------------------------------------
@@ -389,7 +391,7 @@ void fillStateSaveFromXmlElement(StateSave& stateSave, const XmlElement* const x
stateCustomData->value = xmlSafeStringCharDup(cText, false);
}

stateSave.customData.append(stateCustomData);
customData.append(stateCustomData);
}

// -------------------------------------------------------
@@ -397,15 +399,17 @@ void fillStateSaveFromXmlElement(StateSave& stateSave, const XmlElement* const x

else if (tag.equalsIgnoreCase("chunk"))
{
stateSave.chunk = xmlSafeStringCharDup(text, false);
chunk = xmlSafeStringCharDup(text, false);
}
}
}
}
}
#else
void fillStateSaveFromXmlNode(StateSave& stateSave, const QDomNode& xmlNode)
void StateSave::fillFromXmlNode(const QDomNode& xmlNode)
{
clear();

CARLA_SAFE_ASSERT_RETURN(! xmlNode.isNull(),);

for (QDomNode node = xmlNode.firstChild(); ! node.isNull(); node = node.nextSibling())
@@ -424,25 +428,25 @@ void fillStateSaveFromXmlNode(StateSave& stateSave, const QDomNode& xmlNode)

if (tag.compare("type", Qt::CaseInsensitive) == 0)
{
stateSave.type = xmlSafeStringCharDup(text, false);
type = xmlSafeStringCharDup(text, false);
}
else if (tag.compare("name", Qt::CaseInsensitive) == 0)
{
stateSave.name = xmlSafeStringCharDup(text, false);
name = xmlSafeStringCharDup(text, false);
}
else if (tag.compare("label", Qt::CaseInsensitive) == 0 || tag.compare("uri", Qt::CaseInsensitive) == 0)
{
stateSave.label = xmlSafeStringCharDup(text, false);
label = xmlSafeStringCharDup(text, false);
}
else if (tag.compare("binary", Qt::CaseInsensitive) == 0 || tag.compare("bundle", Qt::CaseInsensitive) == 0 || tag.compare("filename", Qt::CaseInsensitive) == 0)
{
stateSave.binary = xmlSafeStringCharDup(text, false);
binary = xmlSafeStringCharDup(text, false);
}
else if (tag.compare("uniqueid", Qt::CaseInsensitive) == 0)
{
bool ok;
const qlonglong uniqueId(text.toLongLong(&ok));
if (ok) stateSave.uniqueId = static_cast<int64_t>(uniqueId);
const qlonglong uniqueIdTry(text.toLongLong(&ok));
if (ok) uniqueId = static_cast<int64_t>(uniqueIdTry);
}
}
}
@@ -462,44 +466,44 @@ void fillStateSaveFromXmlNode(StateSave& stateSave, const QDomNode& xmlNode)

if (tag.compare("active", Qt::CaseInsensitive) == 0)
{
stateSave.active = (text.compare("yes", Qt::CaseInsensitive) == 0 || text.compare("true", Qt::CaseInsensitive) == 0);
active = (text.compare("yes", Qt::CaseInsensitive) == 0 || text.compare("true", Qt::CaseInsensitive) == 0);
}
else if (tag.compare("drywet", Qt::CaseInsensitive) == 0)
{
bool ok;
const float value(text.toFloat(&ok));
if (ok) stateSave.dryWet = carla_fixValue(0.0f, 1.0f, value);
if (ok) dryWet = carla_fixValue(0.0f, 1.0f, value);
}
else if (tag.compare("volume", Qt::CaseInsensitive) == 0)
{
bool ok;
const float value(text.toFloat(&ok));
if (ok) stateSave.volume = carla_fixValue(0.0f, 1.27f, value);
if (ok) volume = carla_fixValue(0.0f, 1.27f, value);
}
else if (tag.compare("balanceleft", Qt::CaseInsensitive) == 0 || tag.compare("balance-left", Qt::CaseInsensitive) == 0)
{
bool ok;
const float value(text.toFloat(&ok));
if (ok) stateSave.balanceLeft = carla_fixValue(-1.0f, 1.0f, value);
if (ok) balanceLeft = carla_fixValue(-1.0f, 1.0f, value);
}
else if (tag.compare("balanceright", Qt::CaseInsensitive) == 0 || tag.compare("balance-right", Qt::CaseInsensitive) == 0)
{
bool ok;
const float value(text.toFloat(&ok));
if (ok) stateSave.balanceRight = carla_fixValue(-1.0f, 1.0f, value);
if (ok) balanceRight = carla_fixValue(-1.0f, 1.0f, value);
}
else if (tag.compare("panning", Qt::CaseInsensitive) == 0)
{
bool ok;
const float value(text.toFloat(&ok));
if (ok) stateSave.panning = carla_fixValue(-1.0f, 1.0f, value);
if (ok) panning = carla_fixValue(-1.0f, 1.0f, value);
}
else if (tag.compare("controlchannel", Qt::CaseInsensitive) == 0 || tag.compare("control-channel", Qt::CaseInsensitive) == 0)
{
bool ok;
const short value(text.toShort(&ok));
if (ok && value >= 1 && value <= MAX_MIDI_CHANNELS)
stateSave.ctrlChannel = static_cast<int8_t>(value-1);
ctrlChannel = static_cast<int8_t>(value-1);
}

// -------------------------------------------------------
@@ -510,11 +514,11 @@ void fillStateSaveFromXmlNode(StateSave& stateSave, const QDomNode& xmlNode)
bool ok;
const int value(text.toInt(&ok));
if (ok && value >= 1)
stateSave.currentProgramIndex = value-1;
currentProgramIndex = value-1;
}
else if (tag.compare("currentprogramname", Qt::CaseInsensitive) == 0 || tag.compare("current-program-name", Qt::CaseInsensitive) == 0)
{
stateSave.currentProgramName = xmlSafeStringCharDup(text, false);
currentProgramName = xmlSafeStringCharDup(text, false);
}

// -------------------------------------------------------
@@ -525,14 +529,14 @@ void fillStateSaveFromXmlNode(StateSave& stateSave, const QDomNode& xmlNode)
bool ok;
const int value(text.toInt(&ok));
if (ok && value >= 1)
stateSave.currentMidiBank = value-1;
currentMidiBank = value-1;
}
else if (tag.compare("currentmidiprogram", Qt::CaseInsensitive) == 0 || tag.compare("current-midi-program", Qt::CaseInsensitive) == 0)
{
bool ok;
const int value(text.toInt(&ok));
if (ok && value >= 1)
stateSave.currentMidiProgram = value-1;
currentMidiProgram = value-1;
}

// -------------------------------------------------------
@@ -583,7 +587,7 @@ void fillStateSaveFromXmlNode(StateSave& stateSave, const QDomNode& xmlNode)
}
}

stateSave.parameters.append(stateParameter);
parameters.append(stateParameter);
}

// -------------------------------------------------------
@@ -606,7 +610,7 @@ void fillStateSaveFromXmlNode(StateSave& stateSave, const QDomNode& xmlNode)
stateCustomData->value = xmlSafeStringCharDup(cText, false);
}

stateSave.customData.append(stateCustomData);
customData.append(stateCustomData);
}

// -------------------------------------------------------
@@ -614,7 +618,7 @@ void fillStateSaveFromXmlNode(StateSave& stateSave, const QDomNode& xmlNode)

else if (tag.compare("chunk", Qt::CaseInsensitive) == 0)
{
stateSave.chunk = xmlSafeStringCharDup(text, false);
chunk = xmlSafeStringCharDup(text, false);
}
}
}
@@ -626,353 +630,361 @@ void fillStateSaveFromXmlNode(StateSave& stateSave, const QDomNode& xmlNode)
// fillXmlStringFromStateSave

#ifdef HAVE_JUCE_LATER
void fillXmlStringFromStateSave(String& content, const StateSave& stateSave)
String StateSave::toString() const
{
String content;

{
String info(" <Info>\n");
String infoXml(" <Info>\n");

info << " <Type>" << String(stateSave.type != nullptr ? stateSave.type : "") << "</Type>\n";
info << " <Name>" << xmlSafeString(stateSave.name, true) << "</Name>\n";
infoXml << " <Type>" << String(type != nullptr ? type : "") << "</Type>\n";
infoXml << " <Name>" << xmlSafeString(name, true) << "</Name>\n";

switch (getPluginTypeFromString(stateSave.type))
switch (getPluginTypeFromString(type))
{
case PLUGIN_NONE:
break;
case PLUGIN_INTERNAL:
info << " <Label>" << xmlSafeString(stateSave.label, true) << "</Label>\n";
infoXml << " <Label>" << xmlSafeString(label, true) << "</Label>\n";
break;
case PLUGIN_LADSPA:
info << " <Binary>" << xmlSafeString(stateSave.binary, true) << "</Binary>\n";
info << " <Label>" << xmlSafeString(stateSave.label, true) << "</Label>\n";
info << " <UniqueID>" << stateSave.uniqueId << "</UniqueID>\n";
infoXml << " <Binary>" << xmlSafeString(binary, true) << "</Binary>\n";
infoXml << " <Label>" << xmlSafeString(label, true) << "</Label>\n";
infoXml << " <UniqueID>" << uniqueId << "</UniqueID>\n";
break;
case PLUGIN_DSSI:
info << " <Binary>" << xmlSafeString(stateSave.binary, true) << "</Binary>\n";
info << " <Label>" << xmlSafeString(stateSave.label, true) << "</Label>\n";
infoXml << " <Binary>" << xmlSafeString(binary, true) << "</Binary>\n";
infoXml << " <Label>" << xmlSafeString(label, true) << "</Label>\n";
break;
case PLUGIN_LV2:
info << " <Bundle>" << xmlSafeString(stateSave.binary, true) << "</Bundle>\n";
info << " <URI>" << xmlSafeString(stateSave.label, true) << "</URI>\n";
infoXml << " <Bundle>" << xmlSafeString(binary, true) << "</Bundle>\n";
infoXml << " <URI>" << xmlSafeString(label, true) << "</URI>\n";
break;
case PLUGIN_VST:
info << " <Binary>" << xmlSafeString(stateSave.binary, true) << "</Binary>\n";
info << " <UniqueID>" << stateSave.uniqueId << "</UniqueID>\n";
infoXml << " <Binary>" << xmlSafeString(binary, true) << "</Binary>\n";
infoXml << " <UniqueID>" << uniqueId << "</UniqueID>\n";
break;
case PLUGIN_VST3:
// TODO?
info << " <Binary>" << xmlSafeString(stateSave.binary, true) << "</Binary>\n";
info << " <UniqueID>" << stateSave.uniqueId << "</UniqueID>\n";
infoXml << " <Binary>" << xmlSafeString(binary, true) << "</Binary>\n";
infoXml << " <UniqueID>" << uniqueId << "</UniqueID>\n";
break;
case PLUGIN_AU:
// TODO?
info << " <Binary>" << xmlSafeString(stateSave.binary, true) << "</Binary>\n";
info << " <UniqueID>" << stateSave.uniqueId << "</UniqueID>\n";
infoXml << " <Binary>" << xmlSafeString(binary, true) << "</Binary>\n";
infoXml << " <UniqueID>" << uniqueId << "</UniqueID>\n";
break;
case PLUGIN_JACK:
info << " <Binary>" << xmlSafeString(stateSave.binary, true) << "</Binary>\n";
infoXml << " <Binary>" << xmlSafeString(binary, true) << "</Binary>\n";
break;
case PLUGIN_REWIRE:
info << " <Label>" << xmlSafeString(stateSave.label, true) << "</Label>\n";
infoXml << " <Label>" << xmlSafeString(label, true) << "</Label>\n";
break;
case PLUGIN_FILE_CSD:
case PLUGIN_FILE_GIG:
case PLUGIN_FILE_SF2:
case PLUGIN_FILE_SFZ:
info << " <Filename>" << xmlSafeString(stateSave.binary, true) << "</Filename>\n";
info << " <Label>" << xmlSafeString(stateSave.label, true) << "</Label>\n";
infoXml << " <Filename>" << xmlSafeString(binary, true) << "</Filename>\n";
infoXml << " <Label>" << xmlSafeString(label, true) << "</Label>\n";
break;
}

info << " </Info>\n\n";
infoXml << " </Info>\n\n";

content << info;
content << infoXml;
}

content << " <Data>\n";

{
String data;
data << " <Active>" << (stateSave.active ? "Yes" : "No") << "</Active>\n";
if (stateSave.dryWet != 1.0f)
data << " <DryWet>" << stateSave.dryWet << "</DryWet>\n";
if (stateSave.volume != 1.0f)
data << " <Volume>" << stateSave.volume << "</Volume>\n";
if (stateSave.balanceLeft != -1.0f)
data << " <Balance-Left>" << stateSave.balanceLeft << "</Balance-Left>\n";
if (stateSave.balanceRight != 1.0f)
data << " <Balance-Right>" << stateSave.balanceRight << "</Balance-Right>\n";
if (stateSave.panning != 0.0f)
data << " <Panning>" << stateSave.panning << "</Panning>\n";
if (stateSave.ctrlChannel < 0)
data << " <ControlChannel>N</ControlChannel>\n";
String dataXml;
dataXml << " <Active>" << (active ? "Yes" : "No") << "</Active>\n";
if (dryWet != 1.0f)
dataXml << " <DryWet>" << dryWet << "</DryWet>\n";
if (volume != 1.0f)
dataXml << " <Volume>" << volume << "</Volume>\n";
if (balanceLeft != -1.0f)
dataXml << " <Balance-Left>" << balanceLeft << "</Balance-Left>\n";
if (balanceRight != 1.0f)
dataXml << " <Balance-Right>" << balanceRight << "</Balance-Right>\n";
if (panning != 0.0f)
dataXml << " <Panning>" << panning << "</Panning>\n";
if (ctrlChannel < 0)
dataXml << " <ControlChannel>N</ControlChannel>\n";
else
data << " <ControlChannel>" << int(stateSave.ctrlChannel+1) << "</ControlChannel>\n";
dataXml << " <ControlChannel>" << int(ctrlChannel+1) << "</ControlChannel>\n";

content << data;
content << dataXml;
}

for (StateParameterItenerator it = stateSave.parameters.begin(); it.valid(); it.next())
for (StateParameterItenerator it = parameters.begin(); it.valid(); it.next())
{
StateParameter* const stateParameter(it.getValue());

String parameter("\n"" <Parameter>\n");
String parameterXml("\n"" <Parameter>\n");

parameter << " <Index>" << String(stateParameter->index) << "</Index>\n";
parameter << " <Name>" << xmlSafeString(stateParameter->name, true) << "</Name>\n";
parameterXml << " <Index>" << String(stateParameter->index) << "</Index>\n";
parameterXml << " <Name>" << xmlSafeString(stateParameter->name, true) << "</Name>\n";

if (stateParameter->symbol != nullptr && stateParameter->symbol[0] != '\0')
parameter << " <Symbol>" << xmlSafeString(stateParameter->symbol, true) << "</Symbol>\n";
parameterXml << " <Symbol>" << xmlSafeString(stateParameter->symbol, true) << "</Symbol>\n";

if (stateParameter->isInput)
parameter << " <Value>" << stateParameter->value << "</Value>\n";
parameterXml << " <Value>" << stateParameter->value << "</Value>\n";

if (stateParameter->midiCC > 0)
{
parameter << " <MidiCC>" << stateParameter->midiCC << "</MidiCC>\n";
parameter << " <MidiChannel>" << stateParameter->midiChannel+1 << "</MidiChannel>\n";
parameterXml << " <MidiCC>" << stateParameter->midiCC << "</MidiCC>\n";
parameterXml << " <MidiChannel>" << stateParameter->midiChannel+1 << "</MidiChannel>\n";
}

parameter << " </Parameter>\n";
parameterXml << " </Parameter>\n";

content << parameter;
content << parameterXml;
}

if (stateSave.currentProgramIndex >= 0 && stateSave.currentProgramName != nullptr && stateSave.currentProgramName[0] != '\0')
if (currentProgramIndex >= 0 && currentProgramName != nullptr && currentProgramName[0] != '\0')
{
// ignore 'default' program
if (stateSave.currentProgramIndex > 0 || ! String(stateSave.currentProgramName).equalsIgnoreCase("default"))
if (currentProgramIndex > 0 || ! String(currentProgramName).equalsIgnoreCase("default"))
{
String program("\n");
program << " <CurrentProgramIndex>" << stateSave.currentProgramIndex+1 << "</CurrentProgramIndex>\n";
program << " <CurrentProgramName>" << xmlSafeString(stateSave.currentProgramName, true) << "</CurrentProgramName>\n";
String programXml("\n");
programXml << " <CurrentProgramIndex>" << currentProgramIndex+1 << "</CurrentProgramIndex>\n";
programXml << " <CurrentProgramName>" << xmlSafeString(currentProgramName, true) << "</CurrentProgramName>\n";

content << program;
content << programXml;
}
}

if (stateSave.currentMidiBank >= 0 && stateSave.currentMidiProgram >= 0)
if (currentMidiBank >= 0 && currentMidiProgram >= 0)
{
String midiProgram("\n");
midiProgram << " <CurrentMidiBank>" << stateSave.currentMidiBank+1 << "</CurrentMidiBank>\n";
midiProgram << " <CurrentMidiProgram>" << stateSave.currentMidiProgram+1 << "</CurrentMidiProgram>\n";
String midiProgramXml("\n");
midiProgramXml << " <CurrentMidiBank>" << currentMidiBank+1 << "</CurrentMidiBank>\n";
midiProgramXml << " <CurrentMidiProgram>" << currentMidiProgram+1 << "</CurrentMidiProgram>\n";

content << midiProgram;
content << midiProgramXml;
}

for (StateCustomDataItenerator it = stateSave.customData.begin(); it.valid(); it.next())
for (StateCustomDataItenerator it = customData.begin(); it.valid(); it.next())
{
StateCustomData* const stateCustomData(it.getValue());
CARLA_SAFE_ASSERT_CONTINUE(stateCustomData->type != nullptr && stateCustomData->type[0] != '\0');
CARLA_SAFE_ASSERT_CONTINUE(stateCustomData->key != nullptr && stateCustomData->key[0] != '\0');
CARLA_SAFE_ASSERT_CONTINUE(stateCustomData->value != nullptr);

String customData("\n"" <CustomData>\n");
customData << " <Type>" << xmlSafeString(stateCustomData->type, true) << "</Type>\n";
customData << " <Key>" << xmlSafeString(stateCustomData->key, true) << "</Key>\n";
String customDataXml("\n"" <CustomData>\n");
customDataXml << " <Type>" << xmlSafeString(stateCustomData->type, true) << "</Type>\n";
customDataXml << " <Key>" << xmlSafeString(stateCustomData->key, true) << "</Key>\n";

if (std::strcmp(stateCustomData->type, CUSTOM_DATA_TYPE_CHUNK) == 0 || std::strlen(stateCustomData->value) >= 128)
{
customData << " <Value>\n";
customData << xmlSafeString(stateCustomData->value, true);
customData << " </Value>\n";
customDataXml << " <Value>\n";
customDataXml << xmlSafeString(stateCustomData->value, true);
customDataXml << " </Value>\n";
}
else
{
customData << " <Value>";
customData << xmlSafeString(stateCustomData->value, true);
customData << "</Value>\n";
customDataXml << " <Value>";
customDataXml << xmlSafeString(stateCustomData->value, true);
customDataXml << "</Value>\n";
}

customData << " </CustomData>\n";
customDataXml << " </CustomData>\n";

content << customData;
content << customDataXml;
}

if (stateSave.chunk != nullptr && stateSave.chunk[0] != '\0')
if (chunk != nullptr && chunk[0] != '\0')
{
String chunk("\n"" <Chunk>\n");
chunk << stateSave.chunk << "\n </Chunk>\n";
String chunkXml("\n"" <Chunk>\n");
chunkXml << chunk << "\n </Chunk>\n";

content << chunk;
content << chunkXml;
}

content << " </Data>\n";

return content;
}
#else
void fillXmlStringFromStateSave(QString& content, const StateSave& stateSave)
QString StateSave::toString() const
{
QString content;

{
QString info(" <Info>\n");
QString infoXml(" <Info>\n");

info += QString(" <Type>%1</Type>\n").arg((stateSave.type != nullptr) ? stateSave.type : "");
info += QString(" <Name>%1</Name>\n").arg(xmlSafeString(stateSave.name, true));
infoXml += QString(" <Type>%1</Type>\n").arg((type != nullptr) ? type : "");
infoXml += QString(" <Name>%1</Name>\n").arg(xmlSafeString(name, true));

switch (getPluginTypeFromString(stateSave.type))
switch (getPluginTypeFromString(type))
{
case PLUGIN_NONE:
break;
case PLUGIN_INTERNAL:
info += QString(" <Label>%1</Label>\n").arg(xmlSafeString(stateSave.label, true));
infoXml += QString(" <Label>%1</Label>\n").arg(xmlSafeString(label, true));
break;
case PLUGIN_LADSPA:
info += QString(" <Binary>%1</Binary>\n").arg(xmlSafeString(stateSave.binary, true));
info += QString(" <Label>%1</Label>\n").arg(xmlSafeString(stateSave.label, true));
info += QString(" <UniqueID>%1</UniqueID>\n").arg(stateSave.uniqueId);
infoXml += QString(" <Binary>%1</Binary>\n").arg(xmlSafeString(binary, true));
infoXml += QString(" <Label>%1</Label>\n").arg(xmlSafeString(label, true));
infoXml += QString(" <UniqueID>%1</UniqueID>\n").arg(uniqueId);
break;
case PLUGIN_DSSI:
info += QString(" <Binary>%1</Binary>\n").arg(xmlSafeString(stateSave.binary, true));
info += QString(" <Label>%1</Label>\n").arg(xmlSafeString(stateSave.label, true));
infoXml += QString(" <Binary>%1</Binary>\n").arg(xmlSafeString(binary, true));
infoXml += QString(" <Label>%1</Label>\n").arg(xmlSafeString(label, true));
break;
case PLUGIN_LV2:
info += QString(" <Bundle>%1</Bundle>\n").arg(xmlSafeString(stateSave.binary, true));
info += QString(" <URI>%1</URI>\n").arg(xmlSafeString(stateSave.label, true));
infoXml += QString(" <Bundle>%1</Bundle>\n").arg(xmlSafeString(binary, true));
infoXml += QString(" <URI>%1</URI>\n").arg(xmlSafeString(label, true));
break;
case PLUGIN_VST:
info += QString(" <Binary>%1</Binary>\n").arg(xmlSafeString(stateSave.binary, true));
info += QString(" <UniqueID>%1</UniqueID>\n").arg(stateSave.uniqueId);
infoXml += QString(" <Binary>%1</Binary>\n").arg(xmlSafeString(binary, true));
infoXml += QString(" <UniqueID>%1</UniqueID>\n").arg(uniqueId);
break;
case PLUGIN_VST3:
// TODO?
info += QString(" <Binary>%1</Binary>\n").arg(xmlSafeString(stateSave.binary, true));
info += QString(" <UniqueID>%1</UniqueID>\n").arg(stateSave.uniqueId);
infoXml += QString(" <Binary>%1</Binary>\n").arg(xmlSafeString(binary, true));
infoXml += QString(" <UniqueID>%1</UniqueID>\n").arg(uniqueId);
break;
case PLUGIN_AU:
// TODO?
info += QString(" <Binary>%1</Binary>\n").arg(xmlSafeString(stateSave.binary, true));
info += QString(" <UniqueID>%1</UniqueID>\n").arg(stateSave.uniqueId);
infoXml += QString(" <Binary>%1</Binary>\n").arg(xmlSafeString(binary, true));
infoXml += QString(" <UniqueID>%1</UniqueID>\n").arg(uniqueId);
break;
case PLUGIN_JACK:
info += QString(" <Binary>%1</Binary>\n").arg(xmlSafeString(stateSave.binary, true));
infoXml += QString(" <Binary>%1</Binary>\n").arg(xmlSafeString(binary, true));
break;
case PLUGIN_REWIRE:
info += QString(" <Label>%1</Label>\n").arg(xmlSafeString(stateSave.label, true));
infoXml += QString(" <Label>%1</Label>\n").arg(xmlSafeString(label, true));
break;
case PLUGIN_FILE_CSD:
case PLUGIN_FILE_GIG:
case PLUGIN_FILE_SF2:
case PLUGIN_FILE_SFZ:
info += QString(" <Filename>%1</Filename>\n").arg(xmlSafeString(stateSave.binary, true));
info += QString(" <Label>%1</Label>\n").arg(xmlSafeString(stateSave.label, true));
infoXml += QString(" <Filename>%1</Filename>\n").arg(xmlSafeString(binary, true));
infoXml += QString(" <Label>%1</Label>\n").arg(xmlSafeString(label, true));
break;
}

info += " </Info>\n\n";
infoXml += " </Info>\n\n";

content += info;
content += infoXml;
}

content += " <Data>\n";

{
QString data;
data += QString(" <Active>%1</Active>\n").arg(stateSave.active ? "Yes" : "No");
if (stateSave.dryWet != 1.0f)
data += QString(" <DryWet>%1</DryWet>\n").arg(stateSave.dryWet, 0, 'g', 7);
if (stateSave.volume != 1.0f)
data += QString(" <Volume>%1</Volume>\n").arg(stateSave.volume, 0, 'g', 7);
if (stateSave.balanceLeft != -1.0f)
data += QString(" <Balance-Left>%1</Balance-Left>\n").arg(stateSave.balanceLeft, 0, 'g', 7);
if (stateSave.balanceRight != 1.0f)
data += QString(" <Balance-Right>%1</Balance-Right>\n").arg(stateSave.balanceRight, 0, 'g', 7);
if (stateSave.panning != 0.0f)
data += QString(" <Panning>%1</Panning>\n").arg(stateSave.panning, 0, 'g', 7);
if (stateSave.ctrlChannel < 0)
data += QString(" <ControlChannel>N</ControlChannel>\n");
QString dataXml;
dataXml += QString(" <Active>%1</Active>\n").arg(active ? "Yes" : "No");
if (dryWet != 1.0f)
dataXml += QString(" <DryWet>%1</DryWet>\n").arg(dryWet, 0, 'g', 7);
if (volume != 1.0f)
dataXml += QString(" <Volume>%1</Volume>\n").arg(volume, 0, 'g', 7);
if (balanceLeft != -1.0f)
dataXml += QString(" <Balance-Left>%1</Balance-Left>\n").arg(balanceLeft, 0, 'g', 7);
if (balanceRight != 1.0f)
dataXml += QString(" <Balance-Right>%1</Balance-Right>\n").arg(balanceRight, 0, 'g', 7);
if (panning != 0.0f)
dataXml += QString(" <Panning>%1</Panning>\n").arg(panning, 0, 'g', 7);
if (ctrlChannel < 0)
dataXml += QString(" <ControlChannel>N</ControlChannel>\n");
else
data += QString(" <ControlChannel>%1</ControlChannel>\n").arg(stateSave.ctrlChannel+1);
dataXml += QString(" <ControlChannel>%1</ControlChannel>\n").arg(ctrlChannel+1);

content += data;
content += dataXml;
}

for (StateParameterItenerator it = stateSave.parameters.begin(); it.valid(); it.next())
for (StateParameterItenerator it = parameters.begin(); it.valid(); it.next())
{
StateParameter* const stateParameter(it.getValue());

QString parameter("\n"" <Parameter>\n");
QString parameterXml("\n"" <Parameter>\n");

parameter += QString(" <Index>%1</Index>\n").arg(stateParameter->index);
parameter += QString(" <Name>%1</Name>\n").arg(xmlSafeString(stateParameter->name, true));
parameterXml += QString(" <Index>%1</Index>\n").arg(stateParameter->index);
parameterXml += QString(" <Name>%1</Name>\n").arg(xmlSafeString(stateParameter->name, true));

if (stateParameter->symbol != nullptr && stateParameter->symbol[0] != '\0')
parameter += QString(" <Symbol>%1</Symbol>\n").arg(xmlSafeString(stateParameter->symbol, true));
parameterXml += QString(" <Symbol>%1</Symbol>\n").arg(xmlSafeString(stateParameter->symbol, true));

if (stateParameter->isInput)
parameter += QString(" <Value>%1</Value>\n").arg(stateParameter->value, 0, 'g', 15);
parameterXml += QString(" <Value>%1</Value>\n").arg(stateParameter->value, 0, 'g', 15);

if (stateParameter->midiCC > 0)
{
parameter += QString(" <MidiCC>%1</MidiCC>\n").arg(stateParameter->midiCC);
parameter += QString(" <MidiChannel>%1</MidiChannel>\n").arg(stateParameter->midiChannel+1);
parameterXml += QString(" <MidiCC>%1</MidiCC>\n").arg(stateParameter->midiCC);
parameterXml += QString(" <MidiChannel>%1</MidiChannel>\n").arg(stateParameter->midiChannel+1);
}

parameter += " </Parameter>\n";
parameterXml += " </Parameter>\n";

content += parameter;
content += parameterXml;
}

if (stateSave.currentProgramIndex >= 0 && stateSave.currentProgramName != nullptr && stateSave.currentProgramName[0] != '\0')
if (currentProgramIndex >= 0 && currentProgramName != nullptr && currentProgramName[0] != '\0')
{
// ignore 'default' program
if (stateSave.currentProgramIndex > 0 || QString(stateSave.currentProgramName).compare("default", Qt::CaseInsensitive) != 0)
if (currentProgramIndex > 0 || QString(currentProgramName).compare("default", Qt::CaseInsensitive) != 0)
{
QString program("\n");
program += QString(" <CurrentProgramIndex>%1</CurrentProgramIndex>\n").arg(stateSave.currentProgramIndex+1);
program += QString(" <CurrentProgramName>%1</CurrentProgramName>\n").arg(xmlSafeString(stateSave.currentProgramName, true));
QString programXml("\n");
programXml += QString(" <CurrentProgramIndex>%1</CurrentProgramIndex>\n").arg(currentProgramIndex+1);
programXml += QString(" <CurrentProgramName>%1</CurrentProgramName>\n").arg(xmlSafeString(currentProgramName, true));

content += program;
content += programXml;
}
}

if (stateSave.currentMidiBank >= 0 && stateSave.currentMidiProgram >= 0)
if (currentMidiBank >= 0 && currentMidiProgram >= 0)
{
QString midiProgram("\n");
midiProgram += QString(" <CurrentMidiBank>%1</CurrentMidiBank>\n").arg(stateSave.currentMidiBank+1);
midiProgram += QString(" <CurrentMidiProgram>%1</CurrentMidiProgram>\n").arg(stateSave.currentMidiProgram+1);
QString midiProgramXml("\n");
midiProgramXml += QString(" <CurrentMidiBank>%1</CurrentMidiBank>\n").arg(currentMidiBank+1);
midiProgramXml += QString(" <CurrentMidiProgram>%1</CurrentMidiProgram>\n").arg(currentMidiProgram+1);

content += midiProgram;
content += midiProgramXml;
}

for (StateCustomDataItenerator it = stateSave.customData.begin(); it.valid(); it.next())
for (StateCustomDataItenerator it = customData.begin(); it.valid(); it.next())
{
StateCustomData* const stateCustomData(it.getValue());
CARLA_SAFE_ASSERT_CONTINUE(stateCustomData->type != nullptr && stateCustomData->type[0] != '\0');
CARLA_SAFE_ASSERT_CONTINUE(stateCustomData->key != nullptr && stateCustomData->key[0] != '\0');
CARLA_SAFE_ASSERT_CONTINUE(stateCustomData->value != nullptr);

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));
QString customDataXml("\n"" <CustomData>\n");
customDataXml += QString(" <Type>%1</Type>\n").arg(xmlSafeString(stateCustomData->type, true));
customDataXml += QString(" <Key>%1</Key>\n").arg(xmlSafeString(stateCustomData->key, true));

if (std::strcmp(stateCustomData->type, CUSTOM_DATA_TYPE_CHUNK) == 0 || std::strlen(stateCustomData->value) >= 128)
{
customData += " <Value>\n";
customData += QString("%1\n").arg(xmlSafeString(stateCustomData->value, true));
customData += " </Value>\n";
customDataXml += " <Value>\n";
customDataXml += QString("%1\n").arg(xmlSafeString(stateCustomData->value, true));
customDataXml += " </Value>\n";
}
else
customData += QString(" <Value>%1</Value>\n").arg(xmlSafeString(stateCustomData->value, true));
customDataXml += QString(" <Value>%1</Value>\n").arg(xmlSafeString(stateCustomData->value, true));

customData += " </CustomData>\n";
customDataXml += " </CustomData>\n";

content += customData;
content += customDataXml;
}

if (stateSave.chunk != nullptr && stateSave.chunk[0] != '\0')
if (chunk != nullptr && chunk[0] != '\0')
{
QString chunk("\n"" <Chunk>\n");
chunk += QString("%1\n").arg(stateSave.chunk);
chunk += " </Chunk>\n";
QString chunkXml("\n"" <Chunk>\n");
chunkXml += QString("%1\n").arg(chunk);
chunkXml += " </Chunk>\n";

content += chunk;
content += chunkXml;
}

content += " </Data>\n";

return content;
}
#endif



+ 11
- 9
source/utils/CarlaStateUtils.hpp View File

@@ -99,21 +99,23 @@ struct StateSave {

StateSave() noexcept;
~StateSave() noexcept;
void reset() noexcept;
void clear() noexcept;

CARLA_DECLARE_NON_COPY_STRUCT(StateSave)
};

// -----------------------------------------------------------------------
#ifdef HAVE_JUCE_LATER
void fillFromXmlElement(const juce::XmlElement* const xmlElement);
#else
void fillFromXmlNode(const QDomNode& xmlNode);
#endif

#ifdef HAVE_JUCE_LATER
void fillStateSaveFromXmlElement(StateSave& stateSave, const juce::XmlElement* const xmlElement);
void fillXmlStringFromStateSave(juce::String& content, const StateSave& stateSave);
juce::String toString() const;
#else
void fillStateSaveFromXmlNode(StateSave& stateSave, const QDomNode& xmlNode);
void fillXmlStringFromStateSave(QString& content, const StateSave& stateSave);
QString toString() const;
#endif

CARLA_DECLARE_NON_COPY_STRUCT(StateSave)
};

// -----------------------------------------------------------------------

CARLA_BACKEND_END_NAMESPACE


Loading…
Cancel
Save