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.

594 lines
17KB

  1. /*
  2. * Carla Plugin Host
  3. * Copyright (C) 2011-2014 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 BUILD_BRIDGE
  18. # error This file should not be compiled if not building bridge
  19. #endif
  20. #include "CarlaEngineInternal.hpp"
  21. #include "CarlaPlugin.hpp"
  22. #include "CarlaBackendUtils.hpp"
  23. #include "CarlaBridgeUtils.hpp"
  24. #include "CarlaMIDI.h"
  25. #include "jackbridge/JackBridge.hpp"
  26. #include <cerrno>
  27. #include <ctime>
  28. #ifdef JACKBRIDGE_EXPORT
  29. // -------------------------------------------------------------------
  30. bool jackbridge_is_ok() noexcept
  31. {
  32. return true;
  33. }
  34. #endif
  35. // -------------------------------------------------------------------
  36. CARLA_BACKEND_START_NAMESPACE
  37. #if 0
  38. } // Fix editor indentation
  39. #endif
  40. // -------------------------------------------------------------------
  41. template<typename T>
  42. bool jackbridge_shm_map2(char* shm, T*& value)
  43. {
  44. value = (T*)jackbridge_shm_map(shm, sizeof(T));
  45. return (value != nullptr);
  46. }
  47. struct BridgeAudioPool {
  48. CarlaString filename;
  49. float* data;
  50. char shm[32];
  51. BridgeAudioPool()
  52. : data(nullptr)
  53. {
  54. carla_zeroChar(shm, 32);
  55. jackbridge_shm_init(shm);
  56. }
  57. ~BridgeAudioPool()
  58. {
  59. // should be cleared by now
  60. CARLA_ASSERT(data == nullptr);
  61. clear();
  62. }
  63. bool attach()
  64. {
  65. jackbridge_shm_attach(shm, filename);
  66. return jackbridge_shm_is_valid(shm);
  67. }
  68. void clear()
  69. {
  70. filename.clear();
  71. data = nullptr;
  72. if (jackbridge_shm_is_valid(shm))
  73. jackbridge_shm_close(shm);
  74. }
  75. CARLA_DECLARE_NON_COPY_STRUCT(BridgeAudioPool)
  76. };
  77. struct BridgeControl : public RingBufferControl<StackRingBuffer> {
  78. CarlaString filename;
  79. BridgeShmControl* data;
  80. char shm[32];
  81. BridgeControl()
  82. : RingBufferControl(nullptr),
  83. data(nullptr)
  84. {
  85. carla_zeroChar(shm, 32);
  86. jackbridge_shm_init(shm);
  87. }
  88. ~BridgeControl()
  89. {
  90. // should be cleared by now
  91. CARLA_ASSERT(data == nullptr);
  92. clear();
  93. }
  94. bool attach()
  95. {
  96. jackbridge_shm_attach(shm, filename);
  97. return jackbridge_shm_is_valid(shm);
  98. }
  99. void clear()
  100. {
  101. filename.clear();
  102. data = nullptr;
  103. if (jackbridge_shm_is_valid(shm))
  104. jackbridge_shm_close(shm);
  105. }
  106. bool mapData()
  107. {
  108. CARLA_ASSERT(data == nullptr);
  109. if (jackbridge_shm_map2<BridgeShmControl>(shm, data))
  110. {
  111. setRingBuffer(&data->ringBuffer, false);
  112. return true;
  113. }
  114. return false;
  115. }
  116. PluginBridgeOpcode readOpcode()
  117. {
  118. return static_cast<PluginBridgeOpcode>(readInt());
  119. }
  120. CARLA_DECLARE_NON_COPY_STRUCT(BridgeControl)
  121. };
  122. struct BridgeTime {
  123. CarlaString filename;
  124. BridgeTimeInfo* info;
  125. char shm[32];
  126. BridgeTime()
  127. : info(nullptr)
  128. {
  129. carla_zeroChar(shm, 32);
  130. jackbridge_shm_init(shm);
  131. }
  132. ~BridgeTime()
  133. {
  134. // should be cleared by now
  135. CARLA_ASSERT(info == nullptr);
  136. clear();
  137. }
  138. bool attach()
  139. {
  140. jackbridge_shm_attach(shm, filename);
  141. return jackbridge_shm_is_valid(shm);
  142. }
  143. void clear()
  144. {
  145. filename.clear();
  146. info = nullptr;
  147. if (jackbridge_shm_is_valid(shm))
  148. jackbridge_shm_close(shm);
  149. }
  150. bool mapData()
  151. {
  152. CARLA_ASSERT(info == nullptr);
  153. return jackbridge_shm_map2<BridgeTimeInfo>(shm, info);
  154. }
  155. CARLA_DECLARE_NON_COPY_STRUCT(BridgeTime)
  156. };
  157. // -------------------------------------------------------------------
  158. class CarlaEngineBridge : public CarlaEngine,
  159. public CarlaThread
  160. {
  161. public:
  162. CarlaEngineBridge(const char* const audioBaseName, const char* const controlBaseName, const char* const timeBaseName)
  163. : CarlaEngine(),
  164. CarlaThread("CarlaEngineBridge"),
  165. fIsRunning(false)
  166. {
  167. carla_debug("CarlaEngineBridge::CarlaEngineBridge()");
  168. fShmAudioPool.filename = "/carla-bridge_shm_";
  169. fShmAudioPool.filename += audioBaseName;
  170. fShmControl.filename = "/carla-bridge_shc_";
  171. fShmControl.filename += controlBaseName;
  172. fShmTime.filename = "/carla-bridge_sht_";
  173. fShmTime.filename += timeBaseName;
  174. }
  175. ~CarlaEngineBridge() noexcept override
  176. {
  177. carla_debug("CarlaEngineBridge::~CarlaEngineBridge()");
  178. }
  179. // -------------------------------------
  180. // CarlaEngine virtual calls
  181. bool init(const char* const clientName) override
  182. {
  183. carla_debug("CarlaEngineBridge::init(\"%s\")", clientName);
  184. // SHM Audio Pool
  185. {
  186. if (! fShmAudioPool.attach())
  187. {
  188. carla_stdout("Failed to open or create shared memory file #1");
  189. return false;
  190. }
  191. }
  192. // SHM Control
  193. {
  194. if (! fShmControl.attach())
  195. {
  196. carla_stdout("Failed to open or create shared memory file #2");
  197. // clear
  198. fShmAudioPool.clear();
  199. return false;
  200. }
  201. if (! fShmControl.mapData())
  202. {
  203. carla_stdout("Failed to map shared memory file #2");
  204. // clear
  205. fShmControl.clear();
  206. fShmAudioPool.clear();
  207. return false;
  208. }
  209. }
  210. // SHM Transport
  211. {
  212. if (! fShmTime.attach())
  213. {
  214. carla_stdout("Failed to open or create shared memory file #3");
  215. // clear
  216. fShmControl.clear();
  217. fShmAudioPool.clear();
  218. return false;
  219. }
  220. if (! fShmTime.mapData())
  221. {
  222. carla_stdout("Failed to map shared memory file #3");
  223. // clear
  224. fShmTime.clear();
  225. fShmControl.clear();
  226. fShmAudioPool.clear();
  227. return false;
  228. }
  229. }
  230. // Read values from memory
  231. PluginBridgeOpcode opcode;
  232. opcode = fShmControl.readOpcode();
  233. CARLA_SAFE_ASSERT_INT(opcode == kPluginBridgeOpcodeNull, opcode);
  234. const uint32_t structSize = fShmControl.readUInt();
  235. CARLA_SAFE_ASSERT_INT2(structSize == sizeof(BridgeShmControl), structSize, sizeof(BridgeShmControl));
  236. carla_stderr("Struct Size: %i", structSize);
  237. opcode = fShmControl.readOpcode();
  238. CARLA_SAFE_ASSERT_INT(opcode == kPluginBridgeOpcodeSetBufferSize, opcode);
  239. pData->bufferSize = fShmControl.readUInt();
  240. carla_stderr("BufferSize: %i", pData->bufferSize);
  241. opcode = fShmControl.readOpcode();
  242. CARLA_SAFE_ASSERT_INT(opcode == kPluginBridgeOpcodeSetSampleRate, opcode);
  243. pData->sampleRate = fShmControl.readFloat();
  244. carla_stderr("SampleRate: %f", pData->sampleRate);
  245. CarlaThread::startThread();
  246. CarlaEngine::init(clientName);
  247. return true;
  248. }
  249. bool close() override
  250. {
  251. carla_debug("CarlaEnginePlugin::close()");
  252. CarlaEngine::close();
  253. CarlaThread::stopThread(6000);
  254. fShmTime.clear();
  255. fShmControl.clear();
  256. fShmAudioPool.clear();
  257. return true;
  258. }
  259. bool isRunning() const noexcept override
  260. {
  261. return fIsRunning;
  262. }
  263. bool isOffline() const noexcept override
  264. {
  265. return false;
  266. }
  267. EngineType getType() const noexcept override
  268. {
  269. return kEngineTypeBridge;
  270. }
  271. const char* getCurrentDriverName() const noexcept
  272. {
  273. return "Bridge";
  274. }
  275. // -------------------------------------
  276. // CarlaThread virtual calls
  277. void run() override
  278. {
  279. fIsRunning = true;
  280. // TODO - set RT permissions
  281. carla_debug("CarlaEngineBridge::run()");
  282. for (; ! shouldThreadExit();)
  283. {
  284. if (! jackbridge_sem_timedwait(&fShmControl.data->runServer, 5))
  285. {
  286. if (errno == ETIMEDOUT)
  287. {
  288. fIsRunning = false;
  289. signalThreadShouldExit();
  290. return;
  291. }
  292. }
  293. for (; fShmControl.isDataAvailable();)
  294. {
  295. const PluginBridgeOpcode opcode(fShmControl.readOpcode());
  296. if (opcode != kPluginBridgeOpcodeProcess) {
  297. carla_debug("CarlaEngineBridge::run() - got opcode: %s", PluginBridgeOpcode2str(opcode));
  298. }
  299. switch (opcode)
  300. {
  301. case kPluginBridgeOpcodeNull:
  302. break;
  303. case kPluginBridgeOpcodeSetAudioPool: {
  304. const int64_t poolSize(fShmControl.readLong());
  305. CARLA_SAFE_ASSERT_BREAK(poolSize > 0);
  306. fShmAudioPool.data = (float*)jackbridge_shm_map(fShmAudioPool.shm, static_cast<size_t>(poolSize));
  307. break;
  308. }
  309. case kPluginBridgeOpcodeSetBufferSize: {
  310. const uint32_t bufferSize(fShmControl.readUInt());
  311. bufferSizeChanged(bufferSize);
  312. break;
  313. }
  314. case kPluginBridgeOpcodeSetSampleRate: {
  315. const float sampleRate(fShmControl.readFloat());
  316. sampleRateChanged(sampleRate);
  317. break;
  318. }
  319. case kPluginBridgeOpcodeSetParameter: {
  320. const int32_t index(fShmControl.readInt());
  321. const float value(fShmControl.readFloat());
  322. CarlaPlugin* const plugin(getPluginUnchecked(0));
  323. if (plugin != nullptr && plugin->isEnabled())
  324. {
  325. plugin->setParameterValueByRealIndex(index, value, false, false, false);
  326. //if (index >= 0)
  327. // plugin->postponeRtEvent(kPluginPostRtEventParameterChange, index, 0, value);
  328. }
  329. break;
  330. }
  331. case kPluginBridgeOpcodeSetProgram: {
  332. const int32_t index(fShmControl.readInt());
  333. CARLA_SAFE_ASSERT_BREAK(index >= 0);
  334. CarlaPlugin* const plugin(getPluginUnchecked(0));
  335. if (plugin != nullptr && plugin->isEnabled())
  336. {
  337. plugin->setProgram(index, false, false, false);
  338. //plugin->postponeRtEvent(kPluginPostRtEventProgramChange, index, 0, 0.0f);
  339. }
  340. break;
  341. }
  342. case kPluginBridgeOpcodeSetMidiProgram: {
  343. const int32_t index(fShmControl.readInt());
  344. CARLA_SAFE_ASSERT_BREAK(index >= 0);
  345. CarlaPlugin* const plugin(getPluginUnchecked(0));
  346. if (plugin != nullptr && plugin->isEnabled())
  347. {
  348. plugin->setMidiProgram(index, false, false, false);
  349. //plugin->postponeRtEvent(kPluginPostRtEventMidiProgramChange, index, 0, 0.0f);
  350. }
  351. break;
  352. }
  353. case kPluginBridgeOpcodeMidiEvent: {
  354. const int64_t time(fShmControl.readLong());
  355. const int32_t size(fShmControl.readInt());
  356. CARLA_SAFE_ASSERT_BREAK(time >= 0);
  357. CARLA_SAFE_ASSERT_BREAK(size > 0 && size <= 4);
  358. uint8_t data[size];
  359. for (int32_t i=0; i < size; ++i)
  360. data[i] = static_cast<uint8_t>(fShmControl.readChar());
  361. CARLA_SAFE_ASSERT_BREAK(pData->events.in != nullptr);
  362. for (ushort i=0; i < kMaxEngineEventInternalCount; ++i)
  363. {
  364. EngineEvent& event(pData->events.in[i]);
  365. if (event.type != kEngineEventTypeNull)
  366. continue;
  367. event.fillFromMidiData(static_cast<uint8_t>(size), data);
  368. break;
  369. }
  370. break;
  371. }
  372. case kPluginBridgeOpcodeProcess: {
  373. CARLA_SAFE_ASSERT_BREAK(fShmAudioPool.data != nullptr);
  374. CarlaPlugin* const plugin(getPluginUnchecked(0));
  375. BridgeTimeInfo* const bridgeInfo(fShmTime.info);
  376. CARLA_SAFE_ASSERT_BREAK(bridgeInfo != nullptr);
  377. if (plugin != nullptr && plugin->isEnabled() && plugin->tryLock(true)) // FIXME - always lock?
  378. {
  379. const uint32_t inCount(plugin->getAudioInCount());
  380. const uint32_t outCount(plugin->getAudioOutCount());
  381. float* inBuffer[inCount];
  382. float* outBuffer[outCount];
  383. for (uint32_t i=0; i < inCount; ++i)
  384. inBuffer[i] = fShmAudioPool.data + i*pData->bufferSize;
  385. for (uint32_t i=0; i < outCount; ++i)
  386. outBuffer[i] = fShmAudioPool.data + (i+inCount)*pData->bufferSize;
  387. EngineTimeInfo& timeInfo(pData->timeInfo);
  388. timeInfo.playing = bridgeInfo->playing;
  389. timeInfo.frame = bridgeInfo->frame;
  390. timeInfo.usecs = bridgeInfo->usecs;
  391. timeInfo.valid = bridgeInfo->valid;
  392. if (timeInfo.valid & EngineTimeInfo::kValidBBT)
  393. {
  394. timeInfo.bbt.bar = bridgeInfo->bar;
  395. timeInfo.bbt.beat = bridgeInfo->beat;
  396. timeInfo.bbt.tick = bridgeInfo->tick;
  397. timeInfo.bbt.beatsPerBar = bridgeInfo->beatsPerBar;
  398. timeInfo.bbt.beatType = bridgeInfo->beatType;
  399. timeInfo.bbt.ticksPerBeat = bridgeInfo->ticksPerBeat;
  400. timeInfo.bbt.beatsPerMinute = bridgeInfo->beatsPerMinute;
  401. timeInfo.bbt.barStartTick = bridgeInfo->barStartTick;
  402. }
  403. plugin->initBuffers();
  404. plugin->process(inBuffer, outBuffer, pData->bufferSize);
  405. plugin->unlock();
  406. }
  407. // clear buffer
  408. CARLA_SAFE_ASSERT_BREAK(pData->events.in != nullptr);
  409. if (pData->events.in[0].type != kEngineEventTypeNull)
  410. carla_zeroStruct<EngineEvent>(pData->events.in, kMaxEngineEventInternalCount);
  411. break;
  412. }
  413. case kPluginBridgeOpcodeQuit:
  414. signalThreadShouldExit();
  415. fIsRunning = false;
  416. break;
  417. }
  418. }
  419. if (! jackbridge_sem_post(&fShmControl.data->runClient))
  420. carla_stderr2("Could not post to semaphore");
  421. }
  422. fIsRunning = false;
  423. }
  424. private:
  425. BridgeAudioPool fShmAudioPool;
  426. BridgeControl fShmControl;
  427. BridgeTime fShmTime;
  428. volatile bool fIsRunning;
  429. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineBridge)
  430. };
  431. // -----------------------------------------
  432. CarlaEngine* CarlaEngine::newBridge(const char* const audioBaseName, const char* const controlBaseName, const char* const timeBaseName)
  433. {
  434. return new CarlaEngineBridge(audioBaseName, controlBaseName, timeBaseName);
  435. }
  436. CARLA_BACKEND_END_NAMESPACE
  437. // -----------------------------------------------------------------------
  438. // Extra stuff for linking purposes
  439. CARLA_BACKEND_START_NAMESPACE
  440. // CarlaEngine* CarlaEngine::newRtAudio(const AudioApi) { return nullptr; }
  441. // unsigned int CarlaEngine::getRtAudioApiCount() { return 0; }
  442. // const char* CarlaEngine::getRtAudioApiName(const unsigned int) { return nullptr; }
  443. // const char* const* CarlaEngine::getRtAudioApiDeviceNames(const unsigned int) { return nullptr; }
  444. // const EngineDriverDeviceInfo* CarlaEngine::getRtAudioDeviceInfo(const unsigned int, const char* const) { return nullptr; }
  445. //
  446. // #ifdef HAVE_JUCE
  447. // CarlaEngine* CarlaEngine::newJuce(const AudioApi) { return nullptr; }
  448. // unsigned int CarlaEngine::getJuceApiCount() { return 0; }
  449. // const char* CarlaEngine::getJuceApiName(const unsigned int) { return nullptr; }
  450. // const char* const* CarlaEngine::getJuceApiDeviceNames(const unsigned int) { return nullptr; }
  451. // const EngineDriverDeviceInfo* CarlaEngine::getJuceDeviceInfo(const unsigned int, const char* const) { return nullptr; }
  452. // #endif
  453. CARLA_BACKEND_END_NAMESPACE
  454. // -----------------------------------------------------------------------
  455. #if defined(CARLA_OS_WIN) && ! defined(__WINE__)
  456. extern "C" __declspec (dllexport)
  457. #else
  458. extern "C" __attribute__ ((visibility("default")))
  459. #endif
  460. void carla_register_native_plugin_carla();
  461. void carla_register_native_plugin_carla(){}
  462. // -----------------------------------------------------------------------