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.

365 lines
14KB

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