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.

306 lines
8.7KB

  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. kPluginBridgeOpcodeReadyWait = 1,
  51. kPluginBridgeOpcodeSetBufferSize = 2,
  52. kPluginBridgeOpcodeSetSampleRate = 3,
  53. kPluginBridgeOpcodeSetParameter = 4,
  54. kPluginBridgeOpcodeSetProgram = 5,
  55. kPluginBridgeOpcodeSetMidiProgram = 6,
  56. kPluginBridgeOpcodeProcess = 7,
  57. kPluginBridgeOpcodeQuit = 8
  58. };
  59. /*!
  60. * @defgroup BridgeMessages Bridge Messages
  61. *
  62. * Various bridge related messages, used as configure(<message>, value).
  63. * \note This is for internal use only.
  64. *
  65. * TODO: Review these, may not be needed anymore
  66. * @{
  67. */
  68. const char* const CARLA_BRIDGE_MSG_HIDE_GUI = "CarlaBridgeHideGUI"; //!< Plugin -> Host call, tells host GUI is now hidden
  69. const char* const CARLA_BRIDGE_MSG_SAVED = "CarlaBridgeSaved"; //!< Plugin -> Host call, tells host state is saved
  70. #if 0
  71. const char* const CARLA_BRIDGE_MSG_SAVE_NOW = "CarlaBridgeSaveNow"; //!< Host -> Plugin call, tells plugin to save state now
  72. const char* const CARLA_BRIDGE_MSG_SET_CHUNK = "CarlaBridgeSetChunk"; //!< Host -> Plugin call, tells plugin to set chunk in file \a value
  73. 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").
  74. //If \a type is 'chunk' or 'binary' \a rvalue refers to chunk file.
  75. #endif
  76. /**@}*/
  77. /*!
  78. * TODO.
  79. */
  80. struct BridgeRingBuffer {
  81. int head;
  82. int tail;
  83. int written;
  84. bool invalidateCommit;
  85. char buf[BRIDGE_SHM_RING_BUFFER_SIZE];
  86. };
  87. /*!
  88. * TODO.
  89. */
  90. struct BridgeShmControl {
  91. // 32 and 64-bit binaries align semaphores differently.
  92. // Let's make sure there's plenty of room for either one.
  93. union {
  94. sem_t runServer;
  95. char _alignServer[32];
  96. };
  97. union {
  98. sem_t runClient;
  99. char _alignClient[32];
  100. };
  101. BridgeRingBuffer ringBuffer;
  102. };
  103. static inline
  104. const char* PluginBridgeInfoType2str(const PluginBridgeInfoType type)
  105. {
  106. switch (type)
  107. {
  108. case kPluginBridgeAudioCount:
  109. return "kPluginBridgeAudioCount";
  110. case kPluginBridgeMidiCount:
  111. return "kPluginBridgeMidiCount";
  112. case kPluginBridgeParameterCount:
  113. return "kPluginBridgeParameterCount";
  114. case kPluginBridgeProgramCount:
  115. return "kPluginBridgeProgramCount";
  116. case kPluginBridgeMidiProgramCount:
  117. return "kPluginBridgeMidiProgramCount";
  118. case kPluginBridgePluginInfo:
  119. return "kPluginBridgePluginInfo";
  120. case kPluginBridgeParameterInfo:
  121. return "kPluginBridgeParameterInfo";
  122. case kPluginBridgeParameterData:
  123. return "kPluginBridgeParameterData";
  124. case kPluginBridgeParameterRanges:
  125. return "kPluginBridgeParameterRanges";
  126. case kPluginBridgeProgramInfo:
  127. return "kPluginBridgeProgramInfo";
  128. case kPluginBridgeMidiProgramInfo:
  129. return "kPluginBridgeMidiProgramInfo";
  130. case kPluginBridgeConfigure:
  131. return "kPluginBridgeConfigure";
  132. case kPluginBridgeSetParameterValue:
  133. return "kPluginBridgeSetParameterValue";
  134. case kPluginBridgeSetDefaultValue:
  135. return "kPluginBridgeSetDefaultValue";
  136. case kPluginBridgeSetProgram:
  137. return "kPluginBridgeSetProgram";
  138. case kPluginBridgeSetMidiProgram:
  139. return "kPluginBridgeSetMidiProgram";
  140. case kPluginBridgeSetCustomData:
  141. return "kPluginBridgeSetCustomData";
  142. case kPluginBridgeSetChunkData:
  143. return "kPluginBridgeSetChunkData";
  144. case kPluginBridgeUpdateNow:
  145. return "kPluginBridgeUpdateNow";
  146. case kPluginBridgeError:
  147. return "kPluginBridgeError";
  148. }
  149. carla_stderr("CarlaBackend::PluginBridgeInfoType2str(%i) - invalid type", type);
  150. return nullptr;
  151. }
  152. // ---------------------------------------------------------------------------------------------
  153. static inline
  154. void rdwr_tryRead(BridgeRingBuffer* const ringbuf, void* const buf, const size_t size)
  155. {
  156. char* const charbuf(static_cast<char*>(buf));
  157. size_t tail = ringbuf->tail;
  158. size_t head = ringbuf->head;
  159. size_t wrap = 0;
  160. if (head <= tail) {
  161. wrap = BRIDGE_SHM_RING_BUFFER_SIZE;
  162. }
  163. if (head - tail + wrap < size) {
  164. return;
  165. }
  166. size_t readto = tail + size;
  167. if (readto >= BRIDGE_SHM_RING_BUFFER_SIZE)
  168. {
  169. readto -= BRIDGE_SHM_RING_BUFFER_SIZE;
  170. size_t firstpart = BRIDGE_SHM_RING_BUFFER_SIZE - tail;
  171. std::memcpy(charbuf, ringbuf->buf + tail, firstpart);
  172. std::memcpy(charbuf + firstpart, ringbuf->buf, readto);
  173. }
  174. else
  175. {
  176. std::memcpy(charbuf, ringbuf->buf + tail, size);
  177. }
  178. ringbuf->tail = readto;
  179. }
  180. static inline
  181. void rdwr_tryWrite(BridgeRingBuffer* const ringbuf, const void* const buf, const size_t size)
  182. {
  183. const char* const charbuf(static_cast<const char*>(buf));
  184. size_t written = ringbuf->written;
  185. size_t tail = ringbuf->tail;
  186. size_t wrap = 0;
  187. if (tail <= written)
  188. {
  189. wrap = BRIDGE_SHM_RING_BUFFER_SIZE;
  190. }
  191. if (tail - written + wrap < size)
  192. {
  193. carla_stderr2("Ring buffer full! Dropping events.");
  194. ringbuf->invalidateCommit = true;
  195. return;
  196. }
  197. size_t writeto = written + size;
  198. if (writeto >= BRIDGE_SHM_RING_BUFFER_SIZE)
  199. {
  200. writeto -= BRIDGE_SHM_RING_BUFFER_SIZE;
  201. size_t firstpart = BRIDGE_SHM_RING_BUFFER_SIZE - written;
  202. std::memcpy(ringbuf->buf + written, charbuf, firstpart);
  203. std::memcpy(ringbuf->buf, charbuf + firstpart, writeto);
  204. }
  205. else
  206. {
  207. std::memcpy(ringbuf->buf + written, charbuf, size);
  208. }
  209. ringbuf->written = writeto;
  210. }
  211. static inline
  212. void rdwr_commitWrite(BridgeRingBuffer* const ringbuf)
  213. {
  214. if (ringbuf->invalidateCommit)
  215. {
  216. ringbuf->written = ringbuf->head;
  217. ringbuf->invalidateCommit = false;
  218. }
  219. else
  220. {
  221. ringbuf->head = ringbuf->written;
  222. }
  223. }
  224. // ---------------------------------------------------------------------------------------------
  225. static inline
  226. bool rdwr_dataAvailable(BridgeRingBuffer* const ringbuf)
  227. {
  228. return (ringbuf->tail != ringbuf->head);
  229. }
  230. static inline
  231. PluginBridgeOpcode rdwr_readOpcode(BridgeRingBuffer* const ringbuf)
  232. {
  233. int i = kPluginBridgeOpcodeNull;
  234. rdwr_tryRead(ringbuf, &i, sizeof(int));
  235. return static_cast<PluginBridgeOpcode>(i);
  236. }
  237. static inline
  238. int rdwr_readInt(BridgeRingBuffer* const ringbuf)
  239. {
  240. int i = 0;
  241. rdwr_tryRead(ringbuf, &i, sizeof(int));
  242. return i;
  243. }
  244. static inline
  245. float rdwr_readFloat(BridgeRingBuffer* const ringbuf)
  246. {
  247. float f = 0.0f;
  248. rdwr_tryRead(ringbuf, &f, sizeof(float));
  249. return f;
  250. }
  251. // ---------------------------------------------------------------------------------------------
  252. static inline
  253. void rdwr_writeOpcode(BridgeRingBuffer* const ringbuf, const PluginBridgeOpcode opcode)
  254. {
  255. const int i = opcode;
  256. rdwr_tryWrite(ringbuf, &i, sizeof(int));
  257. }
  258. static inline
  259. void rdwr_writeInt(BridgeRingBuffer* const ringbuf, const int value)
  260. {
  261. rdwr_tryWrite(ringbuf, &value, sizeof(int));
  262. }
  263. static inline
  264. void rdwr_writeFloat(BridgeRingBuffer* const ringbuf, const float value)
  265. {
  266. rdwr_tryWrite(ringbuf, &value, sizeof(float));
  267. }
  268. // ---------------------------------------------------------------------------------------------
  269. #endif // __CARLA_BRIDGE_UTILS_HPP__