Audio plugin host https://kx.studio/carla
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.

352 lines
13KB

  1. // SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #ifndef CARLA_BRIDGE_UTILS_HPP_INCLUDED
  4. #define CARLA_BRIDGE_UTILS_HPP_INCLUDED
  5. #include "CarlaBridgeDefines.hpp"
  6. #include "CarlaMutex.hpp"
  7. #include "CarlaRingBuffer.hpp"
  8. #include "distrho/extra/String.hpp"
  9. // -------------------------------------------------------------------------------------------------------------------
  10. static inline
  11. const char* PluginBridgeRtClientOpcode2str(const PluginBridgeRtClientOpcode opcode) noexcept
  12. {
  13. switch (opcode)
  14. {
  15. case kPluginBridgeRtClientNull:
  16. return "kPluginBridgeRtClientNull";
  17. case kPluginBridgeRtClientSetAudioPool:
  18. return "kPluginBridgeRtClientSetAudioPool";
  19. case kPluginBridgeRtClientSetBufferSize:
  20. return "kPluginBridgeRtClientSetBufferSize";
  21. case kPluginBridgeRtClientSetSampleRate:
  22. return "kPluginBridgeRtClientSetSampleRate";
  23. case kPluginBridgeRtClientSetOnline:
  24. return "kPluginBridgeRtClientSetOnline";
  25. case kPluginBridgeRtClientControlEventParameter:
  26. return "kPluginBridgeRtClientControlEventParameter";
  27. case kPluginBridgeRtClientControlEventMidiBank:
  28. return "kPluginBridgeRtClientControlEventMidiBank";
  29. case kPluginBridgeRtClientControlEventMidiProgram:
  30. return "kPluginBridgeRtClientControlEventMidiProgram";
  31. case kPluginBridgeRtClientControlEventAllSoundOff:
  32. return "kPluginBridgeRtClientControlEventAllSoundOff";
  33. case kPluginBridgeRtClientControlEventAllNotesOff:
  34. return "kPluginBridgeRtClientControlEventAllNotesOff";
  35. case kPluginBridgeRtClientMidiEvent:
  36. return "kPluginBridgeRtClientMidiEvent";
  37. case kPluginBridgeRtClientProcess:
  38. return "kPluginBridgeRtClientProcess";
  39. case kPluginBridgeRtClientQuit:
  40. return "kPluginBridgeRtClientQuit";
  41. }
  42. carla_stderr("CarlaBackend::PluginBridgeRtClientOpcode2str(%i) - invalid opcode", opcode);
  43. return "";
  44. }
  45. static inline
  46. const char* PluginBridgeNonRtClientOpcode2str(const PluginBridgeNonRtClientOpcode opcode) noexcept
  47. {
  48. switch (opcode)
  49. {
  50. case kPluginBridgeNonRtClientNull:
  51. return "kPluginBridgeNonRtClientNull";
  52. case kPluginBridgeNonRtClientVersion:
  53. return "kPluginBridgeNonRtClientVersion";
  54. case kPluginBridgeNonRtClientPing:
  55. return "kPluginBridgeNonRtClientPing";
  56. case kPluginBridgeNonRtClientPingOnOff:
  57. return "kPluginBridgeNonRtClientPingOnOff";
  58. case kPluginBridgeNonRtClientActivate:
  59. return "kPluginBridgeNonRtClientActivate";
  60. case kPluginBridgeNonRtClientDeactivate:
  61. return "kPluginBridgeNonRtClientDeactivate";
  62. case kPluginBridgeNonRtClientInitialSetup:
  63. return "kPluginBridgeNonRtClientInitialSetup";
  64. case kPluginBridgeNonRtClientSetParameterValue:
  65. return "kPluginBridgeNonRtClientSetParameterValue";
  66. case kPluginBridgeNonRtClientSetParameterMidiChannel:
  67. return "kPluginBridgeNonRtClientSetParameterMidiChannel";
  68. case kPluginBridgeNonRtClientSetParameterMappedControlIndex:
  69. return "kPluginBridgeNonRtClientSetParameterMappedControlIndex";
  70. case kPluginBridgeNonRtClientSetProgram:
  71. return "kPluginBridgeNonRtClientSetProgram";
  72. case kPluginBridgeNonRtClientSetMidiProgram:
  73. return "kPluginBridgeNonRtClientSetMidiProgram";
  74. case kPluginBridgeNonRtClientSetCustomData:
  75. return "kPluginBridgeNonRtClientSetCustomData";
  76. case kPluginBridgeNonRtClientSetChunkDataFile:
  77. return "kPluginBridgeNonRtClientSetChunkDataFile";
  78. case kPluginBridgeNonRtClientSetCtrlChannel:
  79. return "kPluginBridgeNonRtClientSetCtrlChannel";
  80. case kPluginBridgeNonRtClientSetOption:
  81. return "kPluginBridgeNonRtClientSetOption";
  82. case kPluginBridgeNonRtClientGetParameterText:
  83. return "kPluginBridgeNonRtClientGetParameterText";
  84. case kPluginBridgeNonRtClientPrepareForSave:
  85. return "kPluginBridgeNonRtClientPrepareForSave";
  86. case kPluginBridgeNonRtClientRestoreLV2State:
  87. return "kPluginBridgeNonRtClientRestoreLV2State";
  88. case kPluginBridgeNonRtClientShowUI:
  89. return "kPluginBridgeNonRtClientShowUI";
  90. case kPluginBridgeNonRtClientHideUI:
  91. return "kPluginBridgeNonRtClientHideUI";
  92. case kPluginBridgeNonRtClientUiParameterChange:
  93. return "kPluginBridgeNonRtClientUiParameterChange";
  94. case kPluginBridgeNonRtClientUiProgramChange:
  95. return "kPluginBridgeNonRtClientUiProgramChange";
  96. case kPluginBridgeNonRtClientUiMidiProgramChange:
  97. return "kPluginBridgeNonRtClientUiMidiProgramChange";
  98. case kPluginBridgeNonRtClientUiNoteOn:
  99. return "kPluginBridgeNonRtClientUiNoteOn";
  100. case kPluginBridgeNonRtClientUiNoteOff:
  101. return "kPluginBridgeNonRtClientUiNoteOff";
  102. case kPluginBridgeNonRtClientQuit:
  103. return "kPluginBridgeNonRtClientQuit";
  104. case kPluginBridgeNonRtClientSetParameterMappedRange:
  105. return "kPluginBridgeNonRtClientSetParameterMappedRange";
  106. case kPluginBridgeNonRtClientSetOptions:
  107. return "kPluginBridgeNonRtClientSetOptions";
  108. case kPluginBridgeNonRtClientSetWindowTitle:
  109. return "kPluginBridgeNonRtClientSetWindowTitle";
  110. case kPluginBridgeNonRtClientEmbedUI:
  111. return "kPluginBridgeNonRtClientEmbedUI";
  112. case kPluginBridgeNonRtClientReload:
  113. return "kPluginBridgeNonRtClientReload";
  114. }
  115. carla_stderr("CarlaBackend::PluginBridgeNonRtClientOpcode2str(%i) - invalid opcode", opcode);
  116. return "";
  117. }
  118. static inline
  119. const char* PluginBridgeNonRtServerOpcode2str(const PluginBridgeNonRtServerOpcode opcode) noexcept
  120. {
  121. switch (opcode)
  122. {
  123. case kPluginBridgeNonRtServerNull:
  124. return "kPluginBridgeNonRtServerNull";
  125. case kPluginBridgeNonRtServerPong:
  126. return "kPluginBridgeNonRtServerPong";
  127. case kPluginBridgeNonRtServerPluginInfo1:
  128. return "kPluginBridgeNonRtServerPluginInfo1";
  129. case kPluginBridgeNonRtServerPluginInfo2:
  130. return "kPluginBridgeNonRtServerPluginInfo2";
  131. case kPluginBridgeNonRtServerAudioCount:
  132. return "kPluginBridgeNonRtServerAudioCount";
  133. case kPluginBridgeNonRtServerMidiCount:
  134. return "kPluginBridgeNonRtServerMidiCount";
  135. case kPluginBridgeNonRtServerCvCount:
  136. return "kPluginBridgeNonRtServerCvCount";
  137. case kPluginBridgeNonRtServerParameterCount:
  138. return "kPluginBridgeNonRtServerParameterCount";
  139. case kPluginBridgeNonRtServerProgramCount:
  140. return "kPluginBridgeNonRtServerProgramCount";
  141. case kPluginBridgeNonRtServerMidiProgramCount:
  142. return "kPluginBridgeNonRtServerMidiProgramCount";
  143. case kPluginBridgeNonRtServerPortName:
  144. return "kPluginBridgeNonRtServerPortName";
  145. case kPluginBridgeNonRtServerParameterData1:
  146. return "kPluginBridgeNonRtServerParameterData1";
  147. case kPluginBridgeNonRtServerParameterData2:
  148. return "kPluginBridgeNonRtServerParameterData2";
  149. case kPluginBridgeNonRtServerParameterRanges:
  150. return "kPluginBridgeNonRtServerParameterRanges";
  151. case kPluginBridgeNonRtServerParameterValue:
  152. return "kPluginBridgeNonRtServerParameterValue";
  153. case kPluginBridgeNonRtServerParameterValue2:
  154. return "kPluginBridgeNonRtServerParameterValue2";
  155. case kPluginBridgeNonRtServerParameterTouch:
  156. return "kPluginBridgeNonRtServerParameterTouch";
  157. case kPluginBridgeNonRtServerDefaultValue:
  158. return "kPluginBridgeNonRtServerDefaultValue";
  159. case kPluginBridgeNonRtServerCurrentProgram:
  160. return "kPluginBridgeNonRtServerCurrentProgram";
  161. case kPluginBridgeNonRtServerCurrentMidiProgram:
  162. return "kPluginBridgeNonRtServerCurrentMidiProgram";
  163. case kPluginBridgeNonRtServerProgramName:
  164. return "kPluginBridgeNonRtServerProgramName";
  165. case kPluginBridgeNonRtServerMidiProgramData:
  166. return "kPluginBridgeNonRtServerMidiProgramData";
  167. case kPluginBridgeNonRtServerSetCustomData:
  168. return "kPluginBridgeNonRtServerSetCustomData";
  169. case kPluginBridgeNonRtServerSetChunkDataFile:
  170. return "kPluginBridgeNonRtServerSetChunkDataFile";
  171. case kPluginBridgeNonRtServerSetLatency:
  172. return "kPluginBridgeNonRtServerSetLatency";
  173. case kPluginBridgeNonRtServerSetParameterText:
  174. return "kPluginBridgeNonRtServerSetParameterText";
  175. case kPluginBridgeNonRtServerReady:
  176. return "kPluginBridgeNonRtServerReady";
  177. case kPluginBridgeNonRtServerSaved:
  178. return "kPluginBridgeNonRtServerSaved";
  179. case kPluginBridgeNonRtServerUiClosed:
  180. return "kPluginBridgeNonRtServerUiClosed";
  181. case kPluginBridgeNonRtServerError:
  182. return "kPluginBridgeNonRtServerError";
  183. case kPluginBridgeNonRtServerVersion:
  184. return "kPluginBridgeNonRtServerVersion";
  185. case kPluginBridgeNonRtServerRespEmbedUI:
  186. return "kPluginBridgeNonRtServerRespEmbedUI";
  187. case kPluginBridgeNonRtServerResizeEmbedUI:
  188. return "kPluginBridgeNonRtServerResizeEmbedUI";
  189. }
  190. carla_stderr("CarlaBackend::PluginBridgeNonRtServerOpcode2str%i) - invalid opcode", opcode);
  191. return "";
  192. }
  193. // -------------------------------------------------------------------------------------------------------------------
  194. static constexpr const std::size_t kBridgeRtClientDataMidiOutSize = 511*4;
  195. static constexpr const std::size_t kBridgeBaseMidiOutHeaderSize = 6U /* time, port and size */;
  196. // Server => Client RT
  197. struct BridgeRtClientData {
  198. BridgeSemaphore sem;
  199. BridgeTimeInfo timeInfo;
  200. SmallStackBuffer ringBuffer;
  201. uint8_t midiOut[kBridgeRtClientDataMidiOutSize];
  202. uint32_t procFlags;
  203. };
  204. // Server => Client Non-RT
  205. struct BridgeNonRtClientData {
  206. BigStackBuffer ringBuffer;
  207. };
  208. // Client => Server Non-RT
  209. struct BridgeNonRtServerData {
  210. HugeStackBuffer ringBuffer;
  211. };
  212. // -------------------------------------------------------------------------------------------------------------------
  213. struct CARLA_API BridgeAudioPool {
  214. float* data;
  215. std::size_t dataSize;
  216. String filename;
  217. char shm[64];
  218. bool isServer;
  219. BridgeAudioPool() noexcept;
  220. ~BridgeAudioPool() noexcept;
  221. bool initializeServer() noexcept;
  222. bool attachClient(const char* const fname) noexcept;
  223. void clear() noexcept;
  224. void resize(const uint32_t bufferSize, const uint32_t audioPortCount, const uint32_t cvPortCount) noexcept;
  225. const char* getFilenameSuffix() const noexcept;
  226. CARLA_DECLARE_NON_COPYABLE(BridgeAudioPool)
  227. };
  228. // -------------------------------------------------------------------------------------------------------------------
  229. struct CARLA_API BridgeRtClientControl : public CarlaRingBufferControl<SmallStackBuffer> {
  230. BridgeRtClientData* data;
  231. String filename;
  232. bool needsSemDestroy; // client only
  233. char shm[64];
  234. bool isServer;
  235. BridgeRtClientControl() noexcept;
  236. ~BridgeRtClientControl() noexcept override;
  237. bool initializeServer() noexcept;
  238. bool attachClient(const char* const basename) noexcept;
  239. void clear() noexcept;
  240. bool mapData() noexcept;
  241. void unmapData() noexcept;
  242. // non-bridge, server
  243. bool waitForClient(const uint msecs) noexcept;
  244. bool writeOpcode(const PluginBridgeRtClientOpcode opcode) noexcept;
  245. // bridge, client
  246. PluginBridgeRtClientOpcode readOpcode() noexcept;
  247. // helper class that automatically posts semaphore on destructor
  248. struct WaitHelper {
  249. BridgeRtClientData* const data;
  250. const bool ok;
  251. WaitHelper(BridgeRtClientControl& c) noexcept;
  252. ~WaitHelper() noexcept;
  253. CARLA_DECLARE_NON_COPYABLE(WaitHelper)
  254. };
  255. CARLA_DECLARE_NON_COPYABLE(BridgeRtClientControl)
  256. };
  257. // -------------------------------------------------------------------------------------------------------------------
  258. struct CARLA_API BridgeNonRtClientControl : public CarlaRingBufferControl<BigStackBuffer> {
  259. BridgeNonRtClientData* data;
  260. String filename;
  261. CarlaMutex mutex;
  262. char shm[64];
  263. bool isServer;
  264. BridgeNonRtClientControl() noexcept;
  265. ~BridgeNonRtClientControl() noexcept override;
  266. bool initializeServer() noexcept;
  267. bool attachClient(const char* const basename) noexcept;
  268. void clear() noexcept;
  269. bool mapData() noexcept;
  270. void unmapData() noexcept;
  271. // non-bridge, server
  272. void waitIfDataIsReachingLimit() noexcept;
  273. bool writeOpcode(const PluginBridgeNonRtClientOpcode opcode) noexcept;
  274. // bridge, client
  275. PluginBridgeNonRtClientOpcode readOpcode() noexcept;
  276. CARLA_DECLARE_NON_COPYABLE(BridgeNonRtClientControl)
  277. };
  278. // -------------------------------------------------------------------------------------------------------------------
  279. struct CARLA_API BridgeNonRtServerControl : public CarlaRingBufferControl<HugeStackBuffer> {
  280. BridgeNonRtServerData* data;
  281. String filename;
  282. CarlaMutex mutex;
  283. char shm[64];
  284. bool isServer;
  285. BridgeNonRtServerControl() noexcept;
  286. ~BridgeNonRtServerControl() noexcept override;
  287. bool initializeServer() noexcept;
  288. bool attachClient(const char* const basename) noexcept;
  289. void clear() noexcept;
  290. bool mapData() noexcept;
  291. void unmapData() noexcept;
  292. // non-bridge, server
  293. PluginBridgeNonRtServerOpcode readOpcode() noexcept;
  294. // bridge, client
  295. void waitIfDataIsReachingLimit() noexcept;
  296. bool writeOpcode(const PluginBridgeNonRtServerOpcode opcode) noexcept;
  297. CARLA_DECLARE_NON_COPYABLE(BridgeNonRtServerControl)
  298. };
  299. // -------------------------------------------------------------------------------------------------------------------
  300. #endif // CARLA_BRIDGE_UTILS_HPP_INCLUDED