You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

243 lines
7.2KB

  1. /*
  2. * DISTRHO Cardinal Plugin
  3. * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; either version 3 of
  8. * the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the LICENSE file.
  16. */
  17. #include <engine/Engine.hpp>
  18. #include <patch.hpp>
  19. #include <system.hpp>
  20. #ifdef NDEBUG
  21. # undef DEBUG
  22. #endif
  23. #include "CardinalRemote.hpp"
  24. #include "PluginContext.hpp"
  25. #include "extra/Base64.hpp"
  26. #include "extra/ScopedSafeLocale.hpp"
  27. #if defined(STATIC_BUILD) || ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
  28. # undef HAVE_LIBLO
  29. #endif
  30. #if (defined(HAVE_LIBLO) || ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS) && !defined(HEADLESS)
  31. # define CARDINAL_REMOTE_ENABLED
  32. #endif
  33. #ifdef HAVE_LIBLO
  34. # include <lo/lo.h>
  35. // # define REMOTE_HOST "localhost"
  36. # define REMOTE_HOST "192.168.51.1"
  37. #endif
  38. // -----------------------------------------------------------------------------------------------------------
  39. namespace remoteUtils {
  40. #ifdef HAVE_LIBLO
  41. static int osc_handler(const char* const path, const char* const types, lo_arg** argv, const int argc, lo_message, void* const self)
  42. {
  43. d_stdout("osc_handler(\"%s\", \"%s\", %p, %i)", path, types, argv, argc);
  44. if (std::strcmp(path, "/resp") == 0 && argc == 2 && types[0] == 's' && types[1] == 's')
  45. {
  46. d_stdout("osc_handler(\"%s\", ...) - got resp | '%s' '%s'", path, &argv[0]->s, &argv[1]->s);
  47. if (std::strcmp(&argv[0]->s, "hello") == 0 && std::strcmp(&argv[1]->s, "ok") == 0)
  48. static_cast<RemoteDetails*>(self)->connected = true;
  49. }
  50. return 0;
  51. }
  52. #endif
  53. RemoteDetails* getRemote()
  54. {
  55. #ifdef CARDINAL_REMOTE_ENABLED
  56. CardinalPluginContext* const context = static_cast<CardinalPluginContext*>(APP);
  57. DISTRHO_SAFE_ASSERT_RETURN(context != nullptr, nullptr);
  58. CardinalBaseUI* const ui = static_cast<CardinalBaseUI*>(context->ui);
  59. DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr, nullptr);
  60. return ui->remoteDetails;
  61. #else
  62. return nullptr;
  63. #endif
  64. }
  65. bool connectToRemote()
  66. {
  67. #ifdef CARDINAL_REMOTE_ENABLED
  68. CardinalPluginContext* const context = static_cast<CardinalPluginContext*>(APP);
  69. DISTRHO_SAFE_ASSERT_RETURN(context != nullptr, false);
  70. CardinalBaseUI* const ui = static_cast<CardinalBaseUI*>(context->ui);
  71. DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr, false);
  72. RemoteDetails* remoteDetails = ui->remoteDetails;
  73. #if ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
  74. if (remoteDetails == nullptr)
  75. {
  76. ui->remoteDetails = remoteDetails = new RemoteDetails;
  77. remoteDetails->handle = ui;
  78. remoteDetails->connected = true;
  79. remoteDetails->autoDeploy = true;
  80. }
  81. #elif defined(HAVE_LIBLO)
  82. if (remoteDetails == nullptr)
  83. {
  84. const lo_server oscServer = lo_server_new_with_proto(nullptr, LO_UDP, nullptr);
  85. DISTRHO_SAFE_ASSERT_RETURN(oscServer != nullptr, false);
  86. ui->remoteDetails = remoteDetails = new RemoteDetails;
  87. remoteDetails->handle = oscServer;
  88. remoteDetails->connected = false;
  89. remoteDetails->autoDeploy = false;
  90. lo_server_add_method(oscServer, "/resp", nullptr, osc_handler, remoteDetails);
  91. }
  92. const lo_address addr = lo_address_new_with_proto(LO_UDP, REMOTE_HOST, CARDINAL_DEFAULT_REMOTE_HOST_PORT);
  93. DISTRHO_SAFE_ASSERT(addr != nullptr);
  94. if (addr != nullptr)
  95. {
  96. lo_send(addr, "/hello", "");
  97. lo_address_free(addr);
  98. }
  99. #endif
  100. return remoteDetails != nullptr;
  101. #else
  102. return false;
  103. #endif
  104. }
  105. void disconnectFromRemote(RemoteDetails* const remote)
  106. {
  107. if (remote != nullptr)
  108. {
  109. #ifdef HAVE_LIBLO
  110. lo_server_free(static_cast<lo_server>(remote->handle));
  111. #endif
  112. delete remote;
  113. }
  114. }
  115. void idleRemote(RemoteDetails* const remote)
  116. {
  117. DISTRHO_SAFE_ASSERT_RETURN(remote != nullptr,);
  118. #ifdef HAVE_LIBLO
  119. while (lo_server_recv_noblock(static_cast<lo_server>(remote->handle), 0) != 0) {}
  120. #endif
  121. }
  122. void sendParamChangeToRemote(RemoteDetails* const remote, int64_t moduleId, int paramId, float value)
  123. {
  124. #ifdef CARDINAL_REMOTE_ENABLED
  125. #if ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
  126. char paramBuf[512] = {};
  127. {
  128. const ScopedSafeLocale cssl;
  129. std::snprintf(paramBuf, sizeof(paramBuf), "%lld:%d:%f", (long long)moduleId, paramId, value);
  130. }
  131. static_cast<CardinalBaseUI*>(remote->handle)->setState("param", paramBuf);
  132. #elif defined(HAVE_LIBLO)
  133. const lo_address addr = lo_address_new_with_proto(LO_UDP, REMOTE_HOST, CARDINAL_DEFAULT_REMOTE_HOST_PORT);
  134. DISTRHO_SAFE_ASSERT_RETURN(addr != nullptr,);
  135. lo_send(addr, "/param", "hif", moduleId, paramId, value);
  136. lo_address_free(addr);
  137. #endif
  138. #endif
  139. }
  140. void sendFullPatchToRemote(RemoteDetails* const remote)
  141. {
  142. #ifdef CARDINAL_REMOTE_ENABLED
  143. CardinalPluginContext* const context = static_cast<CardinalPluginContext*>(APP);
  144. DISTRHO_SAFE_ASSERT_RETURN(context != nullptr,);
  145. context->engine->prepareSave();
  146. context->patch->saveAutosave();
  147. context->patch->cleanAutosave();
  148. std::vector<uint8_t> data;
  149. using namespace rack::system;
  150. #if ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
  151. FILE* const f = std::fopen(join(context->patch->autosavePath, "patch.json").c_str(), "r");
  152. DISTRHO_SAFE_ASSERT_RETURN(f != nullptr,);
  153. DEFER({
  154. std::fclose(f);
  155. });
  156. std::fseek(f, 0, SEEK_END);
  157. const long fileSize = std::ftell(f);
  158. DISTRHO_SAFE_ASSERT_RETURN(fileSize > 0,);
  159. std::fseek(f, 0, SEEK_SET);
  160. char* const fileContent = new char[fileSize+1];
  161. DISTRHO_SAFE_ASSERT_RETURN(std::fread(fileContent, fileSize, 1, f) == 1,);
  162. fileContent[fileSize] = '\0';
  163. static_cast<CardinalBaseUI*>(remote->handle)->setState("patch", fileContent);
  164. delete[] fileContent;
  165. #elif defined(HAVE_LIBLO)
  166. try {
  167. data = archiveDirectory(context->patch->autosavePath, 1);
  168. } DISTRHO_SAFE_EXCEPTION_RETURN("sendFullPatchToRemote",);
  169. DISTRHO_SAFE_ASSERT_RETURN(data.size() >= 4,);
  170. const lo_address addr = lo_address_new_with_proto(LO_UDP, REMOTE_HOST, CARDINAL_DEFAULT_REMOTE_HOST_PORT);
  171. DISTRHO_SAFE_ASSERT_RETURN(addr != nullptr,);
  172. if (const lo_blob blob = lo_blob_new(data.size(), data.data()))
  173. {
  174. lo_send(addr, "/load", "b", blob);
  175. lo_blob_free(blob);
  176. }
  177. lo_address_free(addr);
  178. #endif
  179. #endif
  180. }
  181. void sendScreenshotToRemote(RemoteDetails*, const char* const screenshot)
  182. {
  183. #if defined(HAVE_LIBLO) && DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
  184. const lo_address addr = lo_address_new_with_proto(LO_UDP, REMOTE_HOST, CARDINAL_DEFAULT_REMOTE_HOST_PORT);
  185. DISTRHO_SAFE_ASSERT_RETURN(addr != nullptr,);
  186. std::vector<uint8_t> data(d_getChunkFromBase64String(screenshot));
  187. if (const lo_blob blob = lo_blob_new(data.size(), data.data()))
  188. {
  189. lo_send(addr, "/screenshot", "b", blob);
  190. lo_blob_free(blob);
  191. }
  192. lo_address_free(addr);
  193. #endif
  194. }
  195. }
  196. // -----------------------------------------------------------------------------------------------------------