Browse Source

Initial code for Carla-Plugin UI; Fixes for Carla-Control

tags/1.9.4
falkTX 11 years ago
parent
commit
8229f8cb57
5 changed files with 226 additions and 37 deletions
  1. +175
    -13
      source/backend/engine/CarlaEngineNative.cpp
  2. +5
    -0
      source/backend/plugin/CarlaPluginThread.cpp
  3. +5
    -2
      source/carla.py
  4. +35
    -22
      source/carla_control.py
  5. +6
    -0
      source/carla_shared.py

+ 175
- 13
source/backend/engine/CarlaEngineNative.cpp View File

@@ -22,19 +22,134 @@

#include "CarlaNative.hpp"

#include <QtCore/QProcess>
#include <QtCore/QTextStream>

CARLA_BACKEND_START_NAMESPACE

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

class CarlaEngineNativeThread : public QThread
{
public:
enum UiState {
UiNone = 0,
UiHide,
UiShow,
UiCrashed
};

CarlaEngineNativeThread(CarlaEngine* const engine)
: kEngine(engine),
fBinary("carla-control"),
fProcess(nullptr),
fUiState(UiNone)
{
carla_debug("CarlaEngineNativeThread::CarlaEngineNativeThread(engine:\"%s\")", engine->getName());
}

~CarlaEngineNativeThread()
{
CARLA_ASSERT_INT(fUiState == UiNone, fUiState);
carla_debug("CarlaEngineNativeThread::~CarlaEngineNativeThread()");

if (fProcess != nullptr)
{
delete fProcess;
fProcess = nullptr;
}
}

void setOscData(const char* const binary)
{
fBinary = binary;
}

UiState getUiState()
{
const UiState state(fUiState);
fUiState = UiNone;

return state;
}

void stop()
{
if (fProcess == nullptr)
return;

fUiState = UiNone;
fProcess->kill();
//fProcess->close();
}

protected:
void run()
{
carla_debug("CarlaEngineNativeThread::run() - binary:\"%s\"", (const char*)fBinary);

if (fProcess == nullptr)
{
fProcess = new QProcess(nullptr);
fProcess->setProcessChannelMode(QProcess::ForwardedChannels);
}
else if (fProcess->state() == QProcess::Running)
{
carla_stderr("CarlaEngineNativeThread::run() - already running, giving up...");

fUiState = UiCrashed;
fProcess->terminate();
//kEngine->callback(CarlaBackend::CALLBACK_SHOW_GUI, kPlugin->id(), -1, 0, 0.0f, nullptr);
// TODO: tell master to hide UI
return;
}

QStringList arguments;
arguments << kEngine->getOscServerPathTCP();

fProcess->start((const char*)fBinary, arguments);
fProcess->waitForStarted();

fUiState = UiShow;

fProcess->waitForFinished(-1);

if (fProcess->exitCode() == 0)
{
// Hide
fUiState = UiHide;
carla_stdout("CarlaEngineNativeThread::run() - GUI closed");
}
else
{
// Kill
fUiState = UiCrashed;
carla_stderr("CarlaEngineNativeThread::run() - GUI crashed while running");
}
}

private:
CarlaEngine* const kEngine;

CarlaString fBinary;
QProcess* fProcess;

UiState fUiState;

CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineNativeThread)
};

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

class CarlaEngineNative : public PluginDescriptorClass,
public CarlaEngine
{
public:
CarlaEngineNative(const HostDescriptor* const host)
: PluginDescriptorClass(host),
CarlaEngine()
CarlaEngine(),
fIsRunning(true),
fThread(this)
{
carla_debug("CarlaEngineNative::CarlaEngineNative()");

@@ -45,12 +160,29 @@ public:
fOptions.preferPluginBridges = false;
fOptions.preferUiBridges = false;
init("Carla-Plugin");

// set control thread binary
CarlaString threadBinary(hostResourceDir());
threadBinary += "/../";
threadBinary += "carla_control.py";

fThread.setOscData(threadBinary);

// TESTING
// if (! addPlugin(PLUGIN_INTERNAL, nullptr, "MIDI Transpose", "midiTranspose"))
// carla_stdout("TESTING PLUG1 ERROR:\n%s", getLastError());
// if (! addPlugin(PLUGIN_INTERNAL, nullptr, "ZynAddSubFX", "zynaddsubfx"))
// carla_stdout("TESTING PLUG2 ERROR:\n%s", getLastError());
// if (! addPlugin(PLUGIN_INTERNAL, nullptr, "Ping Pong Pan", "PingPongPan"))
// carla_stdout("TESTING PLUG3 ERROR:\n%s", getLastError());
}

~CarlaEngineNative() override
{
carla_debug("CarlaEngineNative::~CarlaEngineNative()");

fIsRunning = false;

setAboutToClose();
removeAllPlugins();
close();
@@ -81,7 +213,7 @@ protected:

bool isRunning() const override
{
return true;
return fIsRunning;
}

bool isOffline() const override
@@ -319,7 +451,7 @@ protected:
{
carla_zeroFloat(outBuffer[0], frames);
carla_zeroFloat(outBuffer[1], frames);
return CarlaEngine::proccessPendingEvents();
return proccessPendingEvents();
}

// ---------------------------------------------------------------
@@ -412,14 +544,14 @@ protected:
// ---------------------------------------------------------------
// create audio buffers

float* inBuf[2] = { inBuffer[0], inBuffer[1] };
float* inBuf[2] = { inBuffer[0], inBuffer[1] };
float* outBuf[2] = { outBuffer[0], outBuffer[1] };

// ---------------------------------------------------------------
// process

CarlaEngine::processRack(inBuf, outBuf, frames);
CarlaEngine::proccessPendingEvents();
processRack(inBuf, outBuf, frames);
proccessPendingEvents();
}

// -------------------------------------------------------------------
@@ -427,17 +559,44 @@ protected:

void uiShow(const bool show) override
{
return;
if (show)
{
fThread.start();
}
else
{
#if 0
for (uint32_t i=0; i < kData->curPluginCount; ++i)
{
CarlaPlugin* const plugin(kData->plugins[i].plugin);

// TODO
if (plugin == nullptr || ! plugin->enabled())
continue;

// unused
(void)show;
plugin->showGui(false);
}
#endif

fThread.stop();
}
}

void uiIdle() override
{
CarlaEngine::idle();

switch(fThread.getUiState())
{
case CarlaEngineNativeThread::UiNone:
case CarlaEngineNativeThread::UiShow:
break;
case CarlaEngineNativeThread::UiCrashed:
hostDispatcher(HOST_OPCODE_UI_UNAVAILABLE, 0, 0, nullptr);
break;
case CarlaEngineNativeThread::UiHide:
uiClosed();
break;
}
}

void uiSetParameterValue(const uint32_t index, const float value) override
@@ -495,7 +654,7 @@ protected:

for (unsigned int i=0; i < kData->curPluginCount; ++i)
{
CarlaPlugin* const plugin = kData->plugins[i].plugin;
CarlaPlugin* const plugin(kData->plugins[i].plugin);

if (plugin != nullptr && plugin->enabled())
{
@@ -566,6 +725,9 @@ protected:
// -------------------------------------------------------------------

private:
bool fIsRunning;
CarlaEngineNativeThread fThread;

PluginDescriptorClassEND(CarlaEngineNative)
CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineNative)
};
@@ -574,14 +736,14 @@ private:

static const PluginDescriptor carlaDesc = {
/* category */ ::PLUGIN_CATEGORY_OTHER,
/* hints */ static_cast< ::PluginHints>(::PLUGIN_IS_SYNTH|::PLUGIN_USES_SINGLE_THREAD|::PLUGIN_USES_STATE),
/* hints */ static_cast< ::PluginHints>(::PLUGIN_IS_SYNTH|::PLUGIN_HAS_GUI|::PLUGIN_USES_SINGLE_THREAD|::PLUGIN_USES_STATE),
/* audioIns */ 2,
/* audioOuts */ 2,
/* midiIns */ 1,
/* midiOuts */ 1,
/* paramIns */ 0,
/* paramOuts */ 0,
/* name */ "Carla-Plugin",
/* name */ "Carla-Plugin (TESTING)",
/* label */ "carla",
/* maker */ "falkTX",
/* copyright */ "GNU GPL v2+",


+ 5
- 0
source/backend/plugin/CarlaPluginThread.cpp View File

@@ -55,8 +55,13 @@ CarlaPluginThread::CarlaPluginThread(CarlaBackend::CarlaEngine* const engine, Ca

CarlaPluginThread::~CarlaPluginThread()
{
carla_debug("CarlaPluginThread::~CarlaPluginThread()");

if (fProcess != nullptr)
{
delete fProcess;
fProcess = nullptr;
}
}

void CarlaPluginThread::setMode(const CarlaPluginThread::Mode mode)


+ 5
- 2
source/carla.py View File

@@ -2297,9 +2297,12 @@ if __name__ == '__main__':
app.setOrganizationName("falkTX")
app.setWindowIcon(QIcon(":/scalable/carla.svg"))

for i in range(len(app.arguments())):
argv = app.arguments()
argc = len(argv)

for i in range(argc):
if i == 0: continue
argument = app.arguments()[i]
argument = argv[i]

if argument.startswith("--with-appname="):
appName = os.path.basename(argument.replace("--with-appname=", ""))


+ 35
- 22
source/carla_control.py View File

@@ -601,8 +601,8 @@ class ControlServer(ServerThread):
# Main Window

class CarlaControlW(QMainWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent)
def __init__(self, oscAddr=None):
QMainWindow.__init__(self, None)
self.ui = ui_carla_control.Ui_CarlaControlW()
self.ui.setupUi(self)

@@ -680,6 +680,33 @@ class CarlaControlW(QMainWindow):
self.connect(self, SIGNAL("SetPeaks(int, double, double, double, double)"), SLOT("slot_handleSetPeaks(int, double, double, double, double)"))
self.connect(self, SIGNAL("Exit()"), SLOT("slot_handleExit()"))

if oscAddr:
self.connectToAddr(oscAddr)

def connectToAddr(self, addr):
global lo_target, lo_targetName

self.lo_address = oscAddr
lo_target = Address(self.lo_address)
lo_targetName = self.lo_address.rsplit("/", 1)[-1]
print("Connecting to \"%s\" as '%s'..." % (self.lo_address, lo_targetName))

try:
self.lo_server = ControlServer(self, LO_UDP if self.lo_address.startswith("osc.udp") else LO_TCP)
except: # ServerError, err:
print("Connecting error!")
#print str(err)
QMessageBox.critical(self, self.tr("Error"), self.tr("Failed to connect, operation failed."))
return

if self.lo_server:
self.lo_server.start()
self.ui.act_file_refresh.setEnabled(True)
lo_send(lo_target, "/register", self.lo_server.getFullURL())

self.fIdleTimerFast = self.startTimer(60)
self.fIdleTimerSlow = self.startTimer(60*2)

def removeAll(self):
self.killTimer(self.fIdleTimerFast)
self.killTimer(self.fIdleTimerSlow)
@@ -725,22 +752,7 @@ class CarlaControlW(QMainWindow):

self.slot_handleExit()

self.lo_address = askValue[0]
lo_target = Address(self.lo_address)
lo_targetName = self.lo_address.rsplit("/", 1)[-1]
print("Connecting to \"%s\" as '%s'..." % (self.lo_address, lo_targetName))

try:
self.lo_server = ControlServer(self, LO_UDP if self.lo_address.startswith("osc.udp") else LO_TCP)
except: # ServerError, err:
print("Connecting error!")
#print str(err)
QMessageBox.critical(self, self.tr("Error"), self.tr("Failed to connect, operation failed."))

if self.lo_server:
self.lo_server.start()
self.ui.act_file_refresh.setEnabled(True)
lo_send(lo_target, "/register", self.lo_server.getFullURL())
self.connectToAddr(askValue[0])

@pyqtSlot()
def slot_fileRefresh(self):
@@ -1057,13 +1069,11 @@ if __name__ == '__main__':
app.setWindowIcon(QIcon(":/scalable/carla-control.svg"))

libPrefix = None
oscAddr = None

argv = app.arguments()
argc = len(argv)

#print(argc)
#print(argv)

for i in range(argc):
if i == 0: continue
argument = argv[i]
@@ -1071,6 +1081,9 @@ if __name__ == '__main__':
if argument.startswith("--with-libprefix="):
libPrefix = argument.replace("--with-libprefix=", "")

elif argument.startswith("osc."):
oscAddr = argument

if libPrefix is not None:
libName = os.path.join(libPrefix, "lib", "carla", carla_libname)
else:
@@ -1089,7 +1102,7 @@ if __name__ == '__main__':
Carla.host = Host()

# Create GUI
Carla.gui = CarlaControlW()
Carla.gui = CarlaControlW(oscAddr)

# Set-up custom signal handling
setUpSignals()


+ 6
- 0
source/carla_shared.py View File

@@ -1182,6 +1182,9 @@ class PluginEdit(QDialog):
self.fPluginInfo['maker'] = cString(self.fPluginInfo['maker'])
self.fPluginInfo['copyright'] = cString(self.fPluginInfo['copyright'])

if not Carla.isLocal:
self.fPluginInfo['hints'] &= ~PLUGIN_HAS_GUI

self.reloadInfo()
self.reloadParameters()
self.reloadPrograms()
@@ -1982,6 +1985,9 @@ class PluginWidget(QFrame):
self.fPluginInfo['maker'] = cString(self.fPluginInfo['maker'])
self.fPluginInfo['copyright'] = cString(self.fPluginInfo['copyright'])

if not Carla.isLocal:
self.fPluginInfo['hints'] &= ~PLUGIN_HAS_GUI

self.fLastGreenLedState = False
self.fLastBlueLedState = False



Loading…
Cancel
Save