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.

307 lines
8.8KB

  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, // int
  52. kPluginBridgeOpcodeSetSampleRate = 3, // float
  53. kPluginBridgeOpcodeSetParameter = 4, // int, float
  54. kPluginBridgeOpcodeSetProgram = 5, // int
  55. kPluginBridgeOpcodeSetMidiProgram = 6, // int
  56. kPluginBridgeOpcodeMidiEvent = 7, // int, char, ... (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[32];
  97. };
  98. union {
  99. sem_t runClient;
  100. char _alignClient[32];
  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. char* const charbuf(static_cast<char*>(buf));
  158. size_t tail = ringbuf->tail;
  159. size_t head = ringbuf->head;
  160. size_t wrap = 0;
  161. if (head <= tail) {
  162. wrap = BRIDGE_SHM_RING_BUFFER_SIZE;
  163. }
  164. if (head - tail + wrap < size) {
  165. return;
  166. }
  167. size_t readto = tail + size;
  168. if (readto >= BRIDGE_SHM_RING_BUFFER_SIZE)
  169. {
  170. readto -= BRIDGE_SHM_RING_BUFFER_SIZE;
  171. size_t firstpart = BRIDGE_SHM_RING_BUFFER_SIZE - tail;
  172. std::memcpy(charbuf, ringbuf->buf + tail, firstpart);
  173. std::memcpy(charbuf + firstpart, ringbuf->buf, readto);
  174. }
  175. else
  176. {
  177. std::memcpy(charbuf, ringbuf->buf + tail, size);
  178. }
  179. ringbuf->tail = readto;
  180. }
  181. static inline
  182. void rdwr_tryWrite(BridgeRingBuffer* const ringbuf, const void* const buf, const size_t size)
  183. {
  184. const char* const charbuf(static_cast<const char*>(buf));
  185. size_t written = ringbuf->written;
  186. size_t tail = ringbuf->tail;
  187. size_t wrap = 0;
  188. if (tail <= written)
  189. {
  190. wrap = BRIDGE_SHM_RING_BUFFER_SIZE;
  191. }
  192. if (tail - written + wrap < size)
  193. {
  194. carla_stderr2("Ring buffer full! Dropping events.");
  195. ringbuf->invalidateCommit = true;
  196. return;
  197. }
  198. size_t writeto = written + size;
  199. if (writeto >= BRIDGE_SHM_RING_BUFFER_SIZE)
  200. {
  201. writeto -= BRIDGE_SHM_RING_BUFFER_SIZE;
  202. size_t firstpart = BRIDGE_SHM_RING_BUFFER_SIZE - written;
  203. std::memcpy(ringbuf->buf + written, charbuf, firstpart);
  204. std::memcpy(ringbuf->buf, charbuf + firstpart, writeto);
  205. }
  206. else
  207. {
  208. std::memcpy(ringbuf->buf + written, charbuf, size);
  209. }
  210. ringbuf->written = writeto;
  211. }
  212. static inline
  213. void rdwr_commitWrite(BridgeRingBuffer* const ringbuf)
  214. {
  215. if (ringbuf->invalidateCommit)
  216. {
  217. ringbuf->written = ringbuf->head;
  218. ringbuf->invalidateCommit = false;
  219. }
  220. else
  221. {
  222. ringbuf->head = ringbuf->written;
  223. }
  224. }
  225. // ---------------------------------------------------------------------------------------------
  226. static inline
  227. bool rdwr_dataAvailable(BridgeRingBuffer* const ringbuf)
  228. {
  229. return (ringbuf->tail != ringbuf->head);
  230. }
  231. static inline
  232. PluginBridgeOpcode rdwr_readOpcode(BridgeRingBuffer* const ringbuf)
  233. {
  234. int i = kPluginBridgeOpcodeNull;
  235. rdwr_tryRead(ringbuf, &i, sizeof(int));
  236. return static_cast<PluginBridgeOpcode>(i);
  237. }
  238. static inline
  239. int rdwr_readInt(BridgeRingBuffer* const ringbuf)
  240. {
  241. int i = 0;
  242. rdwr_tryRead(ringbuf, &i, sizeof(int));
  243. return i;
  244. }
  245. static inline
  246. float rdwr_readFloat(BridgeRingBuffer* const ringbuf)
  247. {
  248. float f = 0.0f;
  249. rdwr_tryRead(ringbuf, &f, sizeof(float));
  250. return f;
  251. }
  252. // ---------------------------------------------------------------------------------------------
  253. static inline
  254. void rdwr_writeOpcode(BridgeRingBuffer* const ringbuf, const PluginBridgeOpcode opcode)
  255. {
  256. const int i = opcode;
  257. rdwr_tryWrite(ringbuf, &i, sizeof(int));
  258. }
  259. static inline
  260. void rdwr_writeInt(BridgeRingBuffer* const ringbuf, const int value)
  261. {
  262. rdwr_tryWrite(ringbuf, &value, sizeof(int));
  263. }
  264. static inline
  265. void rdwr_writeFloat(BridgeRingBuffer* const ringbuf, const float value)
  266. {
  267. rdwr_tryWrite(ringbuf, &value, sizeof(float));
  268. }
  269. // ---------------------------------------------------------------------------------------------
  270. #endif // __CARLA_BRIDGE_UTILS_HPP__