| @@ -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']: | |||