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.

345 lines
9.6KB

  1. /*
  2. * Carla Bridge utils imported from dssi-vst code
  3. * Copyright (C) 2013 Filipe Coelho <falktx@falktx.com>
  4. * Copyright (C) 2004-2010 Chris Cannam <cannam@all-day-breakfast.com>
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License as
  8. * published by the Free Software Foundation; either version 2 of
  9. * the License, or any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * For a full copy of the GNU General Public License see the GPL.txt file
  17. */
  18. #ifndef __CARLA_BRIDGE_UTILS_HPP__
  19. #define __CARLA_BRIDGE_UTILS_HPP__
  20. #include "CarlaUtils.hpp"
  21. #include <semaphore.h>
  22. #define BRIDGE_SHM_RING_BUFFER_SIZE 2048
  23. /*!
  24. * TODO.
  25. */
  26. enum PluginBridgeInfoType {
  27. kPluginBridgeAudioCount,
  28. kPluginBridgeMidiCount,
  29. kPluginBridgeParameterCount,
  30. kPluginBridgeProgramCount,
  31. kPluginBridgeMidiProgramCount,
  32. kPluginBridgePluginInfo,
  33. kPluginBridgeParameterInfo,
  34. kPluginBridgeParameterData,
  35. kPluginBridgeParameterRanges,
  36. kPluginBridgeProgramInfo,
  37. kPluginBridgeMidiProgramInfo,
  38. kPluginBridgeConfigure,
  39. kPluginBridgeSetParameterValue,
  40. kPluginBridgeSetDefaultValue,
  41. kPluginBridgeSetProgram,
  42. kPluginBridgeSetMidiProgram,
  43. kPluginBridgeSetCustomData,
  44. kPluginBridgeSetChunkData,
  45. kPluginBridgeUpdateNow,
  46. kPluginBridgeError
  47. };
  48. enum PluginBridgeOpcode {
  49. kPluginBridgeOpcodeNull = 0,
  50. kPluginBridgeOpcodeSetAudioPool = 1, // int
  51. kPluginBridgeOpcodeSetBufferSize = 2, // int
  52. kPluginBridgeOpcodeSetSampleRate = 3, // float
  53. kPluginBridgeOpcodeSetParameter = 4, // int, float
  54. kPluginBridgeOpcodeSetProgram = 5, // int
  55. kPluginBridgeOpcodeSetMidiProgram = 6, // int
  56. kPluginBridgeOpcodeMidiEvent = 7, // long, int, char, ... (long = timeFrame, int = size max 4)
  57. kPluginBridgeOpcodeProcess = 8,
  58. kPluginBridgeOpcodeQuit = 9
  59. };
  60. /*!
  61. * @defgroup BridgeMessages Bridge Messages
  62. *
  63. * Various bridge related messages, used as configure(<message>, value).
  64. * \note This is for internal use only.
  65. *
  66. * TODO: Review these, may not be needed anymore
  67. * @{
  68. */
  69. const char* const CARLA_BRIDGE_MSG_HIDE_GUI = "CarlaBridgeHideGUI"; //!< Plugin -> Host call, tells host GUI is now hidden
  70. const char* const CARLA_BRIDGE_MSG_SAVED = "CarlaBridgeSaved"; //!< Plugin -> Host call, tells host state is saved
  71. #if 0
  72. const char* const CARLA_BRIDGE_MSG_SAVE_NOW = "CarlaBridgeSaveNow"; //!< Host -> Plugin call, tells plugin to save state now
  73. const char* const CARLA_BRIDGE_MSG_SET_CHUNK = "CarlaBridgeSetChunk"; //!< Host -> Plugin call, tells plugin to set chunk in file \a value
  74. const char* const CARLA_BRIDGE_MSG_SET_CUSTOM = "CarlaBridgeSetCustom"; //!< Host -> Plugin call, tells plugin to set a custom data set using \a value ("type·key·rvalue").
  75. //If \a type is 'chunk' or 'binary' \a rvalue refers to chunk file.
  76. #endif
  77. /**@}*/
  78. /*!
  79. * TODO.
  80. */
  81. struct BridgeRingBuffer {
  82. int head;
  83. int tail;
  84. int written;
  85. bool invalidateCommit;
  86. char buf[BRIDGE_SHM_RING_BUFFER_SIZE];
  87. };
  88. /*!
  89. * TODO.
  90. */
  91. struct BridgeShmControl {
  92. // 32 and 64-bit binaries align semaphores differently.
  93. // Let's make sure there's plenty of room for either one.
  94. union {
  95. sem_t runServer;
  96. char _alignServer[128];
  97. };
  98. union {
  99. sem_t runClient;
  100. char _alignClient[128];
  101. };
  102. BridgeRingBuffer ringBuffer;
  103. };
  104. static inline
  105. const char* PluginBridgeInfoType2str(const PluginBridgeInfoType type)
  106. {
  107. switch (type)
  108. {
  109. case kPluginBridgeAudioCount:
  110. return "kPluginBridgeAudioCount";
  111. case kPluginBridgeMidiCount:
  112. return "kPluginBridgeMidiCount";
  113. case kPluginBridgeParameterCount:
  114. return "kPluginBridgeParameterCount";
  115. case kPluginBridgeProgramCount:
  116. return "kPluginBridgeProgramCount";
  117. case kPluginBridgeMidiProgramCount:
  118. return "kPluginBridgeMidiProgramCount";
  119. case kPluginBridgePluginInfo:
  120. return "kPluginBridgePluginInfo";
  121. case kPluginBridgeParameterInfo:
  122. return "kPluginBridgeParameterInfo";
  123. case kPluginBridgeParameterData:
  124. return "kPluginBridgeParameterData";
  125. case kPluginBridgeParameterRanges:
  126. return "kPluginBridgeParameterRanges";
  127. case kPluginBridgeProgramInfo:
  128. return "kPluginBridgeProgramInfo";
  129. case kPluginBridgeMidiProgramInfo:
  130. return "kPluginBridgeMidiProgramInfo";
  131. case kPluginBridgeConfigure:
  132. return "kPluginBridgeConfigure";
  133. case kPluginBridgeSetParameterValue:
  134. return "kPluginBridgeSetParameterValue";
  135. case kPluginBridgeSetDefaultValue:
  136. return "kPluginBridgeSetDefaultValue";
  137. case kPluginBridgeSetProgram:
  138. return "kPluginBridgeSetProgram";
  139. case kPluginBridgeSetMidiProgram:
  140. return "kPluginBridgeSetMidiProgram";
  141. case kPluginBridgeSetCustomData:
  142. return "kPluginBridgeSetCustomData";
  143. case kPluginBridgeSetChunkData:
  144. return "kPluginBridgeSetChunkData";
  145. case kPluginBridgeUpdateNow:
  146. return "kPluginBridgeUpdateNow";
  147. case kPluginBridgeError:
  148. return "kPluginBridgeError";
  149. }
  150. carla_stderr("CarlaBackend::PluginBridgeInfoType2str(%i) - invalid type", type);
  151. return nullptr;
  152. }
  153. // ---------------------------------------------------------------------------------------------
  154. static inline
  155. void rdwr_tryRead(BridgeRingBuffer* const ringbuf, void* const buf, const size_t size)
  156. {
  157. CARLA_ASSERT(buf != nullptr);
  158. if (buf == nullptr)
  159. return;
  160. char* const charbuf(static_cast<char*>(buf));
  161. size_t tail = ringbuf->tail;
  162. size_t head = ringbuf->head;
  163. size_t wrap = 0;
  164. if (head <= tail) {
  165. wrap = BRIDGE_SHM_RING_BUFFER_SIZE;
  166. }
  167. if (head - tail + wrap < size) {
  168. return;
  169. }
  170. size_t readto = tail + size;
  171. if (readto >= BRIDGE_SHM_RING_BUFFER_SIZE)
  172. {
  173. readto -= BRIDGE_SHM_RING_BUFFER_SIZE;
  174. size_t firstpart = BRIDGE_SHM_RING_BUFFER_SIZE - tail;
  175. std::memcpy(charbuf, ringbuf->buf + tail, firstpart);
  176. std::memcpy(charbuf + firstpart, ringbuf->buf, readto);
  177. }
  178. else
  179. {
  180. std::memcpy(charbuf, ringbuf->buf + tail, size);
  181. }
  182. ringbuf->tail = readto;
  183. }
  184. static inline
  185. void rdwr_tryWrite(BridgeRingBuffer* const ringbuf, const void* const buf, const size_t size)
  186. {
  187. CARLA_ASSERT(buf != nullptr);
  188. if (buf == nullptr)
  189. return;
  190. const char* const charbuf(static_cast<const char*>(buf));
  191. size_t written = ringbuf->written;
  192. size_t tail = ringbuf->tail;
  193. size_t wrap = 0;
  194. if (tail <= written)
  195. {
  196. wrap = BRIDGE_SHM_RING_BUFFER_SIZE;
  197. }
  198. if (tail - written + wrap < size)
  199. {
  200. carla_stderr2("Ring buffer full! Dropping events.");
  201. ringbuf->invalidateCommit = true;
  202. return;
  203. }
  204. size_t writeto = written + size;
  205. if (writeto >= BRIDGE_SHM_RING_BUFFER_SIZE)
  206. {
  207. writeto -= BRIDGE_SHM_RING_BUFFER_SIZE;
  208. size_t firstpart = BRIDGE_SHM_RING_BUFFER_SIZE - written;
  209. std::memcpy(ringbuf->buf + written, charbuf, firstpart);
  210. std::memcpy(ringbuf->buf, charbuf + firstpart, writeto);
  211. }
  212. else
  213. {
  214. std::memcpy(ringbuf->buf + written, charbuf, size);
  215. }
  216. ringbuf->written = writeto;
  217. }
  218. static inline
  219. void rdwr_commitWrite(BridgeRingBuffer* const ringbuf)
  220. {
  221. if (ringbuf->invalidateCommit)
  222. {
  223. ringbuf->written = ringbuf->head;
  224. ringbuf->invalidateCommit = false;
  225. }
  226. else
  227. {
  228. ringbuf->head = ringbuf->written;
  229. }
  230. }
  231. // ---------------------------------------------------------------------------------------------
  232. static inline
  233. bool rdwr_dataAvailable(BridgeRingBuffer* const ringbuf)
  234. {
  235. return (ringbuf->tail != ringbuf->head);
  236. }
  237. static inline
  238. PluginBridgeOpcode rdwr_readOpcode(BridgeRingBuffer* const ringbuf)
  239. {
  240. int i = static_cast<int>(kPluginBridgeOpcodeNull);
  241. rdwr_tryRead(ringbuf, &i, sizeof(int));
  242. return static_cast<PluginBridgeOpcode>(i);
  243. }
  244. static inline
  245. char rdwr_readChar(BridgeRingBuffer* const ringbuf)
  246. {
  247. char c = 0;
  248. rdwr_tryRead(ringbuf, &c, sizeof(char));
  249. return c;
  250. }
  251. static inline
  252. int rdwr_readInt(BridgeRingBuffer* const ringbuf)
  253. {
  254. int i = 0;
  255. rdwr_tryRead(ringbuf, &i, sizeof(int));
  256. return i;
  257. }
  258. static inline
  259. long rdwr_readLong(BridgeRingBuffer* const ringbuf)
  260. {
  261. long l = 0;
  262. rdwr_tryRead(ringbuf, &l, sizeof(long));
  263. return l;
  264. }
  265. static inline
  266. float rdwr_readFloat(BridgeRingBuffer* const ringbuf)
  267. {
  268. float f = 0.0f;
  269. rdwr_tryRead(ringbuf, &f, sizeof(float));
  270. return f;
  271. }
  272. // ---------------------------------------------------------------------------------------------
  273. static inline
  274. void rdwr_writeOpcode(BridgeRingBuffer* const ringbuf, const PluginBridgeOpcode opcode)
  275. {
  276. const int intcode(static_cast<int>(opcode));
  277. rdwr_tryWrite(ringbuf, &intcode, sizeof(int));
  278. }
  279. static inline
  280. void rdwr_writeChar(BridgeRingBuffer* const ringbuf, const char value)
  281. {
  282. rdwr_tryWrite(ringbuf, &value, sizeof(char));
  283. }
  284. static inline
  285. void rdwr_writeInt(BridgeRingBuffer* const ringbuf, const int value)
  286. {
  287. rdwr_tryWrite(ringbuf, &value, sizeof(int));
  288. }
  289. static inline
  290. void rdwr_writeLong(BridgeRingBuffer* const ringbuf, const long value)
  291. {
  292. rdwr_tryWrite(ringbuf, &value, sizeof(long));
  293. }
  294. static inline
  295. void rdwr_writeFloat(BridgeRingBuffer* const ringbuf, const float value)
  296. {
  297. rdwr_tryWrite(ringbuf, &value, sizeof(float));
  298. }
  299. // ---------------------------------------------------------------------------------------------
  300. #endif // __CARLA_BRIDGE_UTILS_HPP__