Browse Source

More remote OSC stuff, split UDP and TCP

Signed-off-by: falkTX <falktx@falktx.com>
tags/v2.1-alpha2
falkTX 6 years ago
parent
commit
60cb053d04
Signed by: falkTX <falktx@falktx.com> GPG Key ID: CDBAA37ABC74FBA0
11 changed files with 517 additions and 244 deletions
  1. +2
    -2
      source/backend/engine/CarlaEngine.cpp
  2. +4
    -1
      source/backend/engine/CarlaEngineNative.cpp
  3. +3
    -0
      source/backend/engine/CarlaEngineOsc.cpp
  4. +12
    -3
      source/backend/engine/CarlaEngineOsc.hpp
  5. +155
    -18
      source/backend/engine/CarlaEngineOscHandlers.cpp
  6. +45
    -21
      source/backend/engine/CarlaEngineOscSend.cpp
  7. +27
    -8
      source/backend/engine/CarlaEngineThread.cpp
  8. +14
    -4
      source/frontend/carla_backend.py
  9. +241
    -183
      source/frontend/carla_control.py
  10. +10
    -4
      source/frontend/carla_host.py
  11. +4
    -0
      source/includes/CarlaDefines.h

+ 2
- 2
source/backend/engine/CarlaEngine.cpp View File

@@ -1332,7 +1332,7 @@ void CarlaEngine::callback(const bool sendHost, const bool sendOsc,
if (sendOsc) if (sendOsc)
{ {
#if defined(HAVE_LIBLO) && ! defined(BUILD_BRIDGE) #if defined(HAVE_LIBLO) && ! defined(BUILD_BRIDGE)
if (pData->osc.isControlRegistered())
if (pData->osc.isControlRegisteredForTCP())
{ {
switch (action) switch (action)
{ {
@@ -1823,7 +1823,7 @@ void CarlaEngine::setOption(const EngineOption option, const int value, const ch
bool CarlaEngine::isOscControlRegistered() const noexcept bool CarlaEngine::isOscControlRegistered() const noexcept
{ {
# ifdef HAVE_LIBLO # ifdef HAVE_LIBLO
return pData->osc.isControlRegistered();
return pData->osc.isControlRegisteredForTCP();
# else # else
return false; return false;
# endif # endif


+ 4
- 1
source/backend/engine/CarlaEngineNative.cpp View File

@@ -238,8 +238,11 @@ protected:
} }
else if (std::strcmp(msg, "patchbay_refresh") == 0) else if (std::strcmp(msg, "patchbay_refresh") == 0)
{ {
bool external;
CARLA_SAFE_ASSERT_RETURN(readNextLineAsBool(external), true);

try { try {
ok = fEngine->patchbayRefresh(false);
ok = fEngine->patchbayRefresh(external);
} CARLA_SAFE_EXCEPTION("patchbayRefresh"); } CARLA_SAFE_EXCEPTION("patchbayRefresh");
} }
else if (std::strcmp(msg, "transport_play") == 0) else if (std::strcmp(msg, "transport_play") == 0)


+ 3
- 0
source/backend/engine/CarlaEngineOsc.cpp View File

@@ -183,6 +183,9 @@ void CarlaEngineOsc::close() noexcept
CARLA_SAFE_ASSERT(fServerUDP != nullptr); CARLA_SAFE_ASSERT(fServerUDP != nullptr);
carla_debug("CarlaEngineOsc::close()"); carla_debug("CarlaEngineOsc::close()");


if (fControlDataTCP.target != nullptr)
sendExit();

fName.clear(); fName.clear();


if (fServerTCP != nullptr) if (fServerTCP != nullptr)


+ 12
- 3
source/backend/engine/CarlaEngineOsc.hpp View File

@@ -79,9 +79,14 @@ public:


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


bool isControlRegistered() const noexcept
bool isControlRegisteredForTCP() const noexcept
{ {
return (fControlDataTCP.target != nullptr);
return fControlDataTCP.target != nullptr;
}

bool isControlRegisteredForUDP() const noexcept
{
return fControlDataUDP.target != nullptr;
} }


// ------------------------------------------------------------------- // -------------------------------------------------------------------
@@ -95,11 +100,13 @@ public:
void sendPluginPortCount(const CarlaPlugin* const plugin) const noexcept; void sendPluginPortCount(const CarlaPlugin* const plugin) const noexcept;
void sendPluginParameterInfo(const CarlaPlugin* const plugin, const uint32_t parameterId) const noexcept; void sendPluginParameterInfo(const CarlaPlugin* const plugin, const uint32_t parameterId) const noexcept;
void sendPluginInternalParameterValues(const CarlaPlugin* const plugin) const noexcept; void sendPluginInternalParameterValues(const CarlaPlugin* const plugin) const noexcept;
void sendRuntimeInfo() const noexcept;
void sendPing() const noexcept;
void sendExit() const noexcept;


// ------------------------------------------------------------------- // -------------------------------------------------------------------
// UDP // UDP


void sendRuntimeInfo() const noexcept;
void sendParameterValue(const uint pluginId, const uint32_t index, const float value) const noexcept; void sendParameterValue(const uint pluginId, const uint32_t index, const float value) const noexcept;
void sendPeaks(const uint pluginId, const float peaks[4]) const noexcept; void sendPeaks(const uint pluginId, const float peaks[4]) const noexcept;


@@ -125,6 +132,8 @@ private:


int handleMsgRegister(const bool isTCP, const int argc, const lo_arg* const* const argv, const char* const types); int handleMsgRegister(const bool isTCP, const int argc, const lo_arg* const* const argv, const char* const types);
int handleMsgUnregister(const bool isTCP, const int argc, const lo_arg* const* const argv, const char* const types); int handleMsgUnregister(const bool isTCP, const int argc, const lo_arg* const* const argv, const char* const types);
int handleMsgControl(const char* const method,
const int argc, const lo_arg* const* const argv, const char* const types);


// Internal methods // Internal methods
int handleMsgSetActive(CARLA_ENGINE_OSC_HANDLE_ARGS); int handleMsgSetActive(CARLA_ENGINE_OSC_HANDLE_ARGS);


+ 155
- 18
source/backend/engine/CarlaEngineOscHandlers.cpp View File

@@ -57,12 +57,19 @@ int CarlaEngineOsc::handleMessage(const bool isTCP, const char* const path, cons
if (std::strcmp(path, "/unregister") == 0) if (std::strcmp(path, "/unregister") == 0)
return handleMsgUnregister(isTCP, argc, argv, types); return handleMsgUnregister(isTCP, argc, argv, types);


if (std::strncmp(path, "/ctrl/", 6) == 0)
{
CARLA_SAFE_ASSERT_RETURN(isTCP, 1);
return handleMsgControl(path + 6, argc, argv, types);
}

const std::size_t nameSize(fName.length()); const std::size_t nameSize(fName.length());


// Check if message is for this client // Check if message is for this client
if (std::strlen(path) <= nameSize || std::strncmp(path+1, fName, nameSize) != 0) if (std::strlen(path) <= nameSize || std::strncmp(path+1, fName, nameSize) != 0)
{ {
carla_stderr("CarlaEngineOsc::handleMessage() - message not for this client -> '%s' != '/%s/'", path, fName.buffer());
carla_stderr("CarlaEngineOsc::handleMessage() - message not for this client -> '%s' != '/%s/'",
path, fName.buffer());
return 1; return 1;
} }


@@ -213,29 +220,28 @@ int CarlaEngineOsc::handleMsgRegister(const bool isTCP,


oscData.owner = carla_strdup_safe(url); oscData.owner = carla_strdup_safe(url);
oscData.path = carla_strdup_free(lo_url_get_path(url)); oscData.path = carla_strdup_free(lo_url_get_path(url));
oscData.source = lo_address_new_with_proto(isTCP ? LO_TCP : LO_UDP, host, port);
oscData.target = target; oscData.target = target;


for (uint i=0, count=fEngine->getCurrentPluginCount(); i < count; ++i)
if (isTCP)
{ {
CarlaPlugin* const plugin(fEngine->getPluginUnchecked(i));
CARLA_SAFE_ASSERT_CONTINUE(plugin != nullptr);

fEngine->callback(false, true, ENGINE_CALLBACK_PLUGIN_ADDED, i, 0, 0, 0, 0.0f, plugin->getName());
}
const EngineOptions& opts(fEngine->getOptions());


const EngineOptions& opts(fEngine->getOptions());
fEngine->callback(false, true,
ENGINE_CALLBACK_ENGINE_STARTED, 0,
opts.processMode,
opts.transportMode,
static_cast<int>(fEngine->getBufferSize()),
static_cast<float>(fEngine->getSampleRate()),
fEngine->getCurrentDriverName());


fEngine->callback(false, true,
ENGINE_CALLBACK_ENGINE_STARTED, 0,
opts.processMode,
opts.transportMode,
static_cast<int>(fEngine->getBufferSize()),
static_cast<float>(fEngine->getSampleRate()),
fEngine->getCurrentDriverName());
for (uint i=0, count=fEngine->getCurrentPluginCount(); i < count; ++i)
{
CarlaPlugin* const plugin(fEngine->getPluginUnchecked(i));
CARLA_SAFE_ASSERT_CONTINUE(plugin != nullptr);


// TODO
// fEngine->patchbayRefresh();
fEngine->callback(false, true, ENGINE_CALLBACK_PLUGIN_ADDED, i, 0, 0, 0, 0.0f, plugin->getName());
}
}
} }


lo_address_free(addr); lo_address_free(addr);
@@ -269,6 +275,137 @@ int CarlaEngineOsc::handleMsgUnregister(const bool isTCP,
return 0; return 0;
} }


int CarlaEngineOsc::handleMsgControl(const char* const method,
const int argc, const lo_arg* const* const argv, const char* const types)
{
carla_debug("CarlaEngineOsc::handleMsgControl()");
CARLA_SAFE_ASSERT_RETURN(method != nullptr && method[0] != '\0', 0);
CARLA_SAFE_ASSERT_RETURN(types != nullptr, 0);

if (fControlDataTCP.owner == nullptr)
{
carla_stderr("OSC backend is not registered yet, control failed");
return 0;
}

carla_stdout("OSC control for '%s'", method);

// "patchbay_refresh",
// "transport_play",
// "transport_pause",
// "transport_relocate",
// "transport_bpm",


/**/ if (std::strcmp(method, "clear_engine_xruns") == 0)
{
fEngine->clearXruns();
}
else if (std::strcmp(method, "cancel_engine_action") == 0)
{
fEngine->setActionCanceled(true);
}
// "patchbay_connect",
// "patchbay_disconnect",
else if (std::strcmp(method, "patchbay_connect") == 0)
{
CARLA_SAFE_ASSERT_INT_RETURN(argc == 4, argc, 0);
CARLA_SAFE_ASSERT_RETURN(types[0] == 'i', 0);
CARLA_SAFE_ASSERT_RETURN(types[1] == 'i', 0);
CARLA_SAFE_ASSERT_RETURN(types[2] == 'i', 0);
CARLA_SAFE_ASSERT_RETURN(types[3] == 'i', 0);

const int32_t i0 = argv[0]->i;
CARLA_SAFE_ASSERT_RETURN(i0 >= 0, 0);

const int32_t i1 = argv[1]->i;
CARLA_SAFE_ASSERT_RETURN(i1 >= 0, 0);

const int32_t i2 = argv[2]->i;
CARLA_SAFE_ASSERT_RETURN(i2 >= 0, 0);

const int32_t i3 = argv[3]->i;
CARLA_SAFE_ASSERT_RETURN(i3 >= 0, 0);

fEngine->patchbayConnect(static_cast<uint32_t>(i0),
static_cast<uint32_t>(i1),
static_cast<uint32_t>(i2),
static_cast<uint32_t>(i3));
}
else if (std::strcmp(method, "patchbay_disconnect") == 0)
{
CARLA_SAFE_ASSERT_INT_RETURN(argc == 1, argc, 0);
CARLA_SAFE_ASSERT_RETURN(types[0] == 'i', 0);

const int32_t i = argv[0]->i;
CARLA_SAFE_ASSERT_RETURN(i >= 0, 0);

fEngine->patchbayDisconnect(static_cast<uint32_t>(i));
}
else if (std::strcmp(method, "patchbay_refresh") == 0)
{
CARLA_SAFE_ASSERT_INT_RETURN(argc == 1, argc, 0);
CARLA_SAFE_ASSERT_RETURN(types[0] == 'i', 0);

const int32_t i = argv[0]->i;
fEngine->patchbayRefresh(i != 0);
}
else if (std::strcmp(method, "transport_play") == 0)
{
CARLA_SAFE_ASSERT_INT_RETURN(argc == 0, argc, 0);
fEngine->transportPlay();
}
else if (std::strcmp(method, "transport_pause") == 0)
{
CARLA_SAFE_ASSERT_INT_RETURN(argc == 0, argc, 0);
fEngine->transportPause();
}
else if (std::strcmp(method, "transport_bpm") == 0)
{
CARLA_SAFE_ASSERT_INT_RETURN(argc == 1, argc, 0);
CARLA_SAFE_ASSERT_RETURN(types[0] == 'f', 0);

const double f = argv[0]->f;
CARLA_SAFE_ASSERT_RETURN(f >= 0.0, 0);

fEngine->transportBPM(f);
}
else if (std::strcmp(method, "transport_relocate") == 0)
{
CARLA_SAFE_ASSERT_INT_RETURN(argc == 1, argc, 0);
uint64_t frame;

/**/ if (types[0] == 'i')
{
const int32_t i = argv[0]->i;
CARLA_SAFE_ASSERT_RETURN(i >= 0, 0);
frame = static_cast<uint64_t>(i);
}
else if (types[0] == 'h')
{
const int64_t h = argv[0]->h;
CARLA_SAFE_ASSERT_RETURN(h >= 0, 0);
frame = static_cast<uint64_t>(h);
}
else
{
carla_stderr2("Wrong OSC type used for '%s'", method);
return 0;
}

fEngine->transportRelocate(frame);
}

// #"add_plugin",
// "remove_plugin",
// "remove_all_plugins",
// "rename_plugin",
// "clone_plugin",
// "replace_plugin",
// "switch_plugins",
return 0;
}

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


int CarlaEngineOsc::handleMsgSetActive(CARLA_ENGINE_OSC_HANDLE_ARGS) int CarlaEngineOsc::handleMsgSetActive(CARLA_ENGINE_OSC_HANDLE_ARGS)


+ 45
- 21
source/backend/engine/CarlaEngineOscSend.cpp View File

@@ -33,8 +33,9 @@ void CarlaEngineOsc::sendCallback(const EngineCallbackOpcode action, const uint
{ {
CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.path != nullptr && fControlDataTCP.path[0] != '\0',); CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.path != nullptr && fControlDataTCP.path[0] != '\0',);
CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.target != nullptr,); CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.target != nullptr,);
carla_debug("CarlaEngineOsc::sendCallback(%i:%s, %i, %i, %i, %i, %f, \"%s\")",
action, EngineCallbackOpcode2Str(action), pluginId, value1, value2, value3, valuef, valueStr);
carla_stdout("CarlaEngineOsc::sendCallback(%i:%s, %i, %i, %i, %i, %f, \"%s\")",
action, EngineCallbackOpcode2Str(action), pluginId, value1, value2, value3,
static_cast<double>(valuef), valueStr);


static const char* const kFakeNullString = "(null)"; static const char* const kFakeNullString = "(null)";


@@ -51,7 +52,7 @@ void CarlaEngineOsc::sendPluginInit(const uint pluginId, const char* const plugi
CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.path != nullptr && fControlDataTCP.path[0] != '\0',); CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.path != nullptr && fControlDataTCP.path[0] != '\0',);
CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.target != nullptr,); CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.target != nullptr,);
CARLA_SAFE_ASSERT_RETURN(pluginName != nullptr && pluginName[0] != '\0',); CARLA_SAFE_ASSERT_RETURN(pluginName != nullptr && pluginName[0] != '\0',);
carla_debug("CarlaEngineOsc::sendadd_plugin_start(%i, \"%s\")", pluginId, pluginName);
carla_stdout("CarlaEngineOsc::sendPluginInit(%i, \"%s\")", pluginId, pluginName);


char targetPath[std::strlen(fControlDataTCP.path)+18]; char targetPath[std::strlen(fControlDataTCP.path)+18];
std::strcpy(targetPath, fControlDataTCP.path); std::strcpy(targetPath, fControlDataTCP.path);
@@ -64,7 +65,7 @@ void CarlaEngineOsc::sendPluginInfo(const CarlaPlugin* const plugin) const noexc
CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.path != nullptr && fControlDataTCP.path[0] != '\0',); CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.path != nullptr && fControlDataTCP.path[0] != '\0',);
CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.target != nullptr,); CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.target != nullptr,);
CARLA_SAFE_ASSERT_RETURN(plugin != nullptr,); CARLA_SAFE_ASSERT_RETURN(plugin != nullptr,);
carla_debug("CarlaEngineOsc::sendPluginInfo(%p)", plugin);
carla_stdout("CarlaEngineOsc::sendPluginInfo(%p)", plugin);


char bufName[STR_MAX+1], bufLabel[STR_MAX+1], bufMaker[STR_MAX+1], bufCopyright[STR_MAX+1]; char bufName[STR_MAX+1], bufLabel[STR_MAX+1], bufMaker[STR_MAX+1], bufCopyright[STR_MAX+1];
carla_zeroChars(bufName, STR_MAX+1); carla_zeroChars(bufName, STR_MAX+1);
@@ -94,7 +95,7 @@ void CarlaEngineOsc::sendPluginPortCount(const CarlaPlugin* const plugin) const
CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.path != nullptr && fControlDataTCP.path[0] != '\0',); CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.path != nullptr && fControlDataTCP.path[0] != '\0',);
CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.target != nullptr,); CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.target != nullptr,);
CARLA_SAFE_ASSERT_RETURN(plugin != nullptr,); CARLA_SAFE_ASSERT_RETURN(plugin != nullptr,);
carla_debug("CarlaEngineOsc::sendPluginInfo(%p)", plugin);
carla_stdout("CarlaEngineOsc::sendPluginInfo(%p)", plugin);


uint32_t paramIns, paramOuts; uint32_t paramIns, paramOuts;
plugin->getParameterCountInfo(paramIns, paramOuts); plugin->getParameterCountInfo(paramIns, paramOuts);
@@ -235,20 +236,43 @@ void CarlaEngineOsc::sendset_midi_program_data(const uint pluginId, const uint32


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


// FIXME use UDP
void CarlaEngineOsc::sendPing() const noexcept
{
CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.path != nullptr && fControlDataTCP.path[0] != '\0',);
CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.target != nullptr,);


void CarlaEngineOsc::sendRuntimeInfo() const noexcept
char targetPath[std::strlen(fControlDataTCP.path)+6];
std::strcpy(targetPath, fControlDataTCP.path);
std::strcat(targetPath, "/ping");
try_lo_send(fControlDataTCP.target, targetPath, "");
}

void CarlaEngineOsc::sendExit() const noexcept
{ {
CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.path != nullptr && fControlDataTCP.path[0] != '\0',); CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.path != nullptr && fControlDataTCP.path[0] != '\0',);
CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.target != nullptr,); CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.target != nullptr,);
carla_debug("CarlaEngineOsc::sendExit()");

char targetPath[std::strlen(fControlDataTCP.path)+6];
std::strcpy(targetPath, fControlDataTCP.path);
std::strcat(targetPath, "/exit");
try_lo_send(fControlDataTCP.target, targetPath, "");
}

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

void CarlaEngineOsc::sendRuntimeInfo() const noexcept
{
CARLA_SAFE_ASSERT_RETURN(fControlDataUDP.path != nullptr && fControlDataUDP.path[0] != '\0',);
CARLA_SAFE_ASSERT_RETURN(fControlDataUDP.target != nullptr,);
carla_debug("CarlaEngineOsc::sendRuntimeInfo()"); carla_debug("CarlaEngineOsc::sendRuntimeInfo()");


const EngineTimeInfo timeInfo(fEngine->getTimeInfo()); const EngineTimeInfo timeInfo(fEngine->getTimeInfo());


char targetPath[std::strlen(fControlDataTCP.path)+18];
std::strcpy(targetPath, fControlDataTCP.path);
char targetPath[std::strlen(fControlDataUDP.path)+18];
std::strcpy(targetPath, fControlDataUDP.path);
std::strcat(targetPath, "/runtime"); std::strcat(targetPath, "/runtime");
try_lo_send(fControlDataTCP.target, targetPath, "fiihiiif",
try_lo_send(fControlDataUDP.target, targetPath, "fiihiiif",
static_cast<double>(fEngine->getDSPLoad()), static_cast<double>(fEngine->getDSPLoad()),
static_cast<int32_t>(fEngine->getTotalXruns()), static_cast<int32_t>(fEngine->getTotalXruns()),
timeInfo.playing ? 1 : 0, timeInfo.playing ? 1 : 0,
@@ -261,13 +285,13 @@ void CarlaEngineOsc::sendRuntimeInfo() const noexcept


void CarlaEngineOsc::sendParameterValue(const uint pluginId, const uint32_t index, const float value) const noexcept void CarlaEngineOsc::sendParameterValue(const uint pluginId, const uint32_t index, const float value) const noexcept
{ {
CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.path != nullptr && fControlDataTCP.path[0] != '\0',);
CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.target != nullptr,);
CARLA_SAFE_ASSERT_RETURN(fControlDataUDP.path != nullptr && fControlDataUDP.path[0] != '\0',);
CARLA_SAFE_ASSERT_RETURN(fControlDataUDP.target != nullptr,);


char targetPath[std::strlen(fControlDataTCP.path)+21];
std::strcpy(targetPath, fControlDataTCP.path);
std::strcat(targetPath, "/param_fixme");
try_lo_send(fControlDataTCP.target, targetPath, "iif",
char targetPath[std::strlen(fControlDataUDP.path)+21];
std::strcpy(targetPath, fControlDataUDP.path);
std::strcat(targetPath, "/param");
try_lo_send(fControlDataUDP.target, targetPath, "iif",
static_cast<int32_t>(pluginId), static_cast<int32_t>(pluginId),
index, index,
static_cast<double>(value)); static_cast<double>(value));
@@ -275,13 +299,13 @@ void CarlaEngineOsc::sendParameterValue(const uint pluginId, const uint32_t inde


void CarlaEngineOsc::sendPeaks(const uint pluginId, const float peaks[4]) const noexcept void CarlaEngineOsc::sendPeaks(const uint pluginId, const float peaks[4]) const noexcept
{ {
CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.path != nullptr && fControlDataTCP.path[0] != '\0',);
CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.target != nullptr,);
CARLA_SAFE_ASSERT_RETURN(fControlDataUDP.path != nullptr && fControlDataUDP.path[0] != '\0',);
CARLA_SAFE_ASSERT_RETURN(fControlDataUDP.target != nullptr,);


char targetPath[std::strlen(fControlDataTCP.path)+11];
std::strcpy(targetPath, fControlDataTCP.path);
char targetPath[std::strlen(fControlDataUDP.path)+11];
std::strcpy(targetPath, fControlDataUDP.path);
std::strcat(targetPath, "/peaks"); std::strcat(targetPath, "/peaks");
try_lo_send(fControlDataTCP.target, targetPath, "iffff", static_cast<int32_t>(pluginId),
try_lo_send(fControlDataUDP.target, targetPath, "iffff", static_cast<int32_t>(pluginId),
static_cast<double>(peaks[0]), static_cast<double>(peaks[0]),
static_cast<double>(peaks[1]), static_cast<double>(peaks[1]),
static_cast<double>(peaks[2]), static_cast<double>(peaks[2]),


+ 27
- 8
source/backend/engine/CarlaEngineThread.cpp View File

@@ -19,6 +19,8 @@
#include "CarlaEngineInternal.hpp" #include "CarlaEngineInternal.hpp"
#include "CarlaPlugin.hpp" #include "CarlaPlugin.hpp"


#include "water/misc/Time.h"

CARLA_BACKEND_START_NAMESPACE CARLA_BACKEND_START_NAMESPACE


// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
@@ -49,7 +51,8 @@ void CarlaEngineThread::run() noexcept
float value; float value;


#if defined(HAVE_LIBLO) && ! defined(BUILD_BRIDGE) #if defined(HAVE_LIBLO) && ! defined(BUILD_BRIDGE)
CarlaEngineOsc& engineOsc(kEngine->pData->osc);
// int64_t lastPingTime = 0;
const CarlaEngineOsc& engineOsc(kEngine->pData->osc);
#endif #endif


// thread must do something... // thread must do something...
@@ -58,16 +61,14 @@ void CarlaEngineThread::run() noexcept
for (; (kIsAlwaysRunning || kEngine->isRunning()) && ! shouldThreadExit();) for (; (kIsAlwaysRunning || kEngine->isRunning()) && ! shouldThreadExit();)
{ {
#if defined(HAVE_LIBLO) && ! defined(BUILD_BRIDGE) #if defined(HAVE_LIBLO) && ! defined(BUILD_BRIDGE)
const bool oscRegisted = kEngine->isOscControlRegistered();
const bool oscRegistedForUDP = engineOsc.isControlRegisteredForUDP();
#else #else
const bool oscRegisted = false;
const bool oscRegistedForUDP = false;
#endif #endif


#if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE) #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
if (kIsPlugin) if (kIsPlugin)
engineOsc.idle(); engineOsc.idle();
if (oscRegisted)
engineOsc.sendRuntimeInfo();
#endif #endif


for (uint i=0, count = kEngine->getCurrentPluginCount(); i < count; ++i) for (uint i=0, count = kEngine->getCurrentPluginCount(); i < count; ++i)
@@ -90,7 +91,7 @@ void CarlaEngineThread::run() noexcept
// ----------------------------------------------------------- // -----------------------------------------------------------
// Post-poned events // Post-poned events


if (oscRegisted || updateUI)
if (oscRegistedForUDP || updateUI)
{ {
// ------------------------------------------------------- // -------------------------------------------------------
// Update parameter outputs // Update parameter outputs
@@ -104,7 +105,7 @@ void CarlaEngineThread::run() noexcept


#if defined(HAVE_LIBLO) && ! defined(BUILD_BRIDGE) #if defined(HAVE_LIBLO) && ! defined(BUILD_BRIDGE)
// Update OSC engine client // Update OSC engine client
if (oscRegisted)
if (oscRegistedForUDP)
engineOsc.sendParameterValue(i, j, value); engineOsc.sendParameterValue(i, j, value);
#endif #endif
// Update UI // Update UI
@@ -124,11 +125,29 @@ void CarlaEngineThread::run() noexcept
// ----------------------------------------------------------- // -----------------------------------------------------------
// Update OSC control client peaks // Update OSC control client peaks


if (oscRegisted)
if (oscRegistedForUDP)
engineOsc.sendPeaks(i, kEngine->getPeaks(i)); engineOsc.sendPeaks(i, kEngine->getPeaks(i));
#endif #endif
} }


#if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
if (oscRegistedForUDP)
engineOsc.sendRuntimeInfo();

/*
if (engineOsc.isControlRegisteredForTCP())
{
const int64_t timeNow = water::Time::currentTimeMillis();

if (timeNow - lastPingTime > 1000)
{
engineOsc.sendPing();
lastPingTime = timeNow;
}
}
*/
#endif

carla_msleep(25); carla_msleep(25);
} }




+ 14
- 4
source/frontend/carla_backend.py View File

@@ -3034,8 +3034,7 @@ class CarlaHostPlugin(CarlaHostMeta):
return self.sendMsgAndSetError(["patchbay_disconnect", connectionId]) return self.sendMsgAndSetError(["patchbay_disconnect", connectionId])


def patchbay_refresh(self, external): def patchbay_refresh(self, external):
# don't send external param, never used in plugins
return self.sendMsgAndSetError(["patchbay_refresh"])
return self.sendMsgAndSetError(["patchbay_refresh", external])


def transport_play(self): def transport_play(self):
self.sendMsg(["transport_play"]) self.sendMsg(["transport_play"])
@@ -3047,7 +3046,7 @@ class CarlaHostPlugin(CarlaHostMeta):
self.sendMsg(["transport_bpm", bpm]) self.sendMsg(["transport_bpm", bpm])


def transport_relocate(self, frame): def transport_relocate(self, frame):
self.sendMsg(["transport_relocate"])
self.sendMsg(["transport_relocate", frame])


def get_current_transport_frame(self): def get_current_transport_frame(self):
return self.fTransportInfo['frame'] return self.fTransportInfo['frame']
@@ -3313,6 +3312,15 @@ class CarlaHostPlugin(CarlaHostMeta):
self._reset_info(info) self._reset_info(info)
self.fPluginsInfo.append(info) self.fPluginsInfo.append(info)


def _allocateAsNeeded(self, pluginId):
if pluginId < len(self.fPluginsInfo):
return

for i in range(pluginId + 1 - len(self.fPluginsInfo)):
info = PluginStoreInfo()
self._reset_info(info)
self.fPluginsInfo.append(info)

def _reset_info(self, info): def _reset_info(self, info):
info.pluginInfo = PyCarlaPluginInfo.copy() info.pluginInfo = PyCarlaPluginInfo.copy()
info.pluginRealName = "" info.pluginRealName = ""
@@ -3352,6 +3360,7 @@ class CarlaHostPlugin(CarlaHostMeta):
self.fPluginsInfo[pluginId].internalValues[abs(paramIndex)-2] = float(value) self.fPluginsInfo[pluginId].internalValues[abs(paramIndex)-2] = float(value)


def _set_audioCountInfo(self, pluginId, info): def _set_audioCountInfo(self, pluginId, info):
#self._allocateAsNeeded(pluginId)
self.fPluginsInfo[pluginId].audioCountInfo = info self.fPluginsInfo[pluginId].audioCountInfo = info


def _set_midiCountInfo(self, pluginId, info): def _set_midiCountInfo(self, pluginId, info):
@@ -3455,7 +3464,8 @@ class CarlaHostPlugin(CarlaHostMeta):
self.fPluginsInfo[pluginId].customData[cdIndex] = data self.fPluginsInfo[pluginId].customData[cdIndex] = data


def _set_peaks(self, pluginId, in1, in2, out1, out2): def _set_peaks(self, pluginId, in1, in2, out1, out2):
self.fPluginsInfo[pluginId].peaks = [in1, in2, out1, out2]
if pluginId < len(self.fPluginsInfo):
self.fPluginsInfo[pluginId].peaks = [in1, in2, out1, out2]


def _switchPlugins(self, pluginIdA, pluginIdB): def _switchPlugins(self, pluginIdA, pluginIdB):
tmp = self.fPluginsInfo[pluginIdA] tmp = self.fPluginsInfo[pluginIdA]


+ 241
- 183
source/frontend/carla_control.py View File

@@ -44,8 +44,12 @@ class CarlaHostOSC(CarlaHostQtPlugin):
def __init__(self): def __init__(self):
CarlaHostQtPlugin.__init__(self) CarlaHostQtPlugin.__init__(self)


self.lo_target = None
self.lo_target_name = ""
self.lo_server_tcp = None
self.lo_server_udp = None
self.lo_target_tcp = None
self.lo_target_udp = None
self.lo_target_tcp_name = ""
self.lo_target_udp_name = ""


# ------------------------------------------------------------------- # -------------------------------------------------------------------


@@ -61,87 +65,96 @@ class CarlaHostOSC(CarlaHostQtPlugin):
method = lines.pop(0) method = lines.pop(0)


if method == "set_engine_option": if method == "set_engine_option":
print(method, lines)
return True return True


if self.lo_target is None:
return self.printAndReturnError("lo_target is None")
if self.lo_target_name is None:
return self.printAndReturnError("lo_target_name is None")

if method not in (
#"set_option",
"set_active",
"set_drywet",
"set_volume",
"set_balance_left",
"set_balance_right",
"set_panning",
#"set_ctrl_channel",
"set_parameter_value",
"set_parameter_midi_channel",
"set_parameter_midi_cc",
"set_program",
"set_midi_program",
#"set_custom_data",
#"set_chunk_data",
#"prepare_for_save",
#"reset_parameters",
#"randomize_parameters",
"send_midi_note"
):
return self.printAndReturnError("invalid method '%s'" % method)

pluginId = lines.pop(0)

args = []

if method == "send_midi_note":
channel, note, velocity = lines

if velocity:
method = "note_on"
args = [channel, note, velocity]
else:
method = "note_off"
args = [channel, note]
if self.lo_target_tcp is None:
return self.printAndReturnError("lo_target_tcp is None")
if self.lo_target_tcp_name is None:
return self.printAndReturnError("lo_target_tcp_name is None")

if method in ("clear_engine_xruns",
"cancel_engine_action",
#"load_file",
#"load_project",
#"save_project",
#"clear_project_filename",
"patchbay_connect",
"patchbay_disconnect",
"patchbay_refresh",
"transport_play",
"transport_pause",
"transport_bpm",
"transport_relocate",
#"add_plugin",
"remove_plugin",
"remove_all_plugins",
"rename_plugin",
"clone_plugin",
#"replace_plugin",
"switch_plugins",
#"load_plugin_state",
#"save_plugin_state",
):
path = "/ctrl/" + method

elif method in (#"set_option",
"set_active",
"set_drywet",
"set_volume",
"set_balance_left",
"set_balance_right",
"set_panning",
#"set_ctrl_channel",
"set_parameter_value",
"set_parameter_midi_channel",
"set_parameter_midi_cc",
"set_program",
"set_midi_program",
#"set_custom_data",
#"set_chunk_data",
#"prepare_for_save",
#"reset_parameters",
#"randomize_parameters",
"send_midi_note"
):
pluginId = lines.pop(0)
path = "/%s/%i/%s" % (self.lo_target_tcp_name, pluginId, method)


else: else:
for line in lines:
if isinstance(line, bool):
args.append(int(line))
else:
args.append(line)

path = "/%s/%i/%s" % (self.lo_target_name, pluginId, method)
return self.printAndReturnError("invalid method '%s'" % method)


print(path, args)
args = [int(line) if isinstance(line, bool) else line for line in lines]
#print(path, args)


lo_send(self.lo_target, path, *args)
lo_send(self.lo_target_tcp, path, *args)
return True return True


# ------------------------------------------------------------------- # -------------------------------------------------------------------


def engine_init(self, driverName, clientName): def engine_init(self, driverName, clientName):
return self.lo_target is not None
print("engine_init", self.lo_target_tcp is not None)
return self.lo_target_tcp is not None


def engine_close(self): def engine_close(self):
print("engine_close")
return True return True


def engine_idle(self): def engine_idle(self):
return return


def is_engine_running(self): def is_engine_running(self):
return self.lo_target is not None
return self.lo_target_tcp is not None


def set_engine_about_to_close(self): def set_engine_about_to_close(self):
return return


# ------------------------------------------------------------------------------------------------------------
# ---------------------------------------------------------------------------------------------------------------------
# OSC Control server # OSC Control server


class CarlaControlServer(Server):
def __init__(self, host, mode):
Server.__init__(self, 8998 + int(random()*9000), mode)
class CarlaControlServerTCP(Server):
def __init__(self, host):
Server.__init__(self, proto=LO_TCP)


self.host = host self.host = host


@@ -152,36 +165,32 @@ class CarlaControlServer(Server):
pass pass


def getFullURL(self): def getFullURL(self):
return "%scarla-control" % self.get_url()
return "%sctrl" % self.get_url()


@make_method('/carla-control/cb', 'iiiiifs')
@make_method('/ctrl/cb', 'iiiiifs')
def carla_cb(self, path, args): def carla_cb(self, path, args):
print(path, args)
self.fReceivedMsgs = True self.fReceivedMsgs = True
action, pluginId, value1, value2, value3, valuef, valueStr = args action, pluginId, value1, value2, value3, valuef, valueStr = args
self.host._setViaCallback(action, pluginId, value1, value2, value3, valuef, valueStr) self.host._setViaCallback(action, pluginId, value1, value2, value3, valuef, valueStr)
engineCallback(self.host, action, pluginId, value1, value2, value3, valuef, valueStr) engineCallback(self.host, action, pluginId, value1, value2, value3, valuef, valueStr)


@make_method('/carla-control/init', 'is') # FIXME set name in add method
@make_method('/ctrl/init', 'is') # FIXME set name in add method
def carla_init(self, path, args): def carla_init(self, path, args):
print(path, args)
self.fReceivedMsgs = True self.fReceivedMsgs = True
pluginId, pluginName = args pluginId, pluginName = args
self.host._add(pluginId) self.host._add(pluginId)
self.host._set_pluginInfoUpdate(pluginId, {'name': pluginName}) self.host._set_pluginInfoUpdate(pluginId, {'name': pluginName})


@make_method('/carla-control/ports', 'iiiiiiii')
@make_method('/ctrl/ports', 'iiiiiiii')
def carla_ports(self, path, args): def carla_ports(self, path, args):
print(path, args)
self.fReceivedMsgs = True self.fReceivedMsgs = True
pluginId, audioIns, audioOuts, midiIns, midiOuts, paramIns, paramOuts, paramTotal = args pluginId, audioIns, audioOuts, midiIns, midiOuts, paramIns, paramOuts, paramTotal = args
self.host._set_audioCountInfo(pluginId, {'ins': audioIns, 'outs': audioOuts}) self.host._set_audioCountInfo(pluginId, {'ins': audioIns, 'outs': audioOuts})
self.host._set_midiCountInfo(pluginId, {'ins': midiOuts, 'outs': midiOuts}) self.host._set_midiCountInfo(pluginId, {'ins': midiOuts, 'outs': midiOuts})
self.host._set_parameterCountInfo(pluginId, paramTotal, {'ins': paramIns, 'outs': paramOuts}) self.host._set_parameterCountInfo(pluginId, paramTotal, {'ins': paramIns, 'outs': paramOuts})


@make_method('/carla-control/info', 'iiiihssss')
@make_method('/ctrl/info', 'iiiihssss')
def carla_info(self, path, args): def carla_info(self, path, args):
print(path, args)
self.fReceivedMsgs = True self.fReceivedMsgs = True
pluginId, type_, category, hints, uniqueId, realName, label, maker, copyright = args pluginId, type_, category, hints, uniqueId, realName, label, maker, copyright = args
optsAvail = optsEnabled = 0x0 # FIXME optsAvail = optsEnabled = 0x0 # FIXME
@@ -207,9 +216,8 @@ class CarlaControlServer(Server):
self.host._set_pluginInfoUpdate(pluginId, pinfo) self.host._set_pluginInfoUpdate(pluginId, pinfo)
self.host._set_pluginRealName(pluginId, realName) self.host._set_pluginRealName(pluginId, realName)


@make_method('/carla-control/param', 'iiiiiissfffffff')
@make_method('/ctrl/param', 'iiiiiissfffffff')
def carla_param(self, path, args): def carla_param(self, path, args):
print(path, args)
self.fReceivedMsgs = True self.fReceivedMsgs = True
( (
pluginId, paramId, type_, hints, midiChan, midiCC, name, unit, pluginId, paramId, type_, hints, midiChan, midiCC, name, unit,
@@ -248,9 +256,8 @@ class CarlaControlServer(Server):


self.host._set_parameterValue(pluginId, paramId, value) self.host._set_parameterValue(pluginId, paramId, value)


@make_method('/carla-control/iparams', 'ifffffff')
@make_method('/ctrl/iparams', 'ifffffff')
def carla_iparams(self, path, args): def carla_iparams(self, path, args):
print(path, args)
self.fReceivedMsgs = True self.fReceivedMsgs = True
pluginId, active, drywet, volume, balLeft, balRight, pan, ctrlChan = args pluginId, active, drywet, volume, balLeft, balRight, pan, ctrlChan = args
self.host._set_internalValue(pluginId, PARAMETER_ACTIVE, active) self.host._set_internalValue(pluginId, PARAMETER_ACTIVE, active)
@@ -261,72 +268,97 @@ class CarlaControlServer(Server):
self.host._set_internalValue(pluginId, PARAMETER_PANNING, pan) self.host._set_internalValue(pluginId, PARAMETER_PANNING, pan)
self.host._set_internalValue(pluginId, PARAMETER_CTRL_CHANNEL, ctrlChan) self.host._set_internalValue(pluginId, PARAMETER_CTRL_CHANNEL, ctrlChan)


@make_method('/carla-control/set_program_count', 'ii')
def set_program_count_callback(self, path, args):
print(path, args)
#@make_method('/ctrl/set_program_count', 'ii')
#def set_program_count_callback(self, path, args):
#print(path, args)
#self.fReceivedMsgs = True
#pluginId, count = args
#self.host._set_programCount(pluginId, count)

#@make_method('/ctrl/set_midi_program_count', 'ii')
#def set_midi_program_count_callback(self, path, args):
#print(path, args)
#self.fReceivedMsgs = True
#pluginId, count = args
#self.host._set_midiProgramCount(pluginId, count)

#@make_method('/ctrl/set_program_name', 'iis')
#def set_program_name_callback(self, path, args):
#print(path, args)
#self.fReceivedMsgs = True
#pluginId, progId, progName = args
#self.host._set_programName(pluginId, progId, progName)

#@make_method('/ctrl/set_midi_program_data', 'iiiis')
#def set_midi_program_data_callback(self, path, args):
#print(path, args)
#self.fReceivedMsgs = True
#pluginId, midiProgId, bank, program, name = args
#self.host._set_midiProgramData(pluginId, midiProgId, {'bank': bank, 'program': program, 'name': name})

#@make_method('/note_on', 'iiii')

@make_method('/ctrl/exit', '')
def carla_exit(self, path, args):
self.fReceivedMsgs = True self.fReceivedMsgs = True
pluginId, count = args
self.host._set_programCount(pluginId, count)
#self.host.lo_target_tcp = None
self.host.QuitCallback.emit()


@make_method('/carla-control/set_midi_program_count', 'ii')
def set_midi_program_count_callback(self, path, args):
print(path, args)
@make_method('/ctrl/exit-error', 's')
def carla_exit_error(self, path, args):
self.fReceivedMsgs = True self.fReceivedMsgs = True
pluginId, count = args
self.host._set_midiProgramCount(pluginId, count)
error, = args
self.host.lo_target_tcp = None
self.host.QuitCallback.emit()
self.host.ErrorCallback.emit(error)


@make_method('/carla-control/set_program_name', 'iis')
def set_program_name_callback(self, path, args):
print(path, args)
@make_method(None, None)
def fallback(self, path, args):
print("ControlServerTCP::fallback(\"%s\") - unknown message, args =" % path, args)
self.fReceivedMsgs = True self.fReceivedMsgs = True
pluginId, progId, progName = args
self.host._set_programName(pluginId, progId, progName)


@make_method('/carla-control/set_midi_program_data', 'iiiis')
def set_midi_program_data_callback(self, path, args):
print(path, args)
self.fReceivedMsgs = True
pluginId, midiProgId, bank, program, name = args
self.host._set_midiProgramData(pluginId, midiProgId, {'bank': bank, 'program': program, 'name': name})
# ---------------------------------------------------------------------------------------------------------------------

class CarlaControlServerUDP(Server):
def __init__(self, host):
Server.__init__(self, proto=LO_UDP)

self.host = host


#@make_method('/carla-control/note_on', 'iiii')
def idle(self):
self.fReceivedMsgs = False

while self.recv(0) and self.fReceivedMsgs:
pass


@make_method('/carla-control/runtime', 'fiihiiif')
def getFullURL(self):
return "%sctrl" % self.get_url()

@make_method('/ctrl/runtime', 'fiihiiif')
def carla_runtime(self, path, args): def carla_runtime(self, path, args):
self.fReceivedMsgs = True self.fReceivedMsgs = True
load, xruns, playing, frame, bar, beat, tick, bpm = args load, xruns, playing, frame, bar, beat, tick, bpm = args
self.host._set_runtime_info(load, xruns) self.host._set_runtime_info(load, xruns)
self.host._set_transport(bool(playing), frame, bar, beat, tick, bpm) self.host._set_transport(bool(playing), frame, bar, beat, tick, bpm)


@make_method('/carla-control/param_fixme', 'iif')
@make_method('/ctrl/param', 'iif')
def carla_param_fixme(self, path, args): def carla_param_fixme(self, path, args):
self.fReceivedMsgs = True self.fReceivedMsgs = True
pluginId, paramId, paramValue = args pluginId, paramId, paramValue = args
self.host._set_parameterValue(pluginId, paramId, paramValue) self.host._set_parameterValue(pluginId, paramId, paramValue)


@make_method('/carla-control/peaks', 'iffff')
@make_method('/ctrl/peaks', 'iffff')
def carla_peaks(self, path, args): def carla_peaks(self, path, args):
self.fReceivedMsgs = True self.fReceivedMsgs = True
pluginId, in1, in2, out1, out2 = args pluginId, in1, in2, out1, out2 = args
self.host._set_peaks(pluginId, in1, in2, out1, out2) self.host._set_peaks(pluginId, in1, in2, out1, out2)


#@make_method('/carla-control/note_on', 'iiii')

@make_method('/carla-control/exit-error', 's')
def set_exit_error_callback(self, path, args):
print(path, args)
self.fReceivedMsgs = True
error, = args
self.host.lo_target = None
self.host.QuitCallback.emit()
self.host.ErrorCallback.emit(error)

@make_method(None, None) @make_method(None, None)
def fallback(self, path, args): def fallback(self, path, args):
print("ControlServer::fallback(\"%s\") - unknown message, args =" % path, args)
print("ControlServerUDP::fallback(\"%s\") - unknown message, args =" % path, args)
self.fReceivedMsgs = True self.fReceivedMsgs = True


# ------------------------------------------------------------------------------------------------------------
# ---------------------------------------------------------------------------------------------------------------------
# Main Window # Main Window


class HostWindowOSC(HostWindow): class HostWindowOSC(HostWindow):
@@ -339,11 +371,6 @@ class HostWindowOSC(HostWindow):
host = CarlaHostPlugin() host = CarlaHostPlugin()
self.host = host self.host = host


# ----------------------------------------------------------------------------------------------------
# Internal stuff

self.fOscServer = None

# ---------------------------------------------------------------------------------------------------- # ----------------------------------------------------------------------------------------------------
# Connect actions to functions # Connect actions to functions


@@ -356,32 +383,36 @@ class HostWindowOSC(HostWindow):
if oscAddr: if oscAddr:
QTimer.singleShot(0, self.connectOsc) QTimer.singleShot(0, self.connectOsc)


def connectOsc(self, addr = None):
if addr is not None:
self.fOscAddress = addr
def connectOsc(self, addrTCP = None, addrUDP = None):
if addrTCP is not None:
self.fOscAddressTCP = addrTCP
if addrUDP is not None:
self.fOscAddressUDP = addrUDP


lo_protocol = LO_UDP if self.fOscAddress.startswith("osc.udp") else LO_TCP
lo_target_name = self.fOscAddress.rsplit("/", 1)[-1]
lo_target_tcp_name = self.fOscAddressTCP.rsplit("/", 1)[-1]
lo_target_udp_name = self.fOscAddressUDP.rsplit("/", 1)[-1]


err = None err = None
print("Connecting to \"%s\" as '%s'..." % (self.fOscAddress, lo_target_name))


try: try:
lo_target = Address(self.fOscAddress)
self.fOscServer = CarlaControlServer(self.host, lo_protocol)
lo_send(lo_target, "/register", self.fOscServer.getFullURL())
lo_target_tcp = Address(self.fOscAddressTCP)
lo_server_tcp = CarlaControlServerTCP(self.host)
lo_send(lo_target_tcp, "/register", lo_server_tcp.getFullURL())
print(lo_server_tcp.getFullURL())

lo_target_udp = Address(self.fOscAddressUDP)
lo_server_udp = CarlaControlServerUDP(self.host)
lo_send(lo_target_udp, "/register", lo_server_udp.getFullURL())
print(lo_server_udp.getFullURL())


except AddressError as e: except AddressError as e:
err = e err = e
except OSError as e: except OSError as e:
err = e err = e
except: except:
err = { 'args': [] }
err = Exception()


if err is not None: if err is not None:
del self.fOscServer
self.fOscServer = None

fullError = self.tr("Failed to connect to the Carla instance.") fullError = self.tr("Failed to connect to the Carla instance.")


if len(err.args) > 0: if len(err.args) > 0:
@@ -400,53 +431,72 @@ class HostWindowOSC(HostWindow):
QMessageBox.Ok) QMessageBox.Ok)
return return


self.host.lo_target = lo_target
self.host.lo_target_name = lo_target_name
self.host.lo_server_tcp = lo_server_tcp
self.host.lo_target_tcp = lo_target_tcp
self.host.lo_target_tcp_name = lo_target_tcp_name

self.host.lo_server_udp = lo_server_udp
self.host.lo_target_udp = lo_target_udp
self.host.lo_target_udp_name = lo_target_udp_name

self.ui.act_file_refresh.setEnabled(True) self.ui.act_file_refresh.setEnabled(True)


self.startTimers() self.startTimers()


def disconnectOsc(self): def disconnectOsc(self):
self.killTimers() self.killTimers()

if self.host.lo_target is not None:
try:
lo_send(self.host.lo_target, "/unregister", self.fOscServer.getFullURL())
except:
pass

if self.fOscServer is not None:
del self.fOscServer
self.fOscServer = None

self.unregister()
self.removeAllPlugins() self.removeAllPlugins()


self.host.lo_target = None
self.host.lo_target_name = ""
self.ui.act_file_refresh.setEnabled(False) self.ui.act_file_refresh.setEnabled(False)


# -------------------------------------------------------------------------------------------------------- # --------------------------------------------------------------------------------------------------------
# Timers


def startTimers(self):
if self.fIdleTimerOSC == 0:
self.fIdleTimerOSC = self.startTimer(20)
def unregister(self):
if self.host.lo_server_tcp is not None:
if self.host.lo_target_tcp is not None:
try:
lo_send(self.host.lo_target_tcp, "/unregister", self.host.lo_server_tcp.getFullURL())
except:
pass
self.host.lo_target_tcp = None

while self.host.lo_server_tcp.recv(0):
pass
#self.host.lo_server_tcp.free()
self.host.lo_server_tcp = None

if self.host.lo_server_udp is not None:
if self.host.lo_target_udp is not None:
try:
lo_send(self.host.lo_target_udp, "/unregister", self.host.lo_server_udp.getFullURL())
except:
pass
self.host.lo_target_udp = None

while self.host.lo_server_udp.recv(0):
pass
#self.host.lo_server_udp.free()
self.host.lo_server_udp = None


HostWindow.startTimers(self)
self.host.lo_target_tcp_name = ""
self.host.lo_target_udp_name = ""


def restartTimersIfNeeded(self):
if self.fIdleTimerOSC != 0:
self.killTimer(self.fIdleTimerOSC)
self.fIdleTimerOSC = self.startTimer(20)
# --------------------------------------------------------------------------------------------------------
# Timers


HostWindow.restartTimersIfNeeded(self)
def idleFast(self):
HostWindow.idleFast(self)


def killTimers(self):
if self.fIdleTimerOSC != 0:
self.killTimer(self.fIdleTimerOSC)
self.fIdleTimerOSC = 0
if self.host.lo_server_tcp is not None:
self.host.lo_server_tcp.idle()
else:
self.disconnectOsc()


HostWindow.killTimers(self)
if self.host.lo_server_udp is not None:
self.host.lo_server_udp.idle()
else:
self.disconnectOsc()


# -------------------------------------------------------------------------------------------------------- # --------------------------------------------------------------------------------------------------------


@@ -458,12 +508,15 @@ class HostWindowOSC(HostWindow):


def loadSettings(self, firstTime): def loadSettings(self, firstTime):
settings = HostWindow.loadSettings(self, firstTime) settings = HostWindow.loadSettings(self, firstTime)
self.fOscAddress = settings.value("RemoteAddress", "osc.tcp://127.0.0.1:22752/Carla", type=str)
self.fOscAddressTCP = settings.value("RemoteAddressTCP", "osc.tcp://127.0.0.1:22752/Carla", type=str)
self.fOscAddressUDP = settings.value("RemoteAddressUDP", "osc.udp://127.0.0.1:22752/Carla", type=str)


def saveSettings(self): def saveSettings(self):
settings = HostWindow.saveSettings(self) settings = HostWindow.saveSettings(self)
if self.fOscAddress:
settings.setValue("RemoteAddress", self.fOscAddress)
if self.fOscAddressTCP:
settings.setValue("RemoteAddressTCP", self.fOscAddressTCP)
if self.fOscAddressUDP:
settings.setValue("RemoteAddressUDP", self.fOscAddressUDP)


# -------------------------------------------------------------------------------------------------------- # --------------------------------------------------------------------------------------------------------


@@ -472,7 +525,7 @@ class HostWindowOSC(HostWindow):
dialog = QInputDialog(self) dialog = QInputDialog(self)
dialog.setInputMode(QInputDialog.TextInput) dialog.setInputMode(QInputDialog.TextInput)
dialog.setLabelText(self.tr("Address:")) dialog.setLabelText(self.tr("Address:"))
dialog.setTextValue(self.fOscAddress or "osc.tcp://127.0.0.1:22752/Carla")
dialog.setTextValue(self.fOscAddressTCP or "osc.tcp://127.0.0.1:22752/Carla")
dialog.setWindowTitle(self.tr("Carla Control - Connect")) dialog.setWindowTitle(self.tr("Carla Control - Connect"))
dialog.resize(400,1) dialog.resize(400,1)


@@ -488,45 +541,50 @@ class HostWindowOSC(HostWindow):
self.disconnectOsc() self.disconnectOsc()


if addr: if addr:
self.connectOsc(addr)
self.connectOsc(addr.replace("osc.udp:", "osc.tcp:"), addr.replace("osc.tcp:", "osc.udp:"))


@pyqtSlot() @pyqtSlot()
def slot_fileRefresh(self): def slot_fileRefresh(self):
if self.host.lo_target is None or self.fOscServer is None:
if None in (self.host.lo_server_tcp, self.host.lo_server_udp, self.host.lo_target_tcp, self.host.lo_target_udp):
return return


self.killTimers()
lo_send(self.host.lo_target_udp, "/unregister", self.host.lo_server_udp.getFullURL())
while self.host.lo_server_udp.recv(0):
pass
#self.host.lo_server_udp.free()

lo_send(self.host.lo_target_tcp, "/unregister", self.host.lo_server_tcp.getFullURL())
while self.host.lo_server_tcp.recv(0):
pass
#self.host.lo_server_tcp.free()

self.removeAllPlugins() self.removeAllPlugins()


lo_send(self.host.lo_target, "/unregister", self.fOscServer.getFullURL())
lo_send(self.host.lo_target, "/register", self.fOscServer.getFullURL())
self.host.lo_server_tcp = CarlaControlServerTCP(self.host)
self.host.lo_server_udp = CarlaControlServerUDP(self.host)


self.startTimers()
try:
lo_send(self.host.lo_target_tcp, "/register", self.host.lo_server_tcp.getFullURL())
except:
self.disconnectOsc()
return

try:
lo_send(self.host.lo_target_udp, "/register", self.host.lo_server_udp.getFullURL())
except:
self.disconnectOsc()
return


@pyqtSlot() @pyqtSlot()
def slot_handleQuitCallback(self): def slot_handleQuitCallback(self):
HostWindow.slot_handleQuitCallback(self)
self.disconnectOsc() self.disconnectOsc()
HostWindow.slot_handleQuitCallback(self)


# -------------------------------------------------------------------------------------------------------- # --------------------------------------------------------------------------------------------------------


def timerEvent(self, event):
if event.timerId() == self.fIdleTimerOSC:
self.fOscServer.idle()

if self.host.lo_target is None:
self.disconnectOsc()

HostWindow.timerEvent(self, event)

def closeEvent(self, event): def closeEvent(self, event):
self.killTimers() self.killTimers()

if self.host.lo_target is not None and self.fOscServer is not None:
try:
lo_send(self.host.lo_target, "/unregister", self.fOscServer.getFullURL())
except:
pass
self.unregister()


HostWindow.closeEvent(self, event) HostWindow.closeEvent(self, event)




+ 10
- 4
source/frontend/carla_host.py View File

@@ -128,7 +128,6 @@ class HostWindow(QMainWindow):
# Internal stuff # Internal stuff


self.fIdleTimerNull = self.startTimer(1000) # keep application signals alive self.fIdleTimerNull = self.startTimer(1000) # keep application signals alive
self.fIdleTimerOSC = 0
self.fIdleTimerFast = 0 self.fIdleTimerFast = 0
self.fIdleTimerSlow = 0 self.fIdleTimerSlow = 0


@@ -147,7 +146,8 @@ class HostWindow(QMainWindow):
self.fLastTransportState = False self.fLastTransportState = False
self.fBufferSize = 0 self.fBufferSize = 0
self.fSampleRate = 0.0 self.fSampleRate = 0.0
self.fOscAddress = ""
self.fOscAddressTCP = ""
self.fOscAddressUDP = ""


if MACOS: if MACOS:
self.fMacClosingHelper = True self.fMacClosingHelper = True
@@ -577,7 +577,8 @@ class HostWindow(QMainWindow):
host.nsm_ready(NSM_CALLBACK_INIT) host.nsm_ready(NSM_CALLBACK_INIT)
return return


QTimer.singleShot(0, self.slot_engineStart)
if not host.isControl:
QTimer.singleShot(0, self.slot_engineStart)


# -------------------------------------------------------------------------------------------------------- # --------------------------------------------------------------------------------------------------------
# Setup # Setup
@@ -1262,8 +1263,13 @@ class HostWindow(QMainWindow):


@pyqtSlot(int, str) @pyqtSlot(int, str)
def slot_handlePluginAddedCallback(self, pluginId, pluginName): def slot_handlePluginAddedCallback(self, pluginId, pluginName):
pitem = self.ui.listWidget.createItem(pluginId)
if pluginId != self.fPluginCount:
print("ERROR: pluginAdded mismatch Id:", pluginId, self.fPluginCount)
pitem = self.getPluginItem(pluginId)
pitem.recreateWidget()
return


pitem = self.ui.listWidget.createItem(pluginId)
self.fPluginList.append(pitem) self.fPluginList.append(pitem)
self.fPluginCount += 1 self.fPluginCount += 1




+ 4
- 0
source/includes/CarlaDefines.h View File

@@ -175,6 +175,10 @@
#define CARLA_SAFE_ASSERT_CONTINUE(cond) if (! (cond)) { carla_safe_assert(#cond, __FILE__, __LINE__); continue; } #define CARLA_SAFE_ASSERT_CONTINUE(cond) if (! (cond)) { carla_safe_assert(#cond, __FILE__, __LINE__); continue; }
#define CARLA_SAFE_ASSERT_RETURN(cond, ret) if (! (cond)) { carla_safe_assert(#cond, __FILE__, __LINE__); return ret; } #define CARLA_SAFE_ASSERT_RETURN(cond, ret) if (! (cond)) { carla_safe_assert(#cond, __FILE__, __LINE__); return ret; }


#define CARLA_SAFE_ASSERT_INT_BREAK(cond, value) if (! (cond)) { carla_safe_assert_int(#cond, __FILE__, __LINE__, static_cast<int>(value); break; }
#define CARLA_SAFE_ASSERT_INT_CONTINUE(cond, value) if (! (cond)) { carla_safe_assert_int(#cond, __FILE__, __LINE__, static_cast<int>(value)); continue; }
#define CARLA_SAFE_ASSERT_INT_RETURN(cond, value, ret) if (! (cond)) { carla_safe_assert_int(#cond, __FILE__, __LINE__, static_cast<int>(value)); return ret; }

#define CARLA_SAFE_ASSERT_INT2_BREAK(cond, v1, v2) if (! (cond)) { carla_safe_assert_int2(#cond, __FILE__, __LINE__, static_cast<int>(v1), static_cast<int>(v2)); break; } #define CARLA_SAFE_ASSERT_INT2_BREAK(cond, v1, v2) if (! (cond)) { carla_safe_assert_int2(#cond, __FILE__, __LINE__, static_cast<int>(v1), static_cast<int>(v2)); break; }
#define CARLA_SAFE_ASSERT_INT2_CONTINUE(cond, v1, v2) if (! (cond)) { carla_safe_assert_int2(#cond, __FILE__, __LINE__, static_cast<int>(v1), static_cast<int>(v2)); continue; } #define CARLA_SAFE_ASSERT_INT2_CONTINUE(cond, v1, v2) if (! (cond)) { carla_safe_assert_int2(#cond, __FILE__, __LINE__, static_cast<int>(v1), static_cast<int>(v2)); continue; }
#define CARLA_SAFE_ASSERT_INT2_RETURN(cond, v1, v2, ret) if (! (cond)) { carla_safe_assert_int2(#cond, __FILE__, __LINE__, static_cast<int>(v1), static_cast<int>(v2)); return ret; } #define CARLA_SAFE_ASSERT_INT2_RETURN(cond, v1, v2, ret) if (! (cond)) { carla_safe_assert_int2(#cond, __FILE__, __LINE__, static_cast<int>(v1), static_cast<int>(v2)); return ret; }


Loading…
Cancel
Save