Browse Source

Continue

tags/1.9.4
falkTX 11 years ago
parent
commit
1bffb3f79a
17 changed files with 695 additions and 578 deletions
  1. +17
    -8
      source/backend/Makefile.mk
  2. +5
    -2
      source/backend/engine/CarlaEngine.cpp
  3. +6
    -3
      source/backend/engine/CarlaEngineNative.cpp
  4. +8
    -8
      source/backend/engine/Makefile
  5. +1
    -0
      source/backend/plugin/BridgePlugin.cpp
  6. +4
    -0
      source/backend/plugin/CarlaPlugin.cpp
  7. +2
    -0
      source/backend/plugin/CarlaPluginInternal.hpp
  8. +1
    -2
      source/backend/plugin/CarlaPluginThread.cpp
  9. +1
    -2
      source/backend/plugin/DssiPlugin.cpp
  10. +2
    -0
      source/backend/plugin/LinuxSamplerPlugin.cpp
  11. +1
    -2
      source/backend/plugin/Lv2Plugin.cpp
  12. +59
    -22
      source/backend/plugin/Makefile
  13. +2
    -0
      source/backend/plugin/NativePlugin.cpp
  14. +1
    -2
      source/backend/plugin/VstPlugin.cpp
  15. +1
    -1
      source/utils/CarlaLibCounter.hpp
  16. +567
    -0
      source/utils/CarlaStateUtils.cpp
  17. +17
    -526
      source/utils/CarlaStateUtils.hpp

+ 17
- 8
source/backend/Makefile.mk View File

@@ -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)

# --------------------------------------------------------------
# ----------------------------------------------------------------------------------------------------------------------------

+ 5
- 2
source/backend/engine/CarlaEngine.cpp View File

@@ -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());


+ 6
- 3
source/backend/engine/CarlaEngineNative.cpp View File

@@ -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());


+ 8
- 8
source/backend/engine/Makefile View File

@@ -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 $@

# ----------------------------------------------------------------------------------------------------------------------------

+ 1
- 0
source/backend/plugin/BridgePlugin.cpp View File

@@ -20,6 +20,7 @@

#ifndef BUILD_BRIDGE

#include "CarlaBackendUtils.hpp"
#include "CarlaBridgeUtils.hpp"
#include "CarlaShmUtils.hpp"



+ 4
- 0
source/backend/plugin/CarlaPlugin.cpp View File

@@ -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



+ 2
- 0
source/backend/plugin/CarlaPluginInternal.hpp View File

@@ -27,6 +27,8 @@
#include "CarlaMutex.hpp"
#include "RtLinkedList.hpp"

#include "CarlaMIDI.h"

#include <cmath>

#ifdef HAVE_JUCE


+ 1
- 2
source/backend/plugin/CarlaPluginThread.cpp View File

@@ -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>


+ 1
- 2
source/backend/plugin/DssiPlugin.cpp View File

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



+ 2
- 0
source/backend/plugin/LinuxSamplerPlugin.cpp View File

@@ -26,6 +26,8 @@

#ifdef WANT_LINUXSAMPLER

#include "CarlaBackendUtils.hpp"

#include "linuxsampler/EngineFactory.h"
#include <linuxsampler/Sampler.h>



+ 1
- 2
source/backend/plugin/Lv2Plugin.cpp View File

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



+ 59
- 22
source/backend/plugin/Makefile View File

@@ -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 $@

# --------------------------------------------------------------
# ----------------------------------------------------------------------------------------------------------------------------

+ 2
- 0
source/backend/plugin/NativePlugin.cpp View File

@@ -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);


+ 1
- 2
source/backend/plugin/VstPlugin.cpp View File

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



+ 1
- 1
source/utils/CarlaLibCounter.hpp View File

@@ -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);



+ 567
- 0
source/utils/CarlaStateUtils.cpp View File

@@ -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("&","&amp;").replace("<","&lt;").replace(">","&gt;").replace("'","&apos;").replace("\"","&quot;");
else
return newString.replace("&amp;","&").replace("&lt;","<").replace("&gt;",">").replace("&apos;","'").replace("&quot;","\"");
}

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

+ 17
- 526
source/utils/CarlaStateUtils.hpp View File

@@ -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("&","&amp;").replace("<","&lt;").replace(">","&gt;").replace("'","&apos;").replace("\"","&quot;");
else
return newString.replace("&amp;","&").replace("&lt;","<").replace("&gt;",">").replace("&apos;","'").replace("&quot;","\"");
}

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);

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



Loading…
Cancel
Save