| @@ -6,15 +6,15 @@ | |||
| include ../../Makefile.mk | |||
| # -------------------------------------------------------------- | |||
| # ---------------------------------------------------------------------------------------------------------------------------- | |||
| BUILD_CXX_FLAGS += -I. -I.. -I../../includes -I../../utils -isystem ../../modules | |||
| BUILD_CXX_FLAGS += $(LIBLO_FLAGS) | |||
| BUILD_CXX_FLAGS += $(QTCORE_FLAGS) | |||
| BUILD_CXX_FLAGS += $(QTXML_FLAGS) | |||
| # BUILD_CXX_FLAGS += $(QTCORE_FLAGS) | |||
| # BUILD_CXX_FLAGS += $(QTXML_FLAGS) | |||
| # -------------------------------------------------------------- | |||
| # ---------------------------------------------------------------------------------------------------------------------------- | |||
| BUILD_CXX_FLAGS += -DWANT_NATIVE | |||
| @@ -26,7 +26,7 @@ BUILD_CXX_FLAGS += -DWANT_LADSPA -DWANT_DSSI -DWANT_LV2 | |||
| # endif | |||
| endif | |||
| # -------------------------------------------------------------- | |||
| # ---------------------------------------------------------------------------------------------------------------------------- | |||
| # ifeq ($(HAVE_CSOUND),true) | |||
| # BUILD_CXX_FLAGS += -DWANT_CSOUND | |||
| @@ -40,7 +40,7 @@ ifeq ($(HAVE_LINUXSAMPLER),true) | |||
| BUILD_CXX_FLAGS += -DWANT_LINUXSAMPLER | |||
| endif | |||
| # -------------------------------------------------------------- | |||
| # ---------------------------------------------------------------------------------------------------------------------------- | |||
| ifeq ($(HAVE_AF_DEPS),true) | |||
| BUILD_CXX_FLAGS += -DWANT_AUDIOFILE | |||
| @@ -57,7 +57,7 @@ BUILD_CXX_FLAGS += -DWANT_ZYNADDSUBFX_UI | |||
| endif | |||
| endif | |||
| # -------------------------------------------------------------- | |||
| # ---------------------------------------------------------------------------------------------------------------------------- | |||
| CARLA_DEFINES_H = ../../includes/CarlaDefines.h | |||
| CARLA_MIDI_H = ../../includes/CarlaMIDI.h | |||
| @@ -69,6 +69,7 @@ CARLA_PLUGIN_HPP = ../CarlaPlugin.hpp $(CARLA_BACKEND_H) | |||
| CARLA_UTILS_HPP = ../../utils/CarlaUtils.hpp $(CARLA_DEFINES_H) | |||
| CARLA_JUCE_UTILS_HPP = ../../utils/CarlaJuceUtils.hpp $(CARLA_UTILS_HPP) | |||
| CARLA_LIB_UTILS_HPP = ../../utils/CarlaLibUtils.hpp $(CARLA_UTILS_HPP) | |||
| CARLA_OSC_UTILS_HPP = ../../utils/CarlaOscUtils.hpp $(CARLA_UTILS_HPP) | |||
| CARLA_MUTEX_HPP = ../../utils/CarlaMutex.hpp $(CARLA_UTILS_HPP) | |||
| @@ -76,19 +77,27 @@ CARLA_RING_BUFFER_HPP = ../../utils/CarlaRingBuffer.hpp $(CARLA_UTILS_HPP) | |||
| CARLA_STRING_HPP = ../../utils/CarlaString.hpp $(CARLA_JUCE_UTILS_HPP) | |||
| CARLA_THREAD_HPP = ../../utils/CarlaThread.hpp $(CARLA_MUTEX_HPP) $(CARLA_STRING_HPP) | |||
| LV2_ATOM_QUEUE_HPP = ../../utils/Lv2AtomQueue.hpp $(CARLA_MUTEX_HPP) $(CARLA_RING_BUFFER_HPP) | |||
| LINKED_LIST_HPP = ../../utils/LinkedList.hpp $(CARLA_UTILS_HPP) | |||
| RT_LINKED_LIST_HPP = ../../utils/RtLinkedList.hpp $(LINKED_LIST_HPP) | |||
| CARLA_BACKEND_UTILS_HPP = ../../utils/CarlaBackendUtils.hpp $(CARLA_BACKEND_H) $(CARLA_HOST_H) $(CARLA_STRING_HPP) | |||
| CARLA_BRIDGE_UTILS_HPP = ../../utils/CarlaBridgeUtils.hpp $(CARLA_RING_BUFFER_HPP) | |||
| CARLA_ENGINE_UTILS_HPP = ../../utils/CarlaEngineUtils.hpp $(CARLA_ENGINE_HPP) $(CARLA_UTILS_HPP) | |||
| CARLA_LIB_COUNTER_HPP = ../../utils/CarlaLibCounter.hpp $(CARLA_LIB_UTILS_HPP) $(CARLA_MUTEX_HPP) $(LINKED_LIST_HPP) | |||
| CARLA_PIPE_UTILS_HPP = ../../utils/CarlaPipeUtils.hpp $(CARLA_STRING_HPP) | |||
| CARLA_SHM_UTILS_HPP = ../../utils/CarlaShmUtils.hpp $(CARLA_UTILS_HPP) | |||
| CARLA_STATE_UTILS_HPP = ../../utils/CarlaStateUtils.hpp $(CARLA_BACKEND_UTILS_HPP) $(CARLA_MIDI_H) $(LINKED_LIST_HPP) | |||
| CARLA_LADSPA_UTILS_HPP = ../../utils/CarlaLadspaUtils.hpp $(CARLA_UTILS_HPP) | |||
| CARLA_DSSI_UTILS_HPP = ../../utils/CarlaDssiUtils.hpp $(CARLA_LADSPA_UTILS_HPP) | |||
| CARLA_LV2_UTILS_HPP = ../../utils/CarlaLv2Utils.hpp $(CARLA_UTILS_HPP) | |||
| CARLA_VST_UTILS_HPP = ../../utils/CarlaVstUtils.hpp $(CARLA_UTILS_HPP) | |||
| CARLA_NATIVE_H = ../../modules/CarlaNative.h | |||
| CARLA_NATIVE_HPP = ../../modules/CarlaNative.hpp $(CARLA_NATIVE_H) $(CARLA_MIDI_H) $(CARLA_JUCE_UTILS_HPP) | |||
| JACK_BRIDGE_HPP = ../../modules/jackbridge/JackBridge.hpp $(CARLA_DEFINES_H) | |||
| RTAUDIO_HPP = ../../modules/rtaudio/RtAudio.h | |||
| RTMIDI_HPP = ../../modules/rtmidi/RtMidi.h $(CARLA_DEFINES_H) | |||
| # -------------------------------------------------------------- | |||
| # ---------------------------------------------------------------------------------------------------------------------------- | |||
| @@ -32,6 +32,8 @@ | |||
| #include "CarlaEngineUtils.hpp" | |||
| #include "CarlaStateUtils.hpp" | |||
| #include "CarlaMIDI.h" | |||
| #ifndef HAVE_JUCE | |||
| # include <cmath> | |||
| #else | |||
| @@ -42,6 +44,7 @@ using juce::FloatVectorOperations; | |||
| #include <QtCore/QFile> | |||
| #include <QtCore/QFileInfo> | |||
| #include <QtCore/QTextStream> | |||
| #include <QtXml/QDomNode> | |||
| // ----------------------------------------------------------------------- | |||
| @@ -1414,8 +1417,8 @@ bool CarlaEngine::saveProject(const char* const filename) | |||
| plugin->getRealName(strBuf); | |||
| if (strBuf[0] != '\0') | |||
| out << QString(" <!-- %1 -->\n").arg(xmlSafeString(strBuf, true)); | |||
| //if (strBuf[0] != '\0') | |||
| // out << QString(" <!-- %1 -->\n").arg(xmlSafeString(strBuf, true)); | |||
| QString content; | |||
| fillXmlStringFromSaveState(content, plugin->getSaveState()); | |||
| @@ -27,16 +27,19 @@ | |||
| #include "CarlaEngineInternal.hpp" | |||
| #include "CarlaPlugin.hpp" | |||
| #include "CarlaNative.hpp" | |||
| #include "CarlaBackendUtils.hpp" | |||
| #include "CarlaPipeUtils.hpp" | |||
| #include "CarlaStateUtils.hpp" | |||
| #include "CarlaNative.hpp" | |||
| #ifdef HAVE_JUCE | |||
| # include "juce_audio_basics.h" | |||
| using juce::FloatVectorOperations; | |||
| #endif | |||
| #include <QtCore/QTextStream> | |||
| #include <QtXml/QDomNode> | |||
| CARLA_BACKEND_START_NAMESPACE | |||
| @@ -1255,8 +1258,8 @@ protected: | |||
| plugin->getRealName(strBuf); | |||
| if (strBuf[0] != '\0') | |||
| out << QString(" <!-- %1 -->\n").arg(xmlSafeString(strBuf, true)); | |||
| //if (strBuf[0] != '\0') | |||
| // out << QString(" <!-- %1 -->\n").arg(xmlSafeString(strBuf, true)); | |||
| QString content; | |||
| fillXmlStringFromSaveState(content, plugin->getSaveState()); | |||
| @@ -49,7 +49,7 @@ endif | |||
| all: $(TARGETa) $(TARGETp) | |||
| clean: | |||
| $(RM) *.o $(OBJSp) $(TARGET) $(TARGETp) | |||
| $(RM) *.o $(TARGET) $(TARGETp) | |||
| debug: | |||
| $(MAKE) DEBUG=true | |||
| @@ -66,8 +66,8 @@ $(TARGETp): $(OBJSp) | |||
| # ---------------------------------------------------------------------------------------------------------------------------- | |||
| CarlaEngine.cpp.o: CarlaEngine.cpp $(CARLA_ENGINE_INTERNAL_HPP) $(CARLA_PLUGIN_HPP) $(CARLA_BACKEND_UTILS_HPP) $(CARLA_ENGINE_UTILS_HPP) $(CARLA_STATE_UTILS_HPP) | |||
| $(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | |||
| CarlaEngine.cpp.o: CarlaEngine.cpp $(CARLA_ENGINE_INTERNAL_HPP) $(CARLA_PLUGIN_HPP) $(CARLA_BACKEND_UTILS_HPP) $(CARLA_ENGINE_UTILS_HPP) $(CARLA_STATE_UTILS_HPP) $(CARLA_MIDI_H) | |||
| $(CXX) $< $(BUILD_CXX_FLAGS) $(QTCORE_FLAGS) $(QTXML_FLAGS) -c -o $@ | |||
| CarlaEngineInternal.cpp.o: CarlaEngineInternal.cpp $(CARLA_ENGINE_INTERNAL_HPP) $(CARLA_PLUGIN_HPP) $(CARLA_MIDI_H) | |||
| $(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | |||
| @@ -79,7 +79,7 @@ CarlaEngineThread.cpp.o: CarlaEngineThread.cpp $(CARLA_ENGINE_HPP) $(CARLA_ENGIN | |||
| $(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | |||
| CarlaEngineJack.cpp.o: CarlaEngineJack.cpp $(CARLA_ENGINE_INTERNAL_HPP) $(CARLA_PLUGIN_HPP) $(CARLA_BACKEND_UTILS_HPP) $(CARLA_ENGINE_UTILS_HPP) $(CARLA_MIDI_H) $(JACK_BRIDGE_HPP) | |||
| $(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | |||
| $(CXX) $< $(BUILD_CXX_FLAGS) $(QTCORE_FLAGS) -c -o $@ | |||
| CarlaEngineRtAudio.cpp.o: CarlaEngineRtAudio.cpp $(CARLA_ENGINE_INTERNAL_HPP) $(CARLA_BACKEND_UTILS_HPP) $(RT_LINKED_LIST_HPP) $(RTAUDIO_HPP) $(RTMIDI_HPP) | |||
| $(CXX) $< $(BUILD_CXX_FLAGS) $(RTAUDIO_FLAGS) $(RTMIDI_FLAGS) -c -o $@ | |||
| @@ -87,10 +87,10 @@ CarlaEngineRtAudio.cpp.o: CarlaEngineRtAudio.cpp $(CARLA_ENGINE_INTERNAL_HPP) $( | |||
| CarlaEngineJuce.cpp.o: CarlaEngineJuce.cpp $(CARLA_ENGINE_INTERNAL_HPP) $(CARLA_BACKEND_UTILS_HPP) | |||
| $(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | |||
| CarlaEngineNative.cpp.o: CarlaEngineNative.cpp $(CARLA_ENGINE_INTERNAL_HPP) $(CARLA_PLUGIN_HPP) $(CARLA_NATIVE_HPP) $(CARLA_PIPE_UTILS_HPP) $(CARLA_STATE_UTILS_HPP) | |||
| $(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | |||
| CarlaEngineNative.cpp.o: CarlaEngineNative.cpp $(CARLA_ENGINE_INTERNAL_HPP) $(CARLA_PLUGIN_HPP) $(CARLA_BACKEND_UTILS_HPP) $(CARLA_PIPE_UTILS_HPP) $(CARLA_STATE_UTILS_HPP) $(CARLA_NATIVE_HPP) | |||
| $(CXX) $< $(BUILD_CXX_FLAGS) $(QTCORE_FLAGS) $(QTXML_FLAGS) -c -o $@ | |||
| CarlaEngineNative.cpp.exp.o: CarlaEngineNative.cpp $(CARLA_ENGINE_INTERNAL_HPP) $(CARLA_PLUGIN_HPP) $(CARLA_NATIVE_HPP) $(CARLA_PIPE_UTILS_HPP) $(CARLA_STATE_UTILS_HPP) | |||
| $(CXX) $< $(BUILD_CXX_FLAGS) -DCARLA_PLUGIN_EXPORT -c -o $@ | |||
| CarlaEngineNative.cpp.exp.o: CarlaEngineNative.cpp $(CARLA_ENGINE_INTERNAL_HPP) $(CARLA_PLUGIN_HPP) $(CARLA_BACKEND_UTILS_HPP) $(CARLA_PIPE_UTILS_HPP) $(CARLA_STATE_UTILS_HPP) $(CARLA_NATIVE_HPP) | |||
| $(CXX) $< $(BUILD_CXX_FLAGS) $(QTCORE_FLAGS) $(QTXML_FLAGS) -DCARLA_PLUGIN_EXPORT -c -o $@ | |||
| # ---------------------------------------------------------------------------------------------------------------------------- | |||
| @@ -20,6 +20,7 @@ | |||
| #ifndef BUILD_BRIDGE | |||
| #include "CarlaBackendUtils.hpp" | |||
| #include "CarlaBridgeUtils.hpp" | |||
| #include "CarlaShmUtils.hpp" | |||
| @@ -18,8 +18,12 @@ | |||
| #include "CarlaPluginInternal.hpp" | |||
| #include "CarlaEngine.hpp" | |||
| #include "CarlaBackendUtils.hpp" | |||
| #include "CarlaMIDI.h" | |||
| #include <QtCore/QFile> | |||
| #include <QtCore/QTextStream> | |||
| #include <QtXml/QDomNode> | |||
| CARLA_BACKEND_START_NAMESPACE | |||
| @@ -27,6 +27,8 @@ | |||
| #include "CarlaMutex.hpp" | |||
| #include "RtLinkedList.hpp" | |||
| #include "CarlaMIDI.h" | |||
| #include <cmath> | |||
| #ifdef HAVE_JUCE | |||
| @@ -15,9 +15,8 @@ | |||
| * For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
| */ | |||
| #include "CarlaPluginThread.hpp" | |||
| #include "CarlaPlugin.hpp" | |||
| #include "CarlaPluginThread.hpp" | |||
| #include "CarlaEngine.hpp" | |||
| #include <QtCore/QProcess> | |||
| @@ -21,7 +21,6 @@ | |||
| #ifdef WANT_DSSI | |||
| #include "CarlaDssiUtils.hpp" | |||
| #include "CarlaLibUtils.hpp" | |||
| CARLA_BACKEND_START_NAMESPACE | |||
| @@ -1806,7 +1805,7 @@ public: | |||
| if (! pData->libOpen(filename)) | |||
| { | |||
| pData->engine->setLastError(lib_error(filename)); | |||
| pData->engine->setLastError(pData->libError(filename)); | |||
| return false; | |||
| } | |||
| @@ -26,6 +26,8 @@ | |||
| #ifdef WANT_LINUXSAMPLER | |||
| #include "CarlaBackendUtils.hpp" | |||
| #include "linuxsampler/EngineFactory.h" | |||
| #include <linuxsampler/Sampler.h> | |||
| @@ -21,7 +21,6 @@ | |||
| #ifdef WANT_LV2 | |||
| #include "CarlaLv2Utils.hpp" | |||
| #include "CarlaLibUtils.hpp" | |||
| #include "Lv2AtomQueue.hpp" | |||
| #include "../engine/CarlaEngineOsc.hpp" | |||
| @@ -1408,7 +1407,7 @@ public: | |||
| if (! pData->libOpen(fRdfDescriptor->Binary)) | |||
| { | |||
| pData->engine->setLastError(lib_error(fRdfDescriptor->Binary)); | |||
| pData->engine->setLastError(pData->libError(fRdfDescriptor->Binary)); | |||
| return false; | |||
| } | |||
| @@ -6,55 +6,92 @@ | |||
| include ../Makefile.mk | |||
| # -------------------------------------------------------------- | |||
| # ---------------------------------------------------------------------------------------------------------------------------- | |||
| CARLA_ENGINE_OSC_HPP = ../engine/CarlaEngineOsc.hpp $(CARLA_BACKEND_H) $(CARLA_OSC_UTILS_HPP) $(CARLA_STRING_HPP) | |||
| CARLA_PLUGIN_THREAD_HPP = CarlaPluginThread.hpp $(CARLA_BACKEND_H) $(CARLA_THREAD_HPP) | |||
| CARLA_PLUGIN_INTERNAL_HPP = CarlaPluginInternal.hpp $(CARLA_PLUGIN_HPP) $(CARLA_PLUGIN_THREAD_HPP) $(CARLA_OSC_UTILS_HPP) $(CARLA_STATE_UTILS_HPP) $(CARLA_MUTEX_HPP) $(RT_LINKED_LIST_HPP) $(CARLA_MIDI_H) | |||
| # ---------------------------------------------------------------------------------------------------------------------------- | |||
| OBJS = \ | |||
| CarlaPlugin.cpp.o \ | |||
| CarlaPluginInternal.cpp.o \ | |||
| CarlaPluginThread.cpp.o \ | |||
| BridgePlugin.cpp.o \ | |||
| NativePlugin.cpp.o \ | |||
| BridgePlugin.cpp.o \ | |||
| LadspaPlugin.cpp.o \ | |||
| DssiPlugin.cpp.o \ | |||
| Lv2Plugin.cpp.o \ | |||
| VstPlugin.cpp.o \ | |||
| AuPlugin.cpp.o \ | |||
| CsoundPlugin.cpp.o \ | |||
| JucePlugin.cpp.o \ | |||
| FluidSynthPlugin.cpp.o \ | |||
| LinuxSamplerPlugin.cpp.o \ | |||
| JucePlugin.cpp.o | |||
| LinuxSamplerPlugin.cpp.o | |||
| HEADERS = \ | |||
| ../CarlaBackend.h ../CarlaEngine.hpp ../CarlaPlugin.hpp \ | |||
| CarlaPluginInternal.hpp CarlaPluginThread.hpp | |||
| # ---------------------------------------------------------------------------------------------------------------------------- | |||
| TARGET = ../carla_plugin.a | |||
| # -------------------------------------------------------------- | |||
| # ---------------------------------------------------------------------------------------------------------------------------- | |||
| all: $(TARGET) | |||
| # -------------------------------------------------------------- | |||
| %.cpp.o: %.cpp $(HEADERS) | |||
| $(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | |||
| clean: | |||
| $(RM) *.o $(TARGET) | |||
| FluidSynthPlugin.cpp.o: FluidSynthPlugin.cpp $(HEADERS) | |||
| $(CXX) $< $(BUILD_CXX_FLAGS) $(FLUIDSYNTH_FLAGS) -c -o $@ | |||
| debug: | |||
| $(MAKE) DEBUG=true | |||
| LinuxSamplerPlugin.cpp.o: LinuxSamplerPlugin.cpp $(HEADERS) | |||
| $(CXX) $< $(BUILD_CXX_FLAGS) $(LINUXSAMPLER_FLAGS) -c -o $@ | |||
| # ---------------------------------------------------------------------------------------------------------------------------- | |||
| $(TARGET): $(OBJS) | |||
| $(RM) $@ | |||
| $(AR) crs $@ $^ | |||
| # -------------------------------------------------------------- | |||
| # ---------------------------------------------------------------------------------------------------------------------------- | |||
| clean: | |||
| $(RM) *.o $(TARGET) | |||
| CarlaPlugin.cpp.o: CarlaPlugin.cpp $(CARLA_PLUGIN_INTERNAL_HPP) $(CARLA_ENGINE_HPP) $(CARLA_BACKEND_UTILS_HPP) | |||
| $(CXX) $< $(BUILD_CXX_FLAGS) $(QTCORE_FLAGS) $(QTXML_FLAGS) -c -o $@ | |||
| debug: | |||
| $(MAKE) DEBUG=true | |||
| CarlaPluginInternal.cpp.o: CarlaPluginInternal.cpp $(CARLA_PLUGIN_INTERNAL_HPP) $(CARLA_ENGINE_HPP) $(CARLA_LIB_COUNTER_HPP) | |||
| $(CXX) $< $(BUILD_CXX_FLAGS) $(QTCORE_FLAGS) -c -o $@ | |||
| CarlaPluginThread.cpp.o: CarlaPluginThread.cpp $(CARLA_PLUGIN_HPP) $(CARLA_PLUGIN_THREAD_HPP) $(CARLA_ENGINE_HPP) | |||
| $(CXX) $< $(BUILD_CXX_FLAGS) $(QTCORE_FLAGS) -c -o $@ | |||
| NativePlugin.cpp.o: NativePlugin.cpp $(CARLA_PLUGIN_INTERNAL_HPP) $(CARLA_ENGINE_HPP) $(CARLA_NATIVE_H) $(CARLA_HOST_H) | |||
| $(CXX) $< $(BUILD_CXX_FLAGS) $(QTCORE_FLAGS) -c -o $@ | |||
| BridgePlugin.cpp.o: BridgePlugin.cpp $(CARLA_PLUGIN_INTERNAL_HPP) $(CARLA_ENGINE_HPP) $(CARLA_BACKEND_UTILS_HPP) $(CARLA_BRIDGE_UTILS_HPP) $(CARLA_SHM_UTILS_HPP) $(JACK_BRIDGE_HPP) | |||
| $(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | |||
| LadspaPlugin.cpp.o: LadspaPlugin.cpp $(CARLA_PLUGIN_INTERNAL_HPP) $(CARLA_ENGINE_HPP) $(CARLA_LADSPA_UTILS_HPP) | |||
| $(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | |||
| DssiPlugin.cpp.o: DssiPlugin.cpp $(CARLA_PLUGIN_INTERNAL_HPP) $(CARLA_ENGINE_HPP) $(CARLA_DSSI_UTILS_HPP) | |||
| $(CXX) $< $(BUILD_CXX_FLAGS) $(QTCORE_FLAGS) -c -o $@ # FIXME | |||
| Lv2Plugin.cpp.o: Lv2Plugin.cpp $(CARLA_PLUGIN_INTERNAL_HPP) $(CARLA_ENGINE_HPP) $(CARLA_LV2_UTILS_HPP) $(LV2_ATOM_QUEUE_HPP) $(CARLA_ENGINE_OSC_HPP) | |||
| $(CXX) $< $(BUILD_CXX_FLAGS) $(QTCORE_FLAGS) -c -o $@ # FIXME | |||
| VstPlugin.cpp.o: VstPlugin.cpp $(CARLA_PLUGIN_INTERNAL_HPP) $(CARLA_ENGINE_HPP) $(CARLA_VST_UTILS_HPP) | |||
| $(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | |||
| AuPlugin.cpp.o: AuPlugin.cpp $(CARLA_PLUGIN_HPP) $(CARLA_ENGINE_HPP) $(CARLA_UTILS_HPP) | |||
| $(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | |||
| CsoundPlugin.cpp.o: CsoundPlugin.cpp $(CARLA_PLUGIN_INTERNAL_HPP) $(CARLA_ENGINE_HPP) | |||
| $(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | |||
| JucePlugin.cpp.o: JucePlugin.cpp $(CARLA_PLUGIN_INTERNAL_HPP) $(CARLA_ENGINE_HPP) | |||
| $(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | |||
| FluidSynthPlugin.cpp.o: FluidSynthPlugin.cpp $(CARLA_PLUGIN_INTERNAL_HPP) $(CARLA_ENGINE_HPP) | |||
| $(CXX) $< $(BUILD_CXX_FLAGS) $(FLUIDSYNTH_FLAGS) $(QTCORE_FLAGS) -c -o $@ | |||
| LinuxSamplerPlugin.cpp.o: LinuxSamplerPlugin.cpp $(CARLA_PLUGIN_INTERNAL_HPP) $(CARLA_ENGINE_HPP) $(CARLA_BACKEND_UTILS_HPP) | |||
| $(CXX) $< $(BUILD_CXX_FLAGS) $(LINUXSAMPLER_FLAGS) $(QTCORE_FLAGS) -c -o $@ | |||
| # -------------------------------------------------------------- | |||
| # ---------------------------------------------------------------------------------------------------------------------------- | |||
| @@ -23,6 +23,8 @@ | |||
| #include "CarlaNative.h" | |||
| #include "CarlaHost.h" | |||
| #include "CarlaMIDI.h" | |||
| #include <QtCore/QStringList> | |||
| extern const char* carla_file_callback(FileCallbackOpcode action, bool isDir, const char* title, const char* filter); | |||
| @@ -21,7 +21,6 @@ | |||
| #ifdef WANT_VST | |||
| #include "CarlaVstUtils.hpp" | |||
| #include "CarlaLibUtils.hpp" | |||
| CARLA_BACKEND_START_NAMESPACE | |||
| @@ -2157,7 +2156,7 @@ public: | |||
| if (! pData->libOpen(filename)) | |||
| { | |||
| pData->engine->setLastError(lib_error(filename)); | |||
| pData->engine->setLastError(pData->libError(filename)); | |||
| return false; | |||
| } | |||
| @@ -31,7 +31,7 @@ public: | |||
| void* open(const char* const filename) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(filename != nullptr, nullptr); | |||
| CARLA_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0', nullptr); | |||
| const CarlaMutex::ScopedLocker sl(fMutex); | |||
| @@ -0,0 +1,567 @@ | |||
| /* | |||
| * Carla State utils | |||
| * Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU General Public License as | |||
| * published by the Free Software Foundation; either version 2 of | |||
| * the License, or any later version. | |||
| * | |||
| * This program is distributed in the hope that it will be useful, | |||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| * GNU General Public License for more details. | |||
| * | |||
| * For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
| */ | |||
| #include "CarlaStateUtils.hpp" | |||
| #include "CarlaBackendUtils.hpp" | |||
| #include "CarlaMIDI.h" | |||
| #include <QtCore/QString> | |||
| #include <QtXml/QDomNode> | |||
| CARLA_BACKEND_START_NAMESPACE | |||
| // ----------------------------------------------------------------------- | |||
| // StateParameter | |||
| StateParameter::StateParameter() noexcept | |||
| : index(0), | |||
| name(nullptr), | |||
| symbol(nullptr), | |||
| value(0.0f), | |||
| midiChannel(0), | |||
| midiCC(-1) {} | |||
| StateParameter::~StateParameter() | |||
| { | |||
| if (name != nullptr) | |||
| { | |||
| delete[] name; | |||
| name = nullptr; | |||
| } | |||
| if (symbol != nullptr) | |||
| { | |||
| delete[] symbol; | |||
| symbol = nullptr; | |||
| } | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // StateCustomData | |||
| StateCustomData::StateCustomData() noexcept | |||
| : type(nullptr), | |||
| key(nullptr), | |||
| value(nullptr) {} | |||
| StateCustomData::~StateCustomData() | |||
| { | |||
| if (type != nullptr) | |||
| { | |||
| delete[] type; | |||
| type = nullptr; | |||
| } | |||
| if (key != nullptr) | |||
| { | |||
| delete[] key; | |||
| key = nullptr; | |||
| } | |||
| if (value != nullptr) | |||
| { | |||
| delete[] value; | |||
| value = nullptr; | |||
| } | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // SaveState | |||
| SaveState::SaveState() noexcept | |||
| : type(nullptr), | |||
| name(nullptr), | |||
| label(nullptr), | |||
| binary(nullptr), | |||
| uniqueID(0), | |||
| active(false), | |||
| dryWet(1.0f), | |||
| volume(1.0f), | |||
| balanceLeft(-1.0f), | |||
| balanceRight(1.0f), | |||
| panning(0.0f), | |||
| ctrlChannel(-1), | |||
| currentProgramIndex(-1), | |||
| currentProgramName(nullptr), | |||
| currentMidiBank(-1), | |||
| currentMidiProgram(-1), | |||
| chunk(nullptr) {} | |||
| SaveState::~SaveState() | |||
| { | |||
| reset(); | |||
| } | |||
| void SaveState::reset() | |||
| { | |||
| if (type != nullptr) | |||
| { | |||
| delete[] type; | |||
| type = nullptr; | |||
| } | |||
| if (name != nullptr) | |||
| { | |||
| delete[] name; | |||
| name = nullptr; | |||
| } | |||
| if (label != nullptr) | |||
| { | |||
| delete[] label; | |||
| label = nullptr; | |||
| } | |||
| if (binary != nullptr) | |||
| { | |||
| delete[] binary; | |||
| binary = nullptr; | |||
| } | |||
| if (currentProgramName != nullptr) | |||
| { | |||
| delete[] currentProgramName; | |||
| currentProgramName = nullptr; | |||
| } | |||
| if (chunk != nullptr) | |||
| { | |||
| delete[] chunk; | |||
| chunk = nullptr; | |||
| } | |||
| uniqueID = 0; | |||
| active = false; | |||
| dryWet = 1.0f; | |||
| volume = 1.0f; | |||
| balanceLeft = -1.0f; | |||
| balanceRight = 1.0f; | |||
| panning = 0.0f; | |||
| ctrlChannel = -1; | |||
| currentProgramIndex = -1; | |||
| currentMidiBank = -1; | |||
| currentMidiProgram = -1; | |||
| for (StateParameterItenerator it = parameters.begin(); it.valid(); it.next()) | |||
| { | |||
| StateParameter* const stateParameter(it.getValue()); | |||
| delete stateParameter; | |||
| } | |||
| for (StateCustomDataItenerator it = customData.begin(); it.valid(); it.next()) | |||
| { | |||
| StateCustomData* const stateCustomData(it.getValue()); | |||
| delete stateCustomData; | |||
| } | |||
| parameters.clear(); | |||
| customData.clear(); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // xmlSafeString | |||
| 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(""","\""); | |||
| } | |||
| const char* xmlSafeStringCharDup(const QString& string, const bool toXml) | |||
| { | |||
| return carla_strdup(xmlSafeString(string, toXml).toUtf8().constData()); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // fillSaveStateFromXmlNode | |||
| void fillSaveStateFromXmlNode(SaveState& saveState, const QDomNode& xmlNode) | |||
| { | |||
| if (xmlNode.isNull()) | |||
| return; | |||
| for (QDomNode node = xmlNode.firstChild(); ! node.isNull(); node = node.nextSibling()) | |||
| { | |||
| QString tagName(node.toElement().tagName()); | |||
| // --------------------------------------------------------------- | |||
| // Info | |||
| if (tagName.compare("info", Qt::CaseInsensitive) == 0) | |||
| { | |||
| for (QDomNode xmlInfo = node.toElement().firstChild(); ! xmlInfo.isNull(); xmlInfo = xmlInfo.nextSibling()) | |||
| { | |||
| const QString tag(xmlInfo.toElement().tagName()); | |||
| const QString text(xmlInfo.toElement().text().trimmed()); | |||
| if (tag.compare("type", Qt::CaseInsensitive) == 0) | |||
| { | |||
| saveState.type = xmlSafeStringCharDup(text, false); | |||
| } | |||
| else if (tag.compare("name", Qt::CaseInsensitive) == 0) | |||
| { | |||
| saveState.name = xmlSafeStringCharDup(text, false); | |||
| } | |||
| else if (tag.compare("label", Qt::CaseInsensitive) == 0 || tag.compare("uri", Qt::CaseInsensitive) == 0) | |||
| { | |||
| saveState.label = xmlSafeStringCharDup(text, false); | |||
| } | |||
| else if (tag.compare("binary", Qt::CaseInsensitive) == 0 || tag.compare("filename", Qt::CaseInsensitive) == 0) | |||
| { | |||
| 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; | |||
| } | |||
| } | |||
| } | |||
| // --------------------------------------------------------------- | |||
| // Data | |||
| else if (tagName.compare("data", Qt::CaseInsensitive) == 0) | |||
| { | |||
| for (QDomNode xmlData = node.toElement().firstChild(); ! xmlData.isNull(); xmlData = xmlData.nextSibling()) | |||
| { | |||
| const QString tag(xmlData.toElement().tagName()); | |||
| const QString text(xmlData.toElement().text().trimmed()); | |||
| // ------------------------------------------------------- | |||
| // Internal Data | |||
| if (tag.compare("active", Qt::CaseInsensitive) == 0) | |||
| { | |||
| saveState.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) saveState.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) saveState.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) saveState.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) saveState.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) saveState.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) | |||
| saveState.ctrlChannel = static_cast<int8_t>(value-1); | |||
| } | |||
| // ------------------------------------------------------- | |||
| // Program (current) | |||
| else if (tag.compare("currentprogramindex", Qt::CaseInsensitive) == 0 || tag.compare("current-program-index", Qt::CaseInsensitive) == 0) | |||
| { | |||
| bool ok; | |||
| const int value(text.toInt(&ok)); | |||
| if (ok && value >= 1) | |||
| saveState.currentProgramIndex = value-1; | |||
| } | |||
| else if (tag.compare("currentprogramname", Qt::CaseInsensitive) == 0 || tag.compare("current-program-name", Qt::CaseInsensitive) == 0) | |||
| { | |||
| saveState.currentProgramName = xmlSafeStringCharDup(text, false); | |||
| } | |||
| // ------------------------------------------------------- | |||
| // Midi Program (current) | |||
| else if (tag.compare("currentmidibank", Qt::CaseInsensitive) == 0 || tag.compare("current-midi-bank", Qt::CaseInsensitive) == 0) | |||
| { | |||
| bool ok; | |||
| const int value(text.toInt(&ok)); | |||
| if (ok && value >= 1) | |||
| saveState.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) | |||
| saveState.currentMidiProgram = value-1; | |||
| } | |||
| // ------------------------------------------------------- | |||
| // Parameters | |||
| else if (tag.compare("parameter", Qt::CaseInsensitive) == 0) | |||
| { | |||
| StateParameter* const stateParameter(new StateParameter()); | |||
| for (QDomNode xmlSubData = xmlData.toElement().firstChild(); ! xmlSubData.isNull(); xmlSubData = xmlSubData.nextSibling()) | |||
| { | |||
| const QString pTag(xmlSubData.toElement().tagName()); | |||
| const QString pText(xmlSubData.toElement().text().trimmed()); | |||
| if (pTag.compare("index", Qt::CaseInsensitive) == 0) | |||
| { | |||
| bool ok; | |||
| const uint index(pText.toUInt(&ok)); | |||
| if (ok) stateParameter->index = index; | |||
| } | |||
| else if (pTag.compare("name", Qt::CaseInsensitive) == 0) | |||
| { | |||
| stateParameter->name = xmlSafeStringCharDup(pText, false); | |||
| } | |||
| else if (pTag.compare("symbol", Qt::CaseInsensitive) == 0) | |||
| { | |||
| stateParameter->symbol = xmlSafeStringCharDup(pText, false); | |||
| } | |||
| else if (pTag.compare("value", Qt::CaseInsensitive) == 0) | |||
| { | |||
| bool ok; | |||
| const float value(pText.toFloat(&ok)); | |||
| if (ok) stateParameter->value = value; | |||
| } | |||
| else if (pTag.compare("midichannel", Qt::CaseInsensitive) == 0 || pTag.compare("midi-channel", Qt::CaseInsensitive) == 0) | |||
| { | |||
| bool ok; | |||
| const ushort channel(pText.toUShort(&ok)); | |||
| if (ok && channel >= 1 && channel < MAX_MIDI_CHANNELS) | |||
| stateParameter->midiChannel = static_cast<uint8_t>(channel-1); | |||
| } | |||
| else if (pTag.compare("midicc", Qt::CaseInsensitive) == 0 || pTag.compare("midi-cc", Qt::CaseInsensitive) == 0) | |||
| { | |||
| bool ok; | |||
| const int cc(pText.toInt(&ok)); | |||
| if (ok && cc >= 1 && cc < 0x5F) | |||
| stateParameter->midiCC = static_cast<int16_t>(cc); | |||
| } | |||
| } | |||
| saveState.parameters.append(stateParameter); | |||
| } | |||
| // ------------------------------------------------------- | |||
| // Custom Data | |||
| else if (tag.compare("customdata", Qt::CaseInsensitive) == 0 || tag.compare("custom-data", Qt::CaseInsensitive) == 0) | |||
| { | |||
| StateCustomData* const stateCustomData(new StateCustomData()); | |||
| for (QDomNode xmlSubData = xmlData.toElement().firstChild(); ! xmlSubData.isNull(); xmlSubData = xmlSubData.nextSibling()) | |||
| { | |||
| const QString cTag(xmlSubData.toElement().tagName()); | |||
| const QString cText(xmlSubData.toElement().text().trimmed()); | |||
| if (cTag.compare("type", Qt::CaseInsensitive) == 0) | |||
| stateCustomData->type = xmlSafeStringCharDup(cText, false); | |||
| else if (cTag.compare("key", Qt::CaseInsensitive) == 0) | |||
| stateCustomData->key = xmlSafeStringCharDup(cText, false); | |||
| else if (cTag.compare("value", Qt::CaseInsensitive) == 0) | |||
| stateCustomData->value = xmlSafeStringCharDup(cText, false); | |||
| } | |||
| saveState.customData.append(stateCustomData); | |||
| } | |||
| // ------------------------------------------------------- | |||
| // Chunk | |||
| else if (tag.compare("chunk", Qt::CaseInsensitive) == 0) | |||
| { | |||
| saveState.chunk = xmlSafeStringCharDup(text, false); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // fillXmlStringFromSaveState | |||
| void fillXmlStringFromSaveState(QString& content, const SaveState& saveState) | |||
| { | |||
| { | |||
| QString info(" <Info>\n"); | |||
| 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_AU: | |||
| // TODO? | |||
| info += QString(" <Binary>%1</Binary>\n").arg(xmlSafeString(saveState.binary, true)); | |||
| info += QString(" <UniqueID>%1</UniqueID>\n").arg(saveState.uniqueID); | |||
| 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(saveState.binary, true)); | |||
| info += QString(" <Label>%1</Label>\n").arg(xmlSafeString(saveState.label, 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); | |||
| if (saveState.ctrlChannel < 0) | |||
| data += QString(" <ControlChannel>N</ControlChannel>\n"); | |||
| else | |||
| data += QString(" <ControlChannel>%1</ControlChannel>\n").arg(saveState.ctrlChannel+1); | |||
| content += data; | |||
| } | |||
| for (StateParameterItenerator it = saveState.parameters.begin(); it.valid(); it.next()) | |||
| { | |||
| StateParameter* const stateParameter(it.getValue()); | |||
| 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] != '\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+1); | |||
| } | |||
| parameter += " </Parameter>\n"; | |||
| content += parameter; | |||
| } | |||
| if (saveState.currentProgramIndex >= 0 && saveState.currentProgramName != nullptr && saveState.currentProgramName[0] != '\0') | |||
| { | |||
| // ignore 'default' program | |||
| if (saveState.currentProgramIndex > 0 || QString(saveState.currentProgramName).compare("default", Qt::CaseInsensitive) != 0) | |||
| { | |||
| QString program("\n"); | |||
| program += QString(" <CurrentProgramIndex>%1</CurrentProgramIndex>\n").arg(saveState.currentProgramIndex+1); | |||
| 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+1); | |||
| midiProgram += QString(" <CurrentMidiProgram>%1</CurrentMidiProgram>\n").arg(saveState.currentMidiProgram+1); | |||
| content += midiProgram; | |||
| } | |||
| for (StateCustomDataItenerator it = saveState.customData.begin(); it.valid(); it.next()) | |||
| { | |||
| StateCustomData* const stateCustomData(it.getValue()); | |||
| 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_TYPE_CHUNK) == 0 || std::strlen(stateCustomData->value) >= 128) | |||
| { | |||
| 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] != '\0') | |||
| { | |||
| QString chunk("\n"" <Chunk>\n"); | |||
| chunk += QString("%1\n").arg(saveState.chunk); | |||
| chunk += " </Chunk>\n"; | |||
| content += chunk; | |||
| } | |||
| content += " </Data>\n"; | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| CARLA_BACKEND_END_NAMESPACE | |||
| @@ -18,14 +18,19 @@ | |||
| #ifndef CARLA_STATE_UTILS_HPP_INCLUDED | |||
| #define CARLA_STATE_UTILS_HPP_INCLUDED | |||
| #include "CarlaBackendUtils.hpp" | |||
| #include "CarlaMIDI.h" | |||
| #include "LinkedList.hpp" | |||
| #include <QtXml/QDomNode> | |||
| class QDomNode; | |||
| class QString; | |||
| // ----------------------------------------------------------------------- | |||
| CARLA_BACKEND_START_NAMESPACE | |||
| #if 0 | |||
| } // Fix editor indentation | |||
| #endif | |||
| // ----------------------------------------------------------------------- | |||
| struct StateParameter { | |||
| @@ -36,27 +41,8 @@ struct StateParameter { | |||
| uint8_t midiChannel; | |||
| int16_t midiCC; | |||
| StateParameter() noexcept | |||
| : index(0), | |||
| name(nullptr), | |||
| symbol(nullptr), | |||
| value(0.0f), | |||
| midiChannel(0), | |||
| midiCC(-1) {} | |||
| ~StateParameter() | |||
| { | |||
| if (name != nullptr) | |||
| { | |||
| delete[] name; | |||
| name = nullptr; | |||
| } | |||
| if (symbol != nullptr) | |||
| { | |||
| delete[] symbol; | |||
| symbol = nullptr; | |||
| } | |||
| } | |||
| StateParameter() noexcept; | |||
| ~StateParameter(); | |||
| CARLA_DECLARE_NON_COPY_STRUCT(StateParameter) | |||
| }; | |||
| @@ -66,29 +52,8 @@ struct StateCustomData { | |||
| const char* key; | |||
| const char* value; | |||
| StateCustomData() noexcept | |||
| : type(nullptr), | |||
| key(nullptr), | |||
| value(nullptr) {} | |||
| ~StateCustomData() | |||
| { | |||
| if (type != nullptr) | |||
| { | |||
| delete[] type; | |||
| type = nullptr; | |||
| } | |||
| if (key != nullptr) | |||
| { | |||
| delete[] key; | |||
| key = nullptr; | |||
| } | |||
| if (value != nullptr) | |||
| { | |||
| delete[] value; | |||
| value = nullptr; | |||
| } | |||
| } | |||
| StateCustomData() noexcept; | |||
| ~StateCustomData(); | |||
| CARLA_DECLARE_NON_COPY_STRUCT(StateCustomData) | |||
| }; | |||
| @@ -123,491 +88,17 @@ struct SaveState { | |||
| StateParameterList parameters; | |||
| StateCustomDataList customData; | |||
| SaveState() noexcept | |||
| : type(nullptr), | |||
| name(nullptr), | |||
| label(nullptr), | |||
| binary(nullptr), | |||
| uniqueID(0), | |||
| active(false), | |||
| dryWet(1.0f), | |||
| volume(1.0f), | |||
| balanceLeft(-1.0f), | |||
| balanceRight(1.0f), | |||
| panning(0.0f), | |||
| ctrlChannel(-1), | |||
| currentProgramIndex(-1), | |||
| currentProgramName(nullptr), | |||
| currentMidiBank(-1), | |||
| currentMidiProgram(-1), | |||
| chunk(nullptr) {} | |||
| ~SaveState() | |||
| { | |||
| reset(); | |||
| } | |||
| void reset() | |||
| { | |||
| if (type != nullptr) | |||
| { | |||
| delete[] type; | |||
| type = nullptr; | |||
| } | |||
| if (name != nullptr) | |||
| { | |||
| delete[] name; | |||
| name = nullptr; | |||
| } | |||
| if (label != nullptr) | |||
| { | |||
| delete[] label; | |||
| label = nullptr; | |||
| } | |||
| if (binary != nullptr) | |||
| { | |||
| delete[] binary; | |||
| binary = nullptr; | |||
| } | |||
| if (currentProgramName != nullptr) | |||
| { | |||
| delete[] currentProgramName; | |||
| currentProgramName = nullptr; | |||
| } | |||
| if (chunk != nullptr) | |||
| { | |||
| delete[] chunk; | |||
| chunk = nullptr; | |||
| } | |||
| uniqueID = 0; | |||
| active = false; | |||
| dryWet = 1.0f; | |||
| volume = 1.0f; | |||
| balanceLeft = -1.0f; | |||
| balanceRight = 1.0f; | |||
| panning = 0.0f; | |||
| ctrlChannel = -1; | |||
| currentProgramIndex = -1; | |||
| currentMidiBank = -1; | |||
| currentMidiProgram = -1; | |||
| for (StateParameterItenerator it = parameters.begin(); it.valid(); it.next()) | |||
| { | |||
| StateParameter* const stateParameter(it.getValue()); | |||
| delete stateParameter; | |||
| } | |||
| for (StateCustomDataItenerator it = customData.begin(); it.valid(); it.next()) | |||
| { | |||
| StateCustomData* const stateCustomData(it.getValue()); | |||
| delete stateCustomData; | |||
| } | |||
| parameters.clear(); | |||
| customData.clear(); | |||
| } | |||
| SaveState() noexcept; | |||
| ~SaveState(); | |||
| void reset(); | |||
| CARLA_DECLARE_NON_COPY_STRUCT(SaveState) | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| 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()); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| static inline | |||
| void fillSaveStateFromXmlNode(SaveState& saveState, const QDomNode& xmlNode) | |||
| { | |||
| if (xmlNode.isNull()) | |||
| return; | |||
| for (QDomNode node = xmlNode.firstChild(); ! node.isNull(); node = node.nextSibling()) | |||
| { | |||
| QString tagName(node.toElement().tagName()); | |||
| // --------------------------------------------------------------- | |||
| // Info | |||
| if (tagName.compare("info", Qt::CaseInsensitive) == 0) | |||
| { | |||
| for (QDomNode xmlInfo = node.toElement().firstChild(); ! xmlInfo.isNull(); xmlInfo = xmlInfo.nextSibling()) | |||
| { | |||
| const QString tag(xmlInfo.toElement().tagName()); | |||
| const QString text(xmlInfo.toElement().text().trimmed()); | |||
| if (tag.compare("type", Qt::CaseInsensitive) == 0) | |||
| { | |||
| saveState.type = xmlSafeStringCharDup(text, false); | |||
| } | |||
| else if (tag.compare("name", Qt::CaseInsensitive) == 0) | |||
| { | |||
| saveState.name = xmlSafeStringCharDup(text, false); | |||
| } | |||
| else if (tag.compare("label", Qt::CaseInsensitive) == 0 || tag.compare("uri", Qt::CaseInsensitive) == 0) | |||
| { | |||
| saveState.label = xmlSafeStringCharDup(text, false); | |||
| } | |||
| else if (tag.compare("binary", Qt::CaseInsensitive) == 0 || tag.compare("filename", Qt::CaseInsensitive) == 0) | |||
| { | |||
| 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; | |||
| } | |||
| } | |||
| } | |||
| // --------------------------------------------------------------- | |||
| // Data | |||
| else if (tagName.compare("data", Qt::CaseInsensitive) == 0) | |||
| { | |||
| for (QDomNode xmlData = node.toElement().firstChild(); ! xmlData.isNull(); xmlData = xmlData.nextSibling()) | |||
| { | |||
| const QString tag(xmlData.toElement().tagName()); | |||
| const QString text(xmlData.toElement().text().trimmed()); | |||
| // ------------------------------------------------------- | |||
| // Internal Data | |||
| if (tag.compare("active", Qt::CaseInsensitive) == 0) | |||
| { | |||
| saveState.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) saveState.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) saveState.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) saveState.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) saveState.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) saveState.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) | |||
| saveState.ctrlChannel = static_cast<int8_t>(value-1); | |||
| } | |||
| // ------------------------------------------------------- | |||
| // Program (current) | |||
| else if (tag.compare("currentprogramindex", Qt::CaseInsensitive) == 0 || tag.compare("current-program-index", Qt::CaseInsensitive) == 0) | |||
| { | |||
| bool ok; | |||
| const int value(text.toInt(&ok)); | |||
| if (ok && value >= 1) | |||
| saveState.currentProgramIndex = value-1; | |||
| } | |||
| else if (tag.compare("currentprogramname", Qt::CaseInsensitive) == 0 || tag.compare("current-program-name", Qt::CaseInsensitive) == 0) | |||
| { | |||
| saveState.currentProgramName = xmlSafeStringCharDup(text, false); | |||
| } | |||
| // ------------------------------------------------------- | |||
| // Midi Program (current) | |||
| else if (tag.compare("currentmidibank", Qt::CaseInsensitive) == 0 || tag.compare("current-midi-bank", Qt::CaseInsensitive) == 0) | |||
| { | |||
| bool ok; | |||
| const int value(text.toInt(&ok)); | |||
| if (ok && value >= 1) | |||
| saveState.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) | |||
| saveState.currentMidiProgram = value-1; | |||
| } | |||
| // ------------------------------------------------------- | |||
| // Parameters | |||
| else if (tag.compare("parameter", Qt::CaseInsensitive) == 0) | |||
| { | |||
| StateParameter* const stateParameter(new StateParameter()); | |||
| for (QDomNode xmlSubData = xmlData.toElement().firstChild(); ! xmlSubData.isNull(); xmlSubData = xmlSubData.nextSibling()) | |||
| { | |||
| const QString pTag(xmlSubData.toElement().tagName()); | |||
| const QString pText(xmlSubData.toElement().text().trimmed()); | |||
| if (pTag.compare("index", Qt::CaseInsensitive) == 0) | |||
| { | |||
| bool ok; | |||
| const uint index(pText.toUInt(&ok)); | |||
| if (ok) stateParameter->index = index; | |||
| } | |||
| else if (pTag.compare("name", Qt::CaseInsensitive) == 0) | |||
| { | |||
| stateParameter->name = xmlSafeStringCharDup(pText, false); | |||
| } | |||
| else if (pTag.compare("symbol", Qt::CaseInsensitive) == 0) | |||
| { | |||
| stateParameter->symbol = xmlSafeStringCharDup(pText, false); | |||
| } | |||
| else if (pTag.compare("value", Qt::CaseInsensitive) == 0) | |||
| { | |||
| bool ok; | |||
| const float value(pText.toFloat(&ok)); | |||
| if (ok) stateParameter->value = value; | |||
| } | |||
| else if (pTag.compare("midichannel", Qt::CaseInsensitive) == 0 || pTag.compare("midi-channel", Qt::CaseInsensitive) == 0) | |||
| { | |||
| bool ok; | |||
| const ushort channel(pText.toUShort(&ok)); | |||
| if (ok && channel >= 1 && channel < MAX_MIDI_CHANNELS) | |||
| stateParameter->midiChannel = static_cast<uint8_t>(channel-1); | |||
| } | |||
| else if (pTag.compare("midicc", Qt::CaseInsensitive) == 0 || pTag.compare("midi-cc", Qt::CaseInsensitive) == 0) | |||
| { | |||
| bool ok; | |||
| const int cc(pText.toInt(&ok)); | |||
| if (ok && cc >= 1 && cc < 0x5F) | |||
| stateParameter->midiCC = static_cast<int16_t>(cc); | |||
| } | |||
| } | |||
| saveState.parameters.append(stateParameter); | |||
| } | |||
| // ------------------------------------------------------- | |||
| // Custom Data | |||
| else if (tag.compare("customdata", Qt::CaseInsensitive) == 0 || tag.compare("custom-data", Qt::CaseInsensitive) == 0) | |||
| { | |||
| StateCustomData* const stateCustomData(new StateCustomData()); | |||
| for (QDomNode xmlSubData = xmlData.toElement().firstChild(); ! xmlSubData.isNull(); xmlSubData = xmlSubData.nextSibling()) | |||
| { | |||
| const QString cTag(xmlSubData.toElement().tagName()); | |||
| const QString cText(xmlSubData.toElement().text().trimmed()); | |||
| if (cTag.compare("type", Qt::CaseInsensitive) == 0) | |||
| stateCustomData->type = xmlSafeStringCharDup(cText, false); | |||
| else if (cTag.compare("key", Qt::CaseInsensitive) == 0) | |||
| stateCustomData->key = xmlSafeStringCharDup(cText, false); | |||
| else if (cTag.compare("value", Qt::CaseInsensitive) == 0) | |||
| stateCustomData->value = xmlSafeStringCharDup(cText, false); | |||
| } | |||
| saveState.customData.append(stateCustomData); | |||
| } | |||
| // ------------------------------------------------------- | |||
| // Chunk | |||
| else if (tag.compare("chunk", Qt::CaseInsensitive) == 0) | |||
| { | |||
| saveState.chunk = xmlSafeStringCharDup(text, false); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| static inline | |||
| void fillXmlStringFromSaveState(QString& content, const SaveState& saveState) | |||
| { | |||
| { | |||
| QString info(" <Info>\n"); | |||
| 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_AU: | |||
| // TODO? | |||
| info += QString(" <Binary>%1</Binary>\n").arg(xmlSafeString(saveState.binary, true)); | |||
| info += QString(" <UniqueID>%1</UniqueID>\n").arg(saveState.uniqueID); | |||
| 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(saveState.binary, true)); | |||
| info += QString(" <Label>%1</Label>\n").arg(xmlSafeString(saveState.label, 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); | |||
| if (saveState.ctrlChannel < 0) | |||
| data += QString(" <ControlChannel>N</ControlChannel>\n"); | |||
| else | |||
| data += QString(" <ControlChannel>%1</ControlChannel>\n").arg(saveState.ctrlChannel+1); | |||
| content += data; | |||
| } | |||
| for (StateParameterItenerator it = saveState.parameters.begin(); it.valid(); it.next()) | |||
| { | |||
| StateParameter* const stateParameter(it.getValue()); | |||
| 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] != '\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+1); | |||
| } | |||
| parameter += " </Parameter>\n"; | |||
| content += parameter; | |||
| } | |||
| if (saveState.currentProgramIndex >= 0 && saveState.currentProgramName != nullptr && saveState.currentProgramName[0] != '\0') | |||
| { | |||
| // ignore 'default' program | |||
| if (saveState.currentProgramIndex > 0 || QString(saveState.currentProgramName).compare("default", Qt::CaseInsensitive) != 0) | |||
| { | |||
| QString program("\n"); | |||
| program += QString(" <CurrentProgramIndex>%1</CurrentProgramIndex>\n").arg(saveState.currentProgramIndex+1); | |||
| 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+1); | |||
| midiProgram += QString(" <CurrentMidiProgram>%1</CurrentMidiProgram>\n").arg(saveState.currentMidiProgram+1); | |||
| content += midiProgram; | |||
| } | |||
| for (StateCustomDataItenerator it = saveState.customData.begin(); it.valid(); it.next()) | |||
| { | |||
| StateCustomData* const stateCustomData(it.getValue()); | |||
| 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_TYPE_CHUNK) == 0 || std::strlen(stateCustomData->value) >= 128) | |||
| { | |||
| 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] != '\0') | |||
| { | |||
| QString chunk("\n"" <Chunk>\n"); | |||
| chunk += QString("%1\n").arg(saveState.chunk); | |||
| chunk += " </Chunk>\n"; | |||
| content += chunk; | |||
| } | |||
| content += " </Data>\n"; | |||
| } | |||
| void fillSaveStateFromXmlNode(SaveState& saveState, const QDomNode& xmlNode); | |||
| void fillXmlStringFromSaveState(QString& content, const SaveState& saveState); | |||
| // ----------------------------------------------------------------------- | |||