|
- /*
- * Carla Plugin bridge code
- * Copyright (C) 2012 Filipe Coelho <falktx@gmail.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
- */
-
- #ifdef BUILD_BRIDGE_PLUGIN
-
- #include "carla_bridge_client.h"
- #include "carla_plugin.h"
-
- #include <QtCore/QFile>
- #include <QtCore/QTimerEvent>
- #include <QtGui/QApplication>
- #include <QtGui/QDialog>
- #include <QtGui/QVBoxLayout>
-
- #ifdef Q_OS_UNIX
- #include <signal.h>
- #endif
-
- static int qargc = 0;
- static char** qargv = nullptr;
-
- bool qcloseNow = false;
-
- #if defined(Q_OS_UNIX)
- void closeSignalHandler(int)
- {
- qcloseNow = true;
- }
- #elif defined(Q_OS_WIN)
- BOOL WINAPI closeSignalHandler(DWORD dwCtrlType)
- {
- if (dwCtrlType == CTRL_C_EVENT)
- {
- qcloseNow = true;
- return TRUE;
- }
-
- return FALSE;
- }
- #endif
-
- void initSignalHandler()
- {
- #if defined(Q_OS_UNIX)
- struct sigaction sint, sterm;
-
- sint.sa_handler = closeSignalHandler;
- sigemptyset(&sint.sa_mask);
- sint.sa_flags |= SA_RESTART;
- sigaction(SIGINT, &sint, 0);
-
- sterm.sa_handler = closeSignalHandler;
- sigemptyset(&sterm.sa_mask);
- sterm.sa_flags |= SA_RESTART;
- sigaction(SIGTERM, &sterm, 0);
- #elif defined(Q_OS_WIN)
- SetConsoleCtrlHandler(closeSignalHandler, TRUE);
- #endif
- }
-
- CARLA_BRIDGE_START_NAMESPACE
-
- // -------------------------------------------------------------------------
- // client
-
- class CarlaPluginClient : public CarlaClient
- {
- public:
- CarlaPluginClient(CarlaToolkit* const toolkit)
- : CarlaClient(toolkit)
- {
- engine = nullptr;
- plugin = nullptr;
- }
-
- ~CarlaPluginClient()
- {
- }
-
- void setStuff(CarlaBackend::CarlaEngine* const engine_, CarlaBackend::CarlaPlugin* const plugin_)
- {
- Q_ASSERT(engine_);
- Q_ASSERT(plugin_);
-
- engine = engine_;
- plugin = plugin_;
- }
-
- // ---------------------------------------------------------------------
- // processing
-
- void setParameter(const int32_t rindex, const double value)
- {
- qDebug("CarlaPluginClient::setParameter(%i, %g)", rindex, value);
- Q_ASSERT(plugin);
-
- if (! plugin)
- return;
-
- plugin->setParameterValueByRIndex(rindex, value, true, true, false);
- }
-
- void setProgram(const uint32_t index)
- {
- qDebug("CarlaPluginClient::setProgram(%i)", index);
- Q_ASSERT(engine);
- Q_ASSERT(plugin);
- Q_ASSERT(index < plugin->programCount());
-
- if (! (plugin && engine))
- return;
- if (index >= plugin->programCount())
- return;
-
- plugin->setProgram(index, true, true, false, true);
-
- double value;
- for (uint32_t i=0; i < plugin->parameterCount(); i++)
- {
- value = plugin->getParameterValue(i);
- engine->osc_send_bridge_set_parameter_value(i, value);
- engine->osc_send_bridge_set_default_value(i, value);
- }
- }
-
- void setMidiProgram(const uint32_t index)
- {
- qDebug("CarlaPluginClient::setMidiProgram(%i)", index);
- Q_ASSERT(engine);
- Q_ASSERT(plugin);
-
- if (! (plugin && engine))
- return;
-
- plugin->setMidiProgram(index, true, true, false, true);
-
- double value;
- for (uint32_t i=0; i < plugin->parameterCount(); i++)
- {
- value = plugin->getParameterValue(i);
- engine->osc_send_bridge_set_parameter_value(i, value);
- engine->osc_send_bridge_set_default_value(i, value);
- }
- }
-
- void noteOn(const uint8_t channel, const uint8_t note, const uint8_t velo)
- {
- qDebug("CarlaPluginClient::noteOn(%i, %i, %i)", channel, note, velo);
- Q_ASSERT(plugin);
- Q_ASSERT(velo > 0);
-
- if (! plugin)
- return;
-
- plugin->sendMidiSingleNote(channel, note, velo, true, true, false);
- }
-
- void noteOff(const uint8_t channel, const uint8_t note)
- {
- qDebug("CarlaPluginClient::noteOff(%i, %i)", channel, note);
- Q_ASSERT(plugin);
-
- if (! plugin)
- return;
-
- plugin->sendMidiSingleNote(channel, note, 0, true, true, false);
- }
-
- // ---------------------------------------------------------------------
- // plugin
-
- void saveNow()
- {
- qDebug("CarlaPluginClient::saveNow()");
- Q_ASSERT(plugin);
-
- if (! plugin)
- return;
-
- plugin->prepareForSave();
-
- #if 0
- for (uint32_t i=0; i < CARLA_PLUGIN->customDataCount(); i++)
- {
- const CustomData* const cdata = CARLA_PLUGIN->customData(i);
- osc_send_bridge_custom_data(customdatatype2str(cdata->type), cdata->key, cdata->value);
- }
-
- if (CARLA_PLUGIN->hints() & PLUGIN_USES_CHUNKS)
- {
- void* data = nullptr;
- int32_t dataSize = CARLA_PLUGIN->chunkData(&data);
-
- if (data && dataSize >= 4)
- {
- QString filePath;
- filePath += "/tmp/.CarlaChunk_";
- filePath += CARLA_PLUGIN->name();
-
- QFile file(filePath);
-
- if (file.open(QIODevice::WriteOnly))
- {
- QByteArray chunk((const char*)data, dataSize);
- file.write(chunk);
- file.close();
- osc_send_bridge_chunk_data(filePath.toUtf8().constData());
- }
- }
- }
-
- osc_send_configure(CARLA_BRIDGE_MSG_SAVED, "");
- #endif
- }
-
- void setCustomData(const char* const type, const char* const key, const char* const value)
- {
- qDebug("CarlaPluginClient::setCustomData(\"%s\", \"%s\", \"%s\")", type, key, value);
- Q_ASSERT(plugin);
-
- if (! plugin)
- return;
-
- plugin->setCustomData(CarlaBackend::getCustomDataStringType(type), key, value, true);
- }
-
- void setChunkData(const char* const filePath)
- {
- qDebug("CarlaPluginClient::setChunkData(\"%s\")", filePath);
- Q_ASSERT(plugin);
-
- if (! plugin)
- return;
-
- Q_UNUSED(filePath);
-
- #if 0
- nextChunkFilePath = strdup(filePath);
-
- while (nextChunkFilePath)
- carla_msleep(25);
- #endif
- }
-
- // ---------------------------------------------------------------------
- // idle
-
- void idle()
- {
- Q_ASSERT(plugin);
-
- if (! plugin)
- return;
-
- plugin->idleGui();
- //plugin->showGui(true);
- }
-
- void showGui(const bool yesNo)
- {
- qDebug("CarlaPluginClient::showGui(%s)", bool2str(yesNo));
- Q_ASSERT(plugin);
-
- if (! plugin)
- return;
-
- plugin->showGui(yesNo);
- }
-
- // ---------------------------------------------------------------------
- // callback
-
- void handleCallback(const CarlaBackend::CallbackType action, const int value1, const int value2, const double value3)
- {
- qDebug("CarlaPluginClient::handleCallback(%s, %i, %i, %g)", CarlaBackend::CallbackType2str(action), value1, value2, value3);
-
- // FIXME - those OSC calls should be on the engine
- switch (action)
- {
- case CarlaBackend::CALLBACK_PARAMETER_VALUE_CHANGED:
- engine->osc_send_bridge_set_parameter_value(value1, value3);
- break;
- case CarlaBackend::CALLBACK_PROGRAM_CHANGED:
- engine->osc_send_bridge_set_program(value1);
- break;
- case CarlaBackend::CALLBACK_MIDI_PROGRAM_CHANGED:
- engine->osc_send_bridge_set_midi_program(value1);
- break;
- case CarlaBackend::CALLBACK_NOTE_ON:
- {
- //uint8_t mdata[4] = { 0, MIDI_STATUS_NOTE_ON, (uint8_t)value1, (uint8_t)value2 };
- //osc_send_midi(mdata);
- break;
- }
- case CarlaBackend::CALLBACK_NOTE_OFF:
- {
- //uint8_t mdata[4] = { 0, MIDI_STATUS_NOTE_OFF, (uint8_t)value1, (uint8_t)value2 };
- //osc_send_midi(mdata);
- break;
- }
- case CarlaBackend::CALLBACK_SHOW_GUI:
- //if (value1 == 0)
- //sendOscConfigure(CarlaBackend::CARLA_BRIDGE_MSG_HIDE_GUI, "");
- //quequeMessage(MESSAGE_QUIT, 0, 0, 0.0);
- break;
- case CarlaBackend::CALLBACK_RESIZE_GUI:
- qDebug("resize callback-------------------------------------------------------------------------------");
- quequeMessage(MESSAGE_RESIZE_GUI, value1, value2, 0.0);
- //if (m_toolkit)
- // m_toolkit->resize(value1, value2);
- break;
- case CarlaBackend::CALLBACK_RELOAD_PARAMETERS:
- //if (CARLA_PLUGIN)
- //{
- // for (uint32_t i=0; i < CARLA_PLUGIN->parameterCount(); i++)
- // {
- // osc_send_control(i, CARLA_PLUGIN->getParameterValue(i));
- // }
- //}
- break;
- case CarlaBackend::CALLBACK_QUIT:
- //quequeMessage(MESSAGE_QUIT, 0, 0, 0.0);
- break;
- default:
- break;
- }
- Q_UNUSED(value1);
- Q_UNUSED(value2);
- Q_UNUSED(value3);
- }
-
- // ---------------------------------------------------------------------
-
- static void callback(void* const ptr, CarlaBackend::CallbackType const action, const unsigned short, const int value1, const int value2, const double value3)
- {
- Q_ASSERT(ptr);
-
- if (! ptr)
- return;
-
- CarlaPluginClient* const client = (CarlaPluginClient*)ptr;
- client->handleCallback(action, value1, value2, value3);
- }
-
- private:
- CarlaBackend::CarlaEngine* engine;
- CarlaBackend::CarlaPlugin* plugin;
- };
-
- // -------------------------------------------------------------------------
- // toolkit
-
- class BridgeApplication : public QApplication
- {
- public:
- BridgeApplication()
- : QApplication(qargc, qargv)
- {
- msgTimer = 0;
- m_client = nullptr;
- }
-
- void exec(CarlaPluginClient* const client)
- {
- m_client = client;
- msgTimer = startTimer(50);
-
- QApplication::exec();
- }
-
- protected:
- void timerEvent(QTimerEvent* const event)
- {
- if (qcloseNow)
- return quit();
-
- if (event->timerId() == msgTimer)
- {
- if (m_client)
- {
- m_client->idle();
-
- if (! m_client->runMessages())
- killTimer(msgTimer);
- }
- }
-
- QApplication::timerEvent(event);
- }
-
- private:
- int msgTimer;
- CarlaPluginClient* m_client;
- };
-
- class CarlaToolkitPlugin : public CarlaToolkit
- {
- public:
- CarlaToolkitPlugin()
- : CarlaToolkit("carla-bridge-plugin")
- {
- qDebug("CarlaToolkitPlugin::CarlaToolkitPlugin()");
- app = nullptr;
- dialog = nullptr;
- m_resizable = false;
- }
-
- ~CarlaToolkitPlugin()
- {
- qDebug("CarlaToolkitPlugin::~CarlaToolkitPlugin()");
- Q_ASSERT(! app);
- }
-
- void init()
- {
- qDebug("CarlaToolkitPlugin::init()");
- Q_ASSERT(! app);
-
- app = new BridgeApplication;
- }
-
- void exec(CarlaClient* const client, const bool showGui)
- {
- qDebug("CarlaToolkitPlugin::exec(%p)", client);
- Q_ASSERT(app);
- Q_ASSERT(client);
-
- m_client = client;
-
- if (showGui)
- {
- show();
- }
- else
- {
- m_client->sendOscUpdate();
- m_client->sendOscBridgeUpdate();
- }
-
- app->exec((CarlaPluginClient*)client);
- }
-
- void quit()
- {
- qDebug("CarlaToolkitPlugin::quit()");
- Q_ASSERT(app);
-
- if (dialog)
- {
- dialog->close();
-
- delete dialog;
- dialog = nullptr;
- }
-
- if (app)
- {
- if (! app->closingDown())
- app->quit();
-
- delete app;
- app = nullptr;
- }
- }
-
- void show()
- {
- qDebug("CarlaToolkitPlugin::show()");
-
- if (m_client)
- ((CarlaPluginClient*)m_client)->showGui(true);
-
- if (dialog)
- dialog->show();
- }
-
- void hide()
- {
- qDebug("CarlaToolkitPlugin::hide()");
-
- if (m_client)
- ((CarlaPluginClient*)m_client)->showGui(false);
-
- if (dialog)
- dialog->show();
- }
-
- void resize(int width, int height)
- {
- qDebug("CarlaToolkitPlugin::resize(%i, %i)", width, height);
- Q_ASSERT(dialog);
-
- if (! dialog)
- return;
-
- if (m_resizable)
- dialog->resize(width, height);
- else
- dialog->setFixedSize(width, height);
- }
-
- // ---------------------------------------------------------------------
-
- void createWindow(const char* const pluginName, const bool createLayout, const bool resizable)
- {
- qDebug("CarlaToolkitPlugin::createWindow(%s, %s, %s)", pluginName, bool2str(createLayout), bool2str(resizable));
- Q_ASSERT(pluginName);
-
- m_resizable = resizable;
-
- dialog = new QDialog(nullptr);
- resize(10, 10);
-
- if (createLayout)
- {
- QVBoxLayout* const layout = new QVBoxLayout(dialog);
- dialog->setContentsMargins(0, 0, 0, 0);
- dialog->setLayout(layout);
- }
-
- dialog->setWindowTitle(QString("%1 (GUI)").arg(pluginName));
-
- #ifdef Q_OS_WIN
- if (! resizable)
- dialog->setWindowFlags(dialog->windowFlags() | Qt::MSWindowsFixedSizeDialogHint);
- #endif
- }
-
- CarlaBackend::GuiDataHandle getWindowHandle() const
- {
- return dialog;
- }
-
- // ---------------------------------------------------------------------
-
- private:
- BridgeApplication* app;
- QDialog* dialog;
- bool m_resizable;
- };
-
- CarlaToolkit* CarlaToolkit::createNew(const char* const)
- {
- return new CarlaToolkitPlugin;
- }
-
- // -------------------------------------------------------------------------
-
- CARLA_BRIDGE_END_NAMESPACE
-
- int main(int argc, char* argv[])
- {
- if (argc != 6)
- {
- qWarning("usage: %s <osc-url|\"null\"> <type> <filename> <name|\"(none)\"> <label>", argv[0]);
- return 1;
- }
-
- qargc = argc;
- qargv = argv;
-
- const char* const oscUrl = argv[1];
- const char* const stype = argv[2];
- const char* const filename = argv[3];
- const char* name = argv[4];
- const char* const label = argv[5];
-
- const bool useOsc = strcmp(oscUrl, "null");
-
- if (strcmp(name, "(none)") == 0)
- name = nullptr;
-
- CarlaBackend::PluginType itype;
-
- if (strcmp(stype, "LADSPA") == 0)
- itype = CarlaBackend::PLUGIN_LADSPA;
- else if (strcmp(stype, "DSSI") == 0)
- itype = CarlaBackend::PLUGIN_DSSI;
- else if (strcmp(stype, "LV2") == 0)
- itype = CarlaBackend::PLUGIN_LV2;
- else if (strcmp(stype, "VST") == 0)
- itype = CarlaBackend::PLUGIN_VST;
- else
- {
- itype = CarlaBackend::PLUGIN_NONE;
- qWarning("Invalid plugin type '%s'", stype);
- return 1;
- }
-
- // Init toolkit
- CarlaBridge::CarlaToolkitPlugin toolkit;
- toolkit.init();
-
- // Init client
- CarlaBridge::CarlaPluginClient client(&toolkit);
-
- // Init OSC
- if (useOsc && ! client.oscInit(oscUrl))
- {
- toolkit.quit();
- return -1;
- }
-
- // Init backend engine
- CarlaBackend::CarlaEngineJack engine;
- engine.setCallback(client.callback, &client);
-
- // bridge client <-> engine
- client.registerOscEngine(&engine);
-
- // Init engine
- QString engName = QString("%1 (master)").arg(name ? name : label);
- engName.truncate(engine.maxClientNameSize());
-
- if (! engine.init(engName.toUtf8().constData()))
- {
- qWarning("Bridge engine failed to start, error was:\n%s", CarlaBackend::getLastError());
- engine.close();
- toolkit.quit();
- return 2;
- }
-
- /// Init plugin
- short id = engine.addPlugin(itype, filename, name, label);
- int ret;
-
- if (id >= 0 && id < CarlaBackend::MAX_PLUGINS)
- {
- CarlaBackend::CarlaPlugin* const plugin = engine.getPlugin(id);
- client.setStuff(&engine, plugin);
-
- // create window if needed
- bool guiResizable;
- CarlaBackend::GuiType guiType;
- plugin->getGuiInfo(&guiType, &guiResizable);
-
- if (guiType == CarlaBackend::GUI_INTERNAL_QT4 || guiType == CarlaBackend::GUI_INTERNAL_COCOA || guiType == CarlaBackend::GUI_INTERNAL_HWND || guiType == CarlaBackend::GUI_INTERNAL_X11)
- {
- toolkit.createWindow(plugin->name(), (guiType == CarlaBackend::GUI_INTERNAL_QT4), guiResizable);
- plugin->setGuiData(toolkit.getWindowHandle());
- }
-
- if (! useOsc)
- plugin->setActive(true, false, false);
-
- ret = 0;
- }
- else
- {
- qWarning("Plugin failed to load, error was:\n%s", CarlaBackend::getLastError());
- ret = 1;
- }
-
- if (ret == 0)
- {
- initSignalHandler();
- toolkit.exec(&client, !useOsc);
- }
-
- engine.removeAllPlugins();
- engine.close();
-
- // Close OSC
- if (useOsc)
- {
- client.sendOscExiting();
- client.oscClose();
- }
-
- // Close toolkit
- toolkit.quit();
-
- return ret;
- }
-
- #endif // BUILD_BRIDGE_PLUGIN
|