Signed-off-by: falkTX <falktx@falktx.com>tags/v2.1-alpha2
| @@ -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 | ||||
| @@ -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) | ||||
| @@ -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) | ||||
| @@ -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); | ||||
| @@ -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) | ||||
| @@ -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]), | ||||
| @@ -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); | ||||
| } | } | ||||
| @@ -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] | ||||
| @@ -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) | ||||
| @@ -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 | ||||
| @@ -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; } | ||||