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.

429 lines
11KB

  1. /*
  2. * Carla Engine Bridge
  3. * Copyright (C) 2013 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. #ifdef BUILD_BRIDGE
  18. #include "CarlaEngineInternal.hpp"
  19. #include "CarlaBackendUtils.hpp"
  20. #include "CarlaMIDI.h"
  21. #include "CarlaBridgeUtils.hpp"
  22. #include "CarlaShmUtils.hpp"
  23. #include "jackbridge/JackBridge.hpp"
  24. #include <cerrno>
  25. #include <ctime>
  26. CARLA_BACKEND_START_NAMESPACE
  27. #if 0
  28. } // Fix editor indentation
  29. #endif
  30. // -------------------------------------------------------------------
  31. struct BridgeAudioPool {
  32. CarlaString filename;
  33. float* data;
  34. shm_t shm;
  35. BridgeAudioPool()
  36. : data(nullptr)
  37. {
  38. carla_shm_init(shm);
  39. }
  40. ~BridgeAudioPool()
  41. {
  42. // should be cleared by now
  43. CARLA_ASSERT(data == nullptr);
  44. clear();
  45. }
  46. bool attach()
  47. {
  48. #ifdef CARLA_OS_WIN
  49. // TESTING!
  50. shm = carla_shm_attach_linux((const char*)filename);
  51. #else
  52. shm = carla_shm_attach((const char*)filename);
  53. #endif
  54. return carla_is_shm_valid(shm);
  55. }
  56. void clear()
  57. {
  58. filename.clear();
  59. data = nullptr;
  60. if (carla_is_shm_valid(shm))
  61. carla_shm_close(shm);
  62. }
  63. };
  64. struct BridgeControl : public RingBufferControl {
  65. CarlaString filename;
  66. BridgeShmControl* data;
  67. shm_t shm;
  68. BridgeControl()
  69. : RingBufferControl(nullptr),
  70. data(nullptr)
  71. {
  72. carla_shm_init(shm);
  73. }
  74. ~BridgeControl()
  75. {
  76. // should be cleared by now
  77. CARLA_ASSERT(data == nullptr);
  78. clear();
  79. }
  80. bool attach()
  81. {
  82. #ifdef CARLA_OS_WIN
  83. // TESTING!
  84. shm = carla_shm_attach_linux((const char*)filename);
  85. #else
  86. shm = carla_shm_attach((const char*)filename);
  87. #endif
  88. return carla_is_shm_valid(shm);
  89. }
  90. void clear()
  91. {
  92. filename.clear();
  93. data = nullptr;
  94. if (carla_is_shm_valid(shm))
  95. carla_shm_close(shm);
  96. }
  97. bool mapData()
  98. {
  99. CARLA_ASSERT(data == nullptr);
  100. if (carla_shm_map<BridgeShmControl>(shm, data))
  101. {
  102. setRingBuffer(&data->ringBuffer, false);
  103. return true;
  104. }
  105. return false;
  106. }
  107. PluginBridgeOpcode readOpcode()
  108. {
  109. return static_cast<PluginBridgeOpcode>(readInt());
  110. }
  111. };
  112. // -------------------------------------------------------------------
  113. class CarlaEngineBridge : public CarlaEngine,
  114. public juce::Thread
  115. {
  116. public:
  117. CarlaEngineBridge(const char* const audioBaseName, const char* const controlBaseName)
  118. : CarlaEngine(),
  119. juce::Thread("CarlaEngineBridge"),
  120. fIsRunning(false)
  121. {
  122. carla_debug("CarlaEngineBridge::CarlaEngineBridge()");
  123. fShmAudioPool.filename = "/carla-bridge_shm_";
  124. fShmAudioPool.filename += audioBaseName;
  125. fShmControl.filename = "/carla-bridge_shc_";
  126. fShmControl.filename += controlBaseName;
  127. }
  128. ~CarlaEngineBridge() override
  129. {
  130. carla_debug("CarlaEngineBridge::~CarlaEngineBridge()");
  131. }
  132. // -------------------------------------
  133. // CarlaEngine virtual calls
  134. bool init(const char* const clientName) override
  135. {
  136. carla_debug("CarlaEngineBridge::init(\"%s\")", clientName);
  137. // SHM Audio Pool
  138. {
  139. if (! fShmAudioPool.attach())
  140. {
  141. carla_stdout("Failed to open or create shared memory file #1");
  142. return false;
  143. }
  144. }
  145. // SHM Control
  146. {
  147. if (! fShmControl.attach())
  148. {
  149. carla_stdout("Failed to open or create shared memory file #2");
  150. // clear
  151. fShmAudioPool.clear();
  152. return false;
  153. }
  154. if (! fShmControl.mapData())
  155. {
  156. carla_stdout("Failed to mmap shared memory file");
  157. // clear
  158. fShmControl.clear();
  159. fShmAudioPool.clear();
  160. return false;
  161. }
  162. }
  163. // Read values from memory
  164. PluginBridgeOpcode opcode;
  165. opcode = fShmControl.readOpcode();
  166. CARLA_ASSERT_INT(opcode == kPluginBridgeOpcodeSetBufferSize, opcode);
  167. fBufferSize = fShmControl.readInt();
  168. carla_stderr("BufferSize: %i", fBufferSize);
  169. opcode = fShmControl.readOpcode();
  170. CARLA_ASSERT_INT(opcode == kPluginBridgeOpcodeSetSampleRate, opcode);
  171. fSampleRate = fShmControl.readFloat();
  172. carla_stderr("SampleRate: %f", fSampleRate);
  173. fIsRunning = true;
  174. startThread(10);
  175. CarlaEngine::init(clientName);
  176. return true;
  177. }
  178. bool close() override
  179. {
  180. carla_debug("CarlaEnginePlugin::close()");
  181. CarlaEngine::close();
  182. stopThread(6000);
  183. fShmControl.clear();
  184. fShmAudioPool.clear();
  185. return true;
  186. }
  187. bool isRunning() const noexcept override
  188. {
  189. return fIsRunning;
  190. }
  191. bool isOffline() const noexcept override
  192. {
  193. return false;
  194. }
  195. EngineType getType() const noexcept override
  196. {
  197. return kEngineTypeBridge;
  198. }
  199. // -------------------------------------
  200. // CarlaThread virtual calls
  201. void run() override
  202. {
  203. // TODO - set RT permissions
  204. carla_debug("CarlaEngineBridge::run()");
  205. while (! threadShouldExit())
  206. {
  207. if (! jackbridge_sem_timedwait(&fShmControl.data->runServer, 5))
  208. {
  209. if (errno == ETIMEDOUT)
  210. {
  211. fIsRunning = false;
  212. signalThreadShouldExit();
  213. return;
  214. }
  215. }
  216. while (fShmControl.dataAvailable())
  217. {
  218. const PluginBridgeOpcode opcode(fShmControl.readOpcode());
  219. if (opcode != kPluginBridgeOpcodeProcess)
  220. carla_debug("CarlaEngineBridge::run() - got opcode: %s", PluginBridgeOpcode2str(opcode));
  221. switch (opcode)
  222. {
  223. case kPluginBridgeOpcodeNull:
  224. break;
  225. case kPluginBridgeOpcodeSetAudioPool:
  226. {
  227. const long poolSize(fShmControl.readLong());
  228. fShmAudioPool.data = (float*)carla_shm_map(fShmAudioPool.shm, poolSize);
  229. break;
  230. }
  231. case kPluginBridgeOpcodeSetBufferSize:
  232. {
  233. const int bufferSize(fShmControl.readInt());
  234. bufferSizeChanged(bufferSize);
  235. break;
  236. }
  237. case kPluginBridgeOpcodeSetSampleRate:
  238. {
  239. const float sampleRate(fShmControl.readFloat());
  240. sampleRateChanged(sampleRate);
  241. break;
  242. }
  243. case kPluginBridgeOpcodeSetParameter:
  244. {
  245. const int index(fShmControl.readInt());
  246. const float value(fShmControl.readFloat());
  247. CarlaPlugin* const plugin(getPluginUnchecked(0));
  248. if (plugin != nullptr && plugin->isEnabled())
  249. {
  250. //plugin->setParameterValueByRealIndex(index, value, false, false, false);
  251. //plugin->postponeRtEvent(kPluginPostRtEventParameterChange, index, 0, value);
  252. }
  253. break;
  254. }
  255. case kPluginBridgeOpcodeSetProgram:
  256. {
  257. const int index(fShmControl.readInt());
  258. CarlaPlugin* const plugin(getPluginUnchecked(0));
  259. if (plugin != nullptr && plugin->isEnabled())
  260. {
  261. //plugin->setProgram(index, false, false, false);
  262. //plugin->postponeRtEvent(kPluginPostRtEventProgramChange, index, 0, 0.0f);
  263. }
  264. break;
  265. }
  266. case kPluginBridgeOpcodeSetMidiProgram:
  267. {
  268. const int index(fShmControl.readInt());
  269. CarlaPlugin* const plugin(getPluginUnchecked(0));
  270. if (plugin != nullptr && plugin->isEnabled())
  271. {
  272. //plugin->setMidiProgram(index, false, false, false);
  273. //plugin->postponeRtEvent(kPluginPostRtEventMidiProgramChange, index, 0, 0.0f);
  274. }
  275. break;
  276. }
  277. case kPluginBridgeOpcodeMidiEvent:
  278. {
  279. uint8_t data[4] = { 0 };
  280. const long time(fShmControl.readLong());
  281. const int dataSize(fShmControl.readInt());
  282. CARLA_ASSERT_INT(dataSize >= 1 && dataSize <= 4, dataSize);
  283. for (int i=0; i < dataSize && i < 4; ++i)
  284. data[i] = fShmControl.readChar();
  285. CARLA_ASSERT(pData->bufEvents.in != nullptr);
  286. if (pData->bufEvents.in != nullptr)
  287. {
  288. // TODO
  289. }
  290. break;
  291. }
  292. case kPluginBridgeOpcodeProcess:
  293. {
  294. CARLA_ASSERT(fShmAudioPool.data != nullptr);
  295. CarlaPlugin* const plugin(getPluginUnchecked(0));
  296. if (plugin != nullptr && plugin->isEnabled() && plugin->tryLock())
  297. {
  298. const uint32_t inCount(plugin->getAudioInCount());
  299. const uint32_t outCount(plugin->getAudioOutCount());
  300. float* inBuffer[inCount];
  301. float* outBuffer[outCount];
  302. for (uint32_t i=0; i < inCount; ++i)
  303. inBuffer[i] = fShmAudioPool.data + i*fBufferSize;
  304. for (uint32_t i=0; i < outCount; ++i)
  305. outBuffer[i] = fShmAudioPool.data + (i+inCount)*fBufferSize;
  306. plugin->initBuffers();
  307. plugin->process(inBuffer, outBuffer, fBufferSize);
  308. plugin->unlock();
  309. }
  310. break;
  311. }
  312. case kPluginBridgeOpcodeQuit:
  313. signalThreadShouldExit();
  314. break;
  315. }
  316. }
  317. if (jackbridge_sem_post(&fShmControl.data->runClient) != 0)
  318. pass(); //carla_stderr2("Could not post to semaphore");
  319. }
  320. fIsRunning = false;
  321. }
  322. private:
  323. BridgeAudioPool fShmAudioPool;
  324. BridgeControl fShmControl;
  325. volatile bool fIsRunning;
  326. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineBridge)
  327. };
  328. // -----------------------------------------
  329. CarlaEngine* CarlaEngine::newBridge(const char* const audioBaseName, const char* const controlBaseName)
  330. {
  331. return new CarlaEngineBridge(audioBaseName, controlBaseName);
  332. }
  333. CARLA_BACKEND_END_NAMESPACE
  334. #endif // BUILD_BRIDGE