@@ -112,7 +112,6 @@ c++/carla-native/zynaddsubfx/UI/VirKeyboard.h | |||
_/ | |||
all-recheck | |||
c++/caitlyn/ | |||
c++/carla/ | |||
c++/carla-backend/carla-dynamic.lv2/ | |||
c++/carla-backend/carla_backend_lv2.cpp | |||
c++/carla-backend/carla_backend_vst.cpp | |||
@@ -20,10 +20,14 @@ | |||
#include "carla_bridge_client.hpp" | |||
#include "carla_bridge_toolkit.hpp" | |||
#include "carla_plugin.hpp" | |||
#include "../carla/Shared.hpp" | |||
#include <set> | |||
#include <QtCore/QDir> | |||
#include <QtCore/QFile> | |||
#include <QtCore/QTextStream> | |||
#include <QtCore/QThread> | |||
#include <QtXml/QDomDocument> | |||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) | |||
# include <QtWidgets/QApplication> | |||
@@ -221,12 +225,12 @@ public: | |||
m_uiShow = showUI; | |||
} | |||
void guiClosedCallback(); | |||
protected: | |||
QApplication* app; | |||
CarlaBackend::CarlaPluginGUI* gui; | |||
void guiClosedCallback(); | |||
private: | |||
bool m_hasUI; | |||
bool m_uiQuit; | |||
@@ -253,6 +257,10 @@ public: | |||
msgTimerGUI = 0; | |||
msgTimerOSC = 0; | |||
needsResize = 0; | |||
nextWidth = 0; | |||
nextHeight = 0; | |||
engine = nullptr; | |||
plugin = nullptr; | |||
} | |||
@@ -276,15 +284,12 @@ public: | |||
if (! plugin) | |||
return; | |||
// create window if needed | |||
bool guiResizable; | |||
CarlaBackend::GuiType guiType; | |||
plugin->getGuiInfo(&guiType, &guiResizable); | |||
CarlaBridgeToolkitPlugin* const plugToolkit = (CarlaBridgeToolkitPlugin*)m_toolkit; | |||
qWarning("----------------------------------------------------- trying..., %s", CarlaBackend::GuiType2Str(guiType)); | |||
if (guiType == CarlaBackend::GUI_INTERNAL_QT4 || guiType == CarlaBackend::GUI_INTERNAL_COCOA || guiType == CarlaBackend::GUI_INTERNAL_HWND || guiType == CarlaBackend::GUI_INTERNAL_X11) | |||
{ | |||
plugin->setGuiContainer(plugToolkit->getContainer()); | |||
@@ -332,10 +337,264 @@ public: | |||
CARLA_ASSERT(plugin); | |||
this->plugin = plugin; | |||
// load carla plugin preset if possible | |||
if (const char* const pName = plugin->name()) | |||
{ | |||
QFile pFile(QDir::currentPath() + QDir::separator() + pName + ".carxs"); | |||
qDebug("Trying to load plugin preset file '%s'", pFile.fileName().toUtf8().constData()); | |||
if (! /*(*/pFile.exists() /*&& pFile.isReadable())*/) | |||
{ | |||
qDebug("Plugin preset file doesn't exist or is not readable"); | |||
return; | |||
} | |||
if (! pFile.open(QFile::ReadOnly)) | |||
{ | |||
qWarning("Plugin preset file read failed"); | |||
return; | |||
} | |||
QDomDocument xml; | |||
xml.setContent(pFile.readAll()); | |||
QDomElement xmlNode(xml.documentElement()); | |||
if (xmlNode.tagName() == "CARLA-PRESET") | |||
{ | |||
loadStateDict(getSaveStateDictFromXML(xmlNode)); | |||
} | |||
else | |||
qWarning("Plugin preset file is not valid or corrupted"); | |||
pFile.close(); | |||
} | |||
} | |||
// --------------------------------------------------------------------- | |||
void loadStateDict(const CarlaSaveState* const content) | |||
{ | |||
CARLA_ASSERT(content); | |||
if (! content) | |||
return; | |||
qDebug("Loading plugin state now..."); | |||
// --------------------------------------------------------------------- | |||
// Part 1 - set custom data (except chunks) | |||
foreach (const CarlaStateCustomData& customData, content->customData) | |||
{ | |||
if (customData.type != CUSTOM_DATA_CHUNK) | |||
{ | |||
const char* const type = customData.type.toUtf8().constData(); | |||
const char* const key = customData.key.toUtf8().constData(); | |||
const char* const value = customData.value.toUtf8().constData(); | |||
plugin->setCustomData(type, key, value, true); | |||
} | |||
} | |||
// --------------------------------------------------------------------- | |||
// Part 2 - set program | |||
int32_t programId = -1; | |||
if (! content->currentProgramName.isEmpty()) | |||
{ | |||
const uint32_t programCount = plugin->programCount(); | |||
char strBuf[STR_MAX] = { 0 }; | |||
plugin->getProgramName(content->currentProgramIndex, strBuf); | |||
QString testProgramName(strBuf); | |||
// Program name matches | |||
if (content->currentProgramName == testProgramName) | |||
{ | |||
programId = content->currentProgramIndex; | |||
} | |||
// index < count | |||
else if (content->currentProgramIndex < (int32_t)programCount) | |||
{ | |||
programId = content->currentProgramIndex; | |||
} | |||
// index not valid, try to find by name | |||
else | |||
{ | |||
for (uint32_t i=0; i < programCount; i++) | |||
{ | |||
plugin->getProgramName(i, strBuf); | |||
testProgramName = QString(strBuf); | |||
if (content->currentProgramName == testProgramName) | |||
{ | |||
programId = i; | |||
break; | |||
} | |||
} | |||
} | |||
} | |||
// set program now, if valid | |||
if (programId >= 0) | |||
{ | |||
plugin->setProgram(programId, true, true, false, true); | |||
} | |||
// --------------------------------------------------------------------- | |||
// Part 3 - set midi program | |||
if (content->currentMidiBank >= 0 and content->currentMidiProgram >= 0) | |||
{ | |||
const uint32_t midiProgramCount = plugin->midiProgramCount(); | |||
for (uint32_t i=0; i < midiProgramCount; i++) | |||
{ | |||
const MidiProgramData* const midiProgramData = plugin->midiProgramData(i); | |||
if ((int32_t)midiProgramData->bank == content->currentMidiBank && (int32_t)midiProgramData->program == content->currentMidiProgram) | |||
{ | |||
plugin->setMidiProgram(i, true, true, false, true); | |||
break; | |||
} | |||
} | |||
} | |||
// --------------------------------------------------------------------- | |||
// Part 4a - get plugin parameter symbols | |||
struct ParamSymbol { | |||
uint32_t index; | |||
QString symbol; | |||
ParamSymbol() {} | |||
ParamSymbol(uint32_t index_, const char* symbol_) | |||
: index(index_), | |||
symbol(symbol_) {} | |||
}; | |||
QVector<ParamSymbol> paramSymbols; | |||
foreach (const CarlaStateParameter& parameter, content->parameters) | |||
{ | |||
if (! parameter.symbol.isEmpty()) | |||
{ | |||
char strBuf[STR_MAX] = { 0 }; | |||
plugin->getParameterSymbol(parameter.index, strBuf); | |||
if (strBuf[0] != 0) | |||
{ | |||
ParamSymbol ps(parameter.index, strBuf); | |||
paramSymbols.append(ps); | |||
} | |||
} | |||
} | |||
// --------------------------------------------------------------------- | |||
// Part 4b - set parameter values (carefully) | |||
const double sampleRate = engine->getSampleRate(); | |||
foreach (const CarlaStateParameter& parameter, content->parameters) | |||
{ | |||
int32_t index = -1; | |||
if (content->type == "LADSPA") | |||
{ | |||
// Try to set by symbol, otherwise use index | |||
if (! parameter.symbol.isEmpty()) | |||
{ | |||
bool breaked = false; | |||
foreach (const ParamSymbol& ps, paramSymbols) | |||
{ | |||
if (parameter.symbol == ps.symbol) | |||
{ | |||
index = ps.index; | |||
breaked = true; | |||
break; | |||
} | |||
} | |||
if (! breaked) | |||
index = parameter.index; | |||
} | |||
else | |||
index = parameter.index; | |||
} | |||
else if (content->type == "LV2") | |||
{ | |||
// Symbol only | |||
if (! parameter.symbol.isEmpty()) | |||
{ | |||
bool breaked = false; | |||
foreach (const ParamSymbol& ps, paramSymbols) | |||
{ | |||
if (parameter.symbol == ps.symbol) | |||
{ | |||
index = ps.index; | |||
breaked = true; | |||
break; | |||
} | |||
} | |||
if (! breaked) | |||
qWarning("Failed to find LV2 parameter symbol for '%s')", parameter.symbol.toUtf8().constData()); | |||
} | |||
else | |||
qWarning("LV2 Plugin parameter '%s' has no symbol", parameter.name.toUtf8().constData()); | |||
} | |||
else | |||
{ | |||
// Index only | |||
index = parameter.index; | |||
} | |||
// Now set parameter | |||
if (index >= 0) | |||
{ | |||
const ParameterData* const paramData = plugin->parameterData(index); | |||
double value = parameter.value; | |||
if (paramData->hints & PARAMETER_USES_SAMPLERATE) | |||
value *= sampleRate; | |||
plugin->setParameterValue(index, value, true, true, false); | |||
plugin->setParameterMidiCC(index, parameter.midiCC, true, false); | |||
plugin->setParameterMidiChannel(index, parameter.midiChannel-1, true, false); | |||
} | |||
else | |||
qWarning("Could not set parameter data for '%s')", parameter.name.toUtf8().constData()); | |||
} | |||
// --------------------------------------------------------------------- | |||
// Part 5 - set chunk data | |||
foreach (const CarlaStateCustomData& customData, content->customData) | |||
{ | |||
if (customData.type == CUSTOM_DATA_CHUNK) | |||
{ | |||
const char* const type = customData.type.toUtf8().constData(); | |||
const char* const key = customData.key.toUtf8().constData(); | |||
const char* const value = customData.value.toUtf8().constData(); | |||
plugin->setCustomData(type, key, value, true); | |||
} | |||
} | |||
if (! content->chunk.isEmpty()) | |||
plugin->setChunkData(content->chunk.toUtf8().constData()); | |||
qDebug("Loading plugin state now finished"); | |||
} | |||
void guiClosed() | |||
{ | |||
CARLA_ASSERT(engine); | |||
@@ -352,16 +611,6 @@ public: | |||
plugin->showGui(yesNo); | |||
} | |||
// --------------------------------------------------------------------- | |||
static void callback(void* const ptr, CarlaBackend::CallbackType const action, const unsigned short, const int value1, const int value2, const double value3, const char* const valueStr) | |||
{ | |||
CARLA_ASSERT(ptr); | |||
if (CarlaPluginClient* const _this_ = (CarlaPluginClient*)ptr) | |||
_this_->handleCallback(action, value1, value2, value3, valueStr); | |||
} | |||
// --------------------------------------------------------------------- | |||
// processing | |||
@@ -534,19 +783,119 @@ public: | |||
} | |||
// --------------------------------------------------------------------- | |||
// callback | |||
static void callback(void* const ptr, CarlaBackend::CallbackType const action, const unsigned short, const int value1, const int value2, const double value3, const char* const valueStr) | |||
{ | |||
CARLA_ASSERT(ptr); | |||
if (CarlaPluginClient* const _this_ = (CarlaPluginClient*)ptr) | |||
_this_->handleCallback(action, value1, value2, value3, valueStr); | |||
} | |||
// --------------------------------------------------------------------- | |||
protected: | |||
int msgTimerGUI, msgTimerOSC; | |||
int msgTimerGUI; | |||
int msgTimerOSC; | |||
bool needsResize; | |||
int nextWidth; | |||
int nextHeight; | |||
CarlaBackend::CarlaEngine* engine; | |||
CarlaBackend::CarlaPlugin* plugin; | |||
std::set<int32_t> parametersToUpdate; | |||
void handleCallback(const CarlaBackend::CallbackType action, const int value1, const int value2, const double value3, const char* const valueStr) | |||
{ | |||
qDebug("CarlaPluginClient::handleCallback(%s, %i, %i, %g \"%s\")", CarlaBackend::CallbackType2Str(action), value1, value2, value3, valueStr); | |||
CARLA_BACKEND_USE_NAMESPACE | |||
qDebug("CarlaPluginClient::handleCallback(%s, %i, %i, %g \"%s\")", CallbackType2Str(action), value1, value2, value3, valueStr); | |||
if (! engine) | |||
return; | |||
switch (action) | |||
{ | |||
case CALLBACK_DEBUG: | |||
break; | |||
case CALLBACK_PARAMETER_VALUE_CHANGED: | |||
parametersToUpdate.insert(value1); | |||
break; | |||
case CALLBACK_PARAMETER_MIDI_CHANNEL_CHANGED: | |||
// todo, unused? | |||
break; | |||
case CALLBACK_PARAMETER_MIDI_CC_CHANGED: | |||
// todo, unused? | |||
break; | |||
case CALLBACK_PROGRAM_CHANGED: | |||
engine->osc_send_bridge_set_program(value1); | |||
break; | |||
case CALLBACK_MIDI_PROGRAM_CHANGED: | |||
engine->osc_send_bridge_set_midi_program(value1); | |||
break; | |||
case CALLBACK_NOTE_ON: | |||
// todo | |||
break; | |||
case CALLBACK_NOTE_OFF: | |||
// todo | |||
break; | |||
case CALLBACK_SHOW_GUI: | |||
if (value1 == 0) | |||
{ | |||
CarlaBridgeToolkitPlugin* const plugToolkit = (CarlaBridgeToolkitPlugin*)m_toolkit; | |||
plugToolkit->guiClosedCallback(); | |||
} | |||
break; | |||
case CALLBACK_RESIZE_GUI: | |||
nextWidth = value1; | |||
nextHeight = value2; | |||
needsResize = true; | |||
break; | |||
case CALLBACK_UPDATE: | |||
// todo | |||
break; | |||
case CALLBACK_RELOAD_INFO: | |||
// todo | |||
break; | |||
case CALLBACK_RELOAD_PARAMETERS: | |||
// todo | |||
break; | |||
case CALLBACK_RELOAD_PROGRAMS: | |||
// todo | |||
break; | |||
case CALLBACK_RELOAD_ALL: | |||
// todo | |||
break; | |||
case CALLBACK_NSM_ANNOUNCE: | |||
case CALLBACK_NSM_OPEN1: | |||
case CALLBACK_NSM_OPEN2: | |||
case CALLBACK_NSM_SAVE: | |||
break; | |||
case CALLBACK_ERROR: | |||
break; | |||
case CALLBACK_QUIT: | |||
m_toolkit->quit(); | |||
break; | |||
} | |||
} | |||
void timerEvent(QTimerEvent* const event) | |||
@@ -579,7 +928,6 @@ protected: | |||
void CarlaBridgeToolkitPlugin::show() | |||
{ | |||
qDebug("----------------------------------------------------------------------------------------------------------"); | |||
qDebug("CarlaBridgeToolkitPlugin::show()"); | |||
CARLA_ASSERT(gui); | |||
@@ -1,9 +1,9 @@ | |||
# QtCreator project file | |||
contains(QT_VERSION, ^5.*) { | |||
QT = core widgets | |||
QT = core widgets xml | |||
} else { | |||
QT = core gui | |||
QT = core gui xml | |||
} | |||
CONFIG = debug link_pkgconfig qt warn_on | |||
@@ -25,6 +25,13 @@ HEADERS = \ | |||
../carla_bridge_osc.hpp \ | |||
../carla_bridge_toolkit.hpp \ | |||
# carla | |||
SOURCES += \ | |||
../../carla/Shared.cpp | |||
HEADERS += \ | |||
../../carla/Shared.hpp | |||
# carla-engine | |||
SOURCES += \ | |||
../../carla-engine/carla_engine.cpp \ | |||
@@ -0,0 +1,257 @@ | |||
/* | |||
* Carla (frontend) | |||
* Copyright (C) 2012 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 COPYING file | |||
*/ | |||
#include "Shared.hpp" | |||
//#define __STDC_LIMIT_MACROS | |||
//#include <cstdint> | |||
CARLA_BACKEND_USE_NAMESPACE | |||
// ------------------------------------------------------------------------------------------------ | |||
// Carla Host object | |||
CarlaHostObject Carla; | |||
// ------------------------------------------------------------------------------------------------------------ | |||
// Carla XML helpers | |||
const CarlaSaveState* getSaveStateDictFromXML(const QDomNode& xmlNode) | |||
{ | |||
static CarlaSaveState saveState; | |||
saveState.reset(); | |||
QDomNode node(xmlNode.firstChild()); | |||
while (! node.isNull()) | |||
{ | |||
// ------------------------------------------------------ | |||
// Info | |||
if (node.toElement().tagName() == "Info") | |||
{ | |||
QDomNode xmlInfo(node.toElement().firstChild()); | |||
while (! xmlInfo.isNull()) | |||
{ | |||
const QString tag = xmlInfo.toElement().tagName(); | |||
const QString text = xmlInfo.toElement().text(); //.strip(); | |||
if (tag == "Type") | |||
saveState.type = text; | |||
else if (tag == "Name") | |||
saveState.name = xmlSafeString(text, false); | |||
else if (tag == "Label" || tag == "URI") | |||
saveState.label = xmlSafeString(text, false); | |||
else if (tag == "Binary") | |||
saveState.binary = xmlSafeString(text, false); | |||
else if (tag == "UniqueID") | |||
{ | |||
bool ok; | |||
long uniqueID = text.toLong(&ok); | |||
if (ok) saveState.uniqueID = uniqueID; | |||
} | |||
xmlInfo = xmlInfo.nextSibling(); | |||
} | |||
} | |||
// ------------------------------------------------------ | |||
// Data | |||
else if (node.toElement().tagName() == "Data") | |||
{ | |||
QDomNode xmlData(node.toElement().firstChild()); | |||
while (! xmlData.isNull()) | |||
{ | |||
const QString tag = xmlData.toElement().tagName(); | |||
const QString text = xmlData.toElement().text(); //.strip(); | |||
// ---------------------------------------------- | |||
// Internal Data | |||
if (tag == "Active") | |||
{ | |||
saveState.active = bool(text == "Yes"); | |||
} | |||
else if (tag == "DryWet") | |||
{ | |||
bool ok; | |||
double value = text.toDouble(&ok); | |||
if (ok) saveState.dryWet = value; | |||
} | |||
else if (tag == "Volume") | |||
{ | |||
bool ok; | |||
double value = text.toDouble(&ok); | |||
if (ok) saveState.volume = value; | |||
} | |||
else if (tag == "Balance-Left") | |||
{ | |||
bool ok; | |||
double value = text.toDouble(&ok); | |||
if (ok) saveState.balanceLeft = value; | |||
} | |||
else if (tag == "Balance-Right") | |||
{ | |||
bool ok; | |||
double value = text.toDouble(&ok); | |||
if (ok) saveState.balanceRight = value; | |||
} | |||
// ---------------------------------------------- | |||
// Program (current) | |||
else if (tag == "CurrentProgramIndex") | |||
{ | |||
bool ok; | |||
int value = text.toInt(&ok); | |||
if (ok) saveState.currentProgramIndex = value; | |||
} | |||
else if (tag == "CurrentProgramName") | |||
{ | |||
saveState.currentProgramName = xmlSafeString(text, false); | |||
} | |||
// ---------------------------------------------- | |||
// Midi Program (current) | |||
else if (tag == "CurrentMidiBank") | |||
{ | |||
bool ok; | |||
int value = text.toInt(&ok); | |||
if (ok) saveState.currentMidiBank = value; | |||
} | |||
else if (tag == "CurrentMidiProgram") | |||
{ | |||
bool ok; | |||
int value = text.toInt(&ok); | |||
if (ok) saveState.currentMidiProgram = value; | |||
} | |||
// ---------------------------------------------- | |||
// Parameters | |||
else if (tag == "Parameter") | |||
{ | |||
CarlaStateParameter stateParameter; | |||
QDomNode xmlSubData(xmlData.toElement().firstChild()); | |||
while (! xmlSubData.isNull()) | |||
{ | |||
const QString pTag = xmlSubData.toElement().tagName(); | |||
const QString pText = xmlSubData.toElement().text(); //.strip(); | |||
if (pTag == "index") | |||
{ | |||
bool ok; | |||
uint index = pText.toUInt(&ok); | |||
if (ok) stateParameter.index = index; | |||
} | |||
else if (pTag == "name") | |||
{ | |||
stateParameter.name = xmlSafeString(pText, false); | |||
} | |||
else if (pTag == "symbol") | |||
{ | |||
stateParameter.symbol = xmlSafeString(pText, false); | |||
} | |||
else if (pTag == "value") | |||
{ | |||
bool ok; | |||
double value = pText.toDouble(&ok); | |||
if (ok) stateParameter.value = value; | |||
} | |||
else if (pTag == "midiChannel") | |||
{ | |||
bool ok; | |||
uint channel = pText.toUInt(&ok); | |||
if (ok && channel < 16) | |||
stateParameter.midiChannel = channel; | |||
} | |||
else if (pTag == "midiCC") | |||
{ | |||
bool ok; | |||
int cc = pText.toInt(&ok); | |||
if (ok && cc < INT16_MAX) | |||
stateParameter.midiCC = cc; | |||
} | |||
xmlSubData = xmlSubData.nextSibling(); | |||
} | |||
saveState.parameters.append(stateParameter); | |||
} | |||
// ---------------------------------------------- | |||
// Custom Data | |||
else if (tag == "CustomData") | |||
{ | |||
CarlaStateCustomData stateCustomData; | |||
QDomNode xmlSubData(xmlData.toElement().firstChild()); | |||
while (! xmlSubData.isNull()) | |||
{ | |||
const QString cTag = xmlSubData.toElement().tagName(); | |||
const QString cText = xmlSubData.toElement().text(); //.strip(); | |||
if (cTag == "type") | |||
stateCustomData.type = xmlSafeString(cText, false); | |||
else if (cTag == "key") | |||
stateCustomData.key = xmlSafeString(cText, false); | |||
else if (cTag == "value") | |||
stateCustomData.value = xmlSafeString(cText, false); | |||
xmlSubData = xmlSubData.nextSibling(); | |||
} | |||
saveState.customData.append(stateCustomData); | |||
} | |||
// ---------------------------------------------- | |||
// Chunk | |||
else if (tag == "Chunk") | |||
{ | |||
saveState.chunk = xmlSafeString(text, false); | |||
} | |||
// ---------------------------------------------- | |||
xmlData = xmlData.nextSibling(); | |||
} | |||
} | |||
// ------------------------------------------------------ | |||
node = node.nextSibling(); | |||
} | |||
return &saveState; | |||
} | |||
QString xmlSafeString(QString string, const bool toXml) | |||
{ | |||
if (toXml) | |||
return string.replace("&", "&").replace("<","<").replace(">",">").replace("'","'").replace("\"","""); | |||
else | |||
return string.replace("&", "&").replace("<","<").replace(">",">").replace("'","'").replace(""","\""); | |||
} |
@@ -0,0 +1,151 @@ | |||
/* | |||
* Carla (frontend) | |||
* Copyright (C) 2012 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 COPYING file | |||
*/ | |||
#ifndef SHARED_HPP | |||
#define SHARED_HPP | |||
#include "carla_backend.hpp" | |||
#include <QtCore/QString> | |||
#include <QtCore/QVector> | |||
#include <QtXml/QDomNode> | |||
CARLA_BACKEND_USE_NAMESPACE | |||
#define VERSION "0.5.0" | |||
// ------------------------------------------------------------------------------------------------ | |||
// Carla Host object | |||
struct CarlaHostObject { | |||
void* host; | |||
void* gui; | |||
bool isControl; | |||
ProcessMode processMode; | |||
unsigned int maxParameters; | |||
CarlaHostObject() | |||
: host(nullptr), | |||
gui(nullptr), | |||
isControl(false), | |||
processMode(PROCESS_MODE_CONTINUOUS_RACK), | |||
maxParameters(MAX_PARAMETERS) {} | |||
}; | |||
extern CarlaHostObject Carla; | |||
// ------------------------------------------------------------------------------------------------ | |||
// Carla GUI stuff | |||
#define ICON_STATE_NULL 0 | |||
#define ICON_STATE_WAIT 1 | |||
#define ICON_STATE_OFF 2 | |||
#define ICON_STATE_ON 3 | |||
#define PALETTE_COLOR_NONE 0 | |||
#define PALETTE_COLOR_WHITE 1 | |||
#define PALETTE_COLOR_RED 2 | |||
#define PALETTE_COLOR_GREEN 3 | |||
#define PALETTE_COLOR_BLUE 4 | |||
#define PALETTE_COLOR_YELLOW 5 | |||
#define PALETTE_COLOR_ORANGE 6 | |||
#define PALETTE_COLOR_BROWN 7 | |||
#define PALETTE_COLOR_PINK 8 | |||
struct CarlaStateParameter { | |||
uint32_t index; | |||
QString name; | |||
QString symbol; | |||
double value; | |||
uint8_t midiChannel; | |||
int16_t midiCC; | |||
CarlaStateParameter() | |||
: index(0), | |||
value(0.0), | |||
midiChannel(1), | |||
midiCC(-1) {} | |||
}; | |||
struct CarlaStateCustomData { | |||
QString type; | |||
QString key; | |||
QString value; | |||
CarlaStateCustomData() {} | |||
}; | |||
struct CarlaSaveState { | |||
QString type; | |||
QString name; | |||
QString label; | |||
QString binary; | |||
long uniqueID; | |||
bool active; | |||
double dryWet; | |||
double volume; | |||
double balanceLeft; | |||
double balanceRight; | |||
QVector<CarlaStateParameter> parameters; | |||
int32_t currentProgramIndex; | |||
QString currentProgramName; | |||
int32_t currentMidiBank; | |||
int32_t currentMidiProgram; | |||
QVector<CarlaStateCustomData> customData; | |||
QString chunk; | |||
CarlaSaveState() | |||
: uniqueID(0), | |||
active(false), | |||
dryWet(1.0), | |||
volume(1.0), | |||
balanceLeft(-1.0), | |||
balanceRight(1.0), | |||
currentProgramIndex(-1), | |||
currentMidiBank(-1), | |||
currentMidiProgram(-1) {} | |||
void reset() | |||
{ | |||
type.clear(); | |||
name.clear(); | |||
label.clear(); | |||
binary.clear(); | |||
uniqueID = 0; | |||
active = false; | |||
dryWet = 1.0; | |||
volume = 1.0; | |||
balanceLeft = -1.0; | |||
balanceRight = 1.0; | |||
parameters.clear(); | |||
currentProgramIndex = -1; | |||
currentProgramName.clear(); | |||
currentMidiBank = -1; | |||
currentMidiProgram = -1; | |||
customData.clear(); | |||
chunk.clear(); | |||
} | |||
}; | |||
// ------------------------------------------------------------------------------------------------------------ | |||
// Carla XML helpers | |||
const CarlaSaveState* getSaveStateDictFromXML(const QDomNode& xmlNode); | |||
QString xmlSafeString(QString string, const bool toXml); | |||
#endif // SHARED_HPP |
@@ -12,6 +12,10 @@ GUI: | |||
------------------- | |||
- APPS - | |||
Cadence: | |||
- add freq info to systray tooltip | |||
- add freq Hz change | |||
Claudia: | |||
- Cleanup DB | |||
- Handle sample-rate changes in JACK (made possible by switch-master) | |||
@@ -267,6 +267,9 @@ CarlaSaveState = { | |||
'Chunk': None | |||
} | |||
# ------------------------------------------------------------------------------------------------------------ | |||
# Carla XML helpers | |||
def getSaveStateDictFromXML(xmlNode): | |||
saveState = deepcopy(CarlaSaveState) | |||
@@ -378,7 +381,7 @@ def getSaveStateDictFromXML(xmlNode): | |||
cText = xmlSubData.toElement().text().strip() | |||
if cTag == "type": | |||
stateCustomData['type'] = cText | |||
stateCustomData['type'] = xmlSafeString(cText, False) | |||
elif cTag == "key": | |||
stateCustomData['key'] = xmlSafeString(cText, False) | |||
elif cTag == "value": | |||
@@ -1751,7 +1754,7 @@ class PluginWidget(QFrame, ui_carla_plugin.Ui_PluginWidget): | |||
# Part 1 - set custom data (except binary/chunks) | |||
for customData in content['CustomData']: | |||
if customData['type'] not in (CUSTOM_DATA_BINARY, CUSTOM_DATA_CHUNK): | |||
if customData['type'] != CUSTOM_DATA_CHUNK: | |||
Carla.host.set_custom_data(self.m_pluginId, customData['type'], customData['key'], customData['value']) | |||
# --------------------------------------------------------------------- | |||
@@ -1763,7 +1766,7 @@ class PluginWidget(QFrame, ui_carla_plugin.Ui_PluginWidget): | |||
programCount = Carla.host.get_program_count(self.m_pluginId) | |||
testProgramName = cString(Carla.host.get_program_name(self.m_pluginId, content['CurrentProgramIndex'])) | |||
# Program index and name matches | |||
# Program name matches | |||
if content['CurrentProgramName'] == testProgramName: | |||
programId = content['CurrentProgramIndex'] | |||
@@ -1863,7 +1866,7 @@ class PluginWidget(QFrame, ui_carla_plugin.Ui_PluginWidget): | |||
# Part 5 - set chunk data | |||
for customData in content['CustomData']: | |||
if customData['type'] in (CUSTOM_DATA_BINARY, CUSTOM_DATA_CHUNK): | |||
if customData['type'] == CUSTOM_DATA_CHUNK: | |||
Carla.host.set_custom_data(self.m_pluginId, customData['type'], customData['key'], customData['value']) | |||
if content['Chunk']: | |||