/* * Carla Backend * Copyright (C) 2011-2012 Filipe Coelho * * 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 "carla_threads.h" #include "carla_plugin.h" #include #include // ----------------------------------------------------------------------- // CarlaCheckThread CarlaCheckThread::CarlaCheckThread(CarlaBackend::CarlaEngine* const engine_, QObject* const parent) : QThread(parent), engine(engine_) { qDebug("CarlaCheckThread::CarlaCheckThread(%p)", parent); } CarlaCheckThread::~CarlaCheckThread() { qDebug("CarlaCheckThread::~CarlaCheckThread()"); } void CarlaCheckThread::stopNow() { m_stopNow = true; // TESTING - let processing finish first QMutexLocker(&this->mutex); // FIXME if (isRunning() && ! wait(200)) { quit(); if (isRunning() && ! wait(300)) terminate(); } } void CarlaCheckThread::run() { qDebug("CarlaCheckThread::run()"); bool oscControllerRegisted, usesSingleThread; unsigned short id; double value; m_stopNow = false; while (engine->isRunning() && ! m_stopNow) { const ScopedLocker m(this); oscControllerRegisted = engine->isOscControllerRegisted(); for (unsigned short i=0; i < CarlaBackend::MAX_PLUGINS; i++) { CarlaBackend::CarlaPlugin* const plugin = engine->getPluginUnchecked(i); if (plugin && plugin->enabled()) { id = plugin->id(); usesSingleThread = (plugin->hints() & CarlaBackend::PLUGIN_USES_SINGLE_THREAD); // ------------------------------------------------------- // Process postponed events if (! usesSingleThread) plugin->postEventsRun(); // ------------------------------------------------------- // Update parameter outputs if (oscControllerRegisted || ! usesSingleThread) { for (uint32_t i=0; i < plugin->parameterCount(); i++) { if (plugin->parameterIsOutput(i)) { value = plugin->getParameterValue(i); // Update UI if (! usesSingleThread) plugin->uiParameterChange(i, value); // Update OSC control client if (oscControllerRegisted) engine->osc_send_set_parameter_value(id, i, value); } } } // ------------------------------------------------------- // Update OSC control client if (oscControllerRegisted) { // Peak values if (plugin->audioInCount() > 0) { engine->osc_send_set_input_peak_value(id, 1, engine->getInputPeak(id, 0)); engine->osc_send_set_input_peak_value(id, 2, engine->getInputPeak(id, 1)); } if (plugin->audioOutCount() > 0) { engine->osc_send_set_output_peak_value(id, 1, engine->getOutputPeak(id, 0)); engine->osc_send_set_output_peak_value(id, 2, engine->getOutputPeak(id, 1)); } } } } msleep(50); } } // ----------------------------------------------------------------------- // CarlaPluginThread const char* PluginThreadMode2str(const CarlaPluginThread::PluginThreadMode mode) { switch (mode) { case CarlaPluginThread::PLUGIN_THREAD_DSSI_GUI: return "PLUGIN_THREAD_DSSI_GUI"; case CarlaPluginThread::PLUGIN_THREAD_LV2_GUI: return "PLUGIN_THREAD_LV2_GUI"; case CarlaPluginThread::PLUGIN_THREAD_VST_GUI: return "PLUGIN_THREAD_VST_GUI"; case CarlaPluginThread::PLUGIN_THREAD_BRIDGE: return "PLUGIN_THREAD_BRIDGE"; } qWarning("CarlaPluginThread::PluginThreadMode2str(%i) - invalid mode", mode); return nullptr; } CarlaPluginThread::CarlaPluginThread(CarlaBackend::CarlaEngine* const engine_, CarlaBackend::CarlaPlugin* const plugin_, const PluginThreadMode mode_, QObject* const parent) : QThread(parent), engine(engine_), plugin(plugin_), mode(mode_) { qDebug("CarlaPluginThread::CarlaPluginThread(plugin:\"%s\", engine:\"%s\", %s)", plugin->name(), engine->getName(), PluginThreadMode2str(mode)); m_process = nullptr; } CarlaPluginThread::~CarlaPluginThread() { if (m_process) delete m_process; } void CarlaPluginThread::setOscData(const char* const binary, const char* const label, const char* const data1) { m_binary = QString(binary); m_label = QString(label); m_data1 = QString(data1); } void CarlaPluginThread::run() { qDebug("CarlaPluginThread::run()"); if (! m_process) m_process = new QProcess(nullptr); m_process->setProcessChannelMode(QProcess::ForwardedChannels); QStringList arguments; switch (mode) { case PLUGIN_THREAD_DSSI_GUI: /* osc_url */ arguments << QString("%1/%2").arg(engine->getOscServerPath(), plugin->id()); /* filename */ arguments << plugin->filename(); /* label */ arguments << m_label; /* ui-title */ arguments << QString("%1 (GUI)").arg(plugin->name()); break; case PLUGIN_THREAD_LV2_GUI: /* osc_url */ arguments << QString("%1/%2").arg(engine->getOscServerPath(), plugin->id()); /* URI */ arguments << m_label; /* ui-URI */ arguments << m_data1; /* ui-title */ arguments << QString("%1 (GUI)").arg(plugin->name()); break; case PLUGIN_THREAD_VST_GUI: /* osc_url */ arguments << QString("%1/%2").arg(engine->getOscServerPath(), plugin->id()); /* filename */ arguments << plugin->filename(); /* label */ arguments << m_label; /* ui-title */ arguments << QString("%1 (GUI)").arg(plugin->name()); break; case PLUGIN_THREAD_BRIDGE: { const char* name = plugin->name(); if (! name) name = "(none)"; /* osc_url */ arguments << QString("%1/%2").arg(engine->getOscServerPath(), plugin->id()); /* stype */ arguments << m_data1; /* filename */ arguments << plugin->filename(); /* name */ arguments << name; /* label */ arguments << m_label; break; } } qDebug() << m_binary; qDebug() << arguments; m_process->start(m_binary, arguments); m_process->waitForStarted(); switch (mode) { case PLUGIN_THREAD_DSSI_GUI: case PLUGIN_THREAD_LV2_GUI: case PLUGIN_THREAD_VST_GUI: if (plugin->showOscGui()) { m_process->waitForFinished(-1); if (m_process->exitCode() == 0) { // Hide engine->callback(CarlaBackend::CALLBACK_SHOW_GUI, plugin->id(), 0, 0, 0.0); qWarning("CarlaPluginThread::run() - GUI closed"); } else { // Kill engine->callback(CarlaBackend::CALLBACK_SHOW_GUI, plugin->id(), -1, 0, 0.0); qWarning("CarlaPluginThread::run() - GUI crashed"); break; } } else { qDebug("CarlaPluginThread::run() - GUI timeout"); engine->callback(CarlaBackend::CALLBACK_SHOW_GUI, plugin->id(), 0, 0, 0.0); } break; case PLUGIN_THREAD_BRIDGE: m_process->waitForFinished(-1); #ifdef DEBUG if (m_process->exitCode() == 0) qDebug("CarlaPluginThread::run() - bridge closed"); else qDebug("CarlaPluginThread::run() - bridge crashed"); qDebug("%s", QString(m_process->readAllStandardOutput()).toUtf8().constData()); #endif break; } }