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.

685 lines
21KB

  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. using juce::File;
  29. using juce::String;
  30. #ifdef JACKBRIDGE_EXPORT
  31. // -------------------------------------------------------------------
  32. bool jackbridge_is_ok() noexcept
  33. {
  34. return true;
  35. }
  36. #endif
  37. // -------------------------------------------------------------------
  38. CARLA_BACKEND_START_NAMESPACE
  39. // -------------------------------------------------------------------
  40. template<typename T>
  41. bool jackbridge_shm_map2(char* shm, T*& value)
  42. {
  43. value = (T*)jackbridge_shm_map(shm, sizeof(T));
  44. return (value != nullptr);
  45. }
  46. struct BridgeAudioPool {
  47. CarlaString filename;
  48. float* data;
  49. char shm[32];
  50. BridgeAudioPool()
  51. : data(nullptr)
  52. {
  53. carla_zeroChar(shm, 32);
  54. jackbridge_shm_init(shm);
  55. }
  56. ~BridgeAudioPool()
  57. {
  58. // should be cleared by now
  59. CARLA_ASSERT(data == nullptr);
  60. clear();
  61. }
  62. bool attach()
  63. {
  64. jackbridge_shm_attach(shm, filename);
  65. return jackbridge_shm_is_valid(shm);
  66. }
  67. void clear()
  68. {
  69. filename.clear();
  70. data = nullptr;
  71. if (jackbridge_shm_is_valid(shm))
  72. jackbridge_shm_close(shm);
  73. }
  74. CARLA_DECLARE_NON_COPY_STRUCT(BridgeAudioPool)
  75. };
  76. struct BridgeControl : public CarlaRingBuffer<StackBuffer> {
  77. CarlaString filename;
  78. BridgeShmControl* data;
  79. char shm[32];
  80. BridgeControl()
  81. : CarlaRingBuffer<StackBuffer>(),
  82. data(nullptr)
  83. {
  84. carla_zeroChar(shm, 32);
  85. jackbridge_shm_init(shm);
  86. }
  87. ~BridgeControl()
  88. {
  89. // should be cleared by now
  90. CARLA_ASSERT(data == nullptr);
  91. clear();
  92. }
  93. bool attach()
  94. {
  95. jackbridge_shm_attach(shm, filename);
  96. return jackbridge_shm_is_valid(shm);
  97. }
  98. void clear()
  99. {
  100. filename.clear();
  101. data = nullptr;
  102. if (jackbridge_shm_is_valid(shm))
  103. jackbridge_shm_close(shm);
  104. }
  105. bool mapData()
  106. {
  107. CARLA_ASSERT(data == nullptr);
  108. if (jackbridge_shm_map2<BridgeShmControl>(shm, data))
  109. {
  110. setRingBuffer(&data->buffer, false);
  111. return true;
  112. }
  113. return false;
  114. }
  115. PluginBridgeOpcode readOpcode()
  116. {
  117. return static_cast<PluginBridgeOpcode>(readInt());
  118. }
  119. CARLA_DECLARE_NON_COPY_STRUCT(BridgeControl)
  120. };
  121. struct BridgeTime {
  122. CarlaString filename;
  123. BridgeTimeInfo* info;
  124. char shm[32];
  125. BridgeTime()
  126. : info(nullptr)
  127. {
  128. carla_zeroChar(shm, 32);
  129. jackbridge_shm_init(shm);
  130. }
  131. ~BridgeTime()
  132. {
  133. // should be cleared by now
  134. CARLA_ASSERT(info == nullptr);
  135. clear();
  136. }
  137. bool attach()
  138. {
  139. jackbridge_shm_attach(shm, filename);
  140. return jackbridge_shm_is_valid(shm);
  141. }
  142. void clear()
  143. {
  144. filename.clear();
  145. info = nullptr;
  146. if (jackbridge_shm_is_valid(shm))
  147. jackbridge_shm_close(shm);
  148. }
  149. bool mapData()
  150. {
  151. CARLA_ASSERT(info == nullptr);
  152. return jackbridge_shm_map2<BridgeTimeInfo>(shm, info);
  153. }
  154. CARLA_DECLARE_NON_COPY_STRUCT(BridgeTime)
  155. };
  156. // -------------------------------------------------------------------
  157. class CarlaEngineBridge : public CarlaEngine,
  158. public CarlaThread
  159. {
  160. public:
  161. CarlaEngineBridge(const char* const audioBaseName, const char* const controlBaseName, const char* const timeBaseName)
  162. : CarlaEngine(),
  163. CarlaThread("CarlaEngineBridge"),
  164. fIsRunning(false),
  165. fNextUIState(-1)
  166. {
  167. carla_stdout("CarlaEngineBridge::CarlaEngineBridge(%s, %s, %s)", audioBaseName, controlBaseName, timeBaseName);
  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 stackBufferSize = fShmControl.readUInt();
  235. CARLA_SAFE_ASSERT_INT2(stackBufferSize == sizeof(StackBuffer), stackBufferSize, sizeof(StackBuffer));
  236. const uint32_t shmStructSize = fShmControl.readUInt();
  237. CARLA_SAFE_ASSERT_INT2(shmStructSize == sizeof(BridgeShmControl), shmStructSize, sizeof(BridgeShmControl));
  238. const uint32_t timeStructSize = fShmControl.readUInt();
  239. CARLA_SAFE_ASSERT_INT2(timeStructSize == sizeof(BridgeTimeInfo), timeStructSize, sizeof(BridgeTimeInfo));
  240. opcode = fShmControl.readOpcode();
  241. CARLA_SAFE_ASSERT_INT(opcode == kPluginBridgeOpcodeSetBufferSize, opcode);
  242. pData->bufferSize = fShmControl.readUInt();
  243. opcode = fShmControl.readOpcode();
  244. CARLA_SAFE_ASSERT_INT(opcode == kPluginBridgeOpcodeSetSampleRate, opcode);
  245. pData->sampleRate = fShmControl.readFloat();
  246. carla_stdout("Carla Client Info:");
  247. carla_stdout(" BufferSize: %i", pData->bufferSize);
  248. carla_stdout(" SampleRate: %f", pData->sampleRate);
  249. carla_stdout(" sizeof(StackBuffer): %i/" P_SIZE, stackBufferSize, sizeof(StackBuffer));
  250. carla_stdout(" sizeof(BridgeShmControl): %i/" P_SIZE, shmStructSize, sizeof(BridgeShmControl));
  251. carla_stdout(" sizeof(BridgeTimeInfo): %i/" P_SIZE, timeStructSize, sizeof(BridgeTimeInfo));
  252. CarlaThread::startThread();
  253. CarlaEngine::init(clientName);
  254. return true;
  255. }
  256. bool close() override
  257. {
  258. carla_debug("CarlaEnginePlugin::close()");
  259. CarlaEngine::close();
  260. CarlaThread::stopThread(6000);
  261. fShmTime.clear();
  262. fShmControl.clear();
  263. fShmAudioPool.clear();
  264. return true;
  265. }
  266. bool isRunning() const noexcept override
  267. {
  268. return fIsRunning;
  269. }
  270. bool isOffline() const noexcept override
  271. {
  272. return false;
  273. }
  274. EngineType getType() const noexcept override
  275. {
  276. return kEngineTypeBridge;
  277. }
  278. const char* getCurrentDriverName() const noexcept
  279. {
  280. return "Bridge";
  281. }
  282. void idle() noexcept override
  283. {
  284. CarlaEngine::idle();
  285. if (fNextUIState == -1 || ! fIsRunning)
  286. return;
  287. try {
  288. carla_show_custom_ui(0, bool(fNextUIState));
  289. } CARLA_SAFE_EXCEPTION("bridge show_custom_ui");
  290. fNextUIState = -1;
  291. }
  292. // -------------------------------------
  293. // CarlaThread virtual calls
  294. void run() override
  295. {
  296. fIsRunning = true;
  297. // TODO - set RT permissions
  298. carla_debug("CarlaEngineBridge::run()");
  299. for (; ! shouldThreadExit();)
  300. {
  301. if (! jackbridge_sem_timedwait(&fShmControl.data->runServer, 5))
  302. {
  303. if (errno == ETIMEDOUT)
  304. {
  305. fIsRunning = false;
  306. signalThreadShouldExit();
  307. return;
  308. }
  309. }
  310. for (; fShmControl.isDataAvailableForReading();)
  311. {
  312. const PluginBridgeOpcode opcode(fShmControl.readOpcode());
  313. if (opcode != kPluginBridgeOpcodeProcess) {
  314. carla_debug("CarlaEngineBridge::run() - got opcode: %s", PluginBridgeOpcode2str(opcode));
  315. }
  316. switch (opcode)
  317. {
  318. case kPluginBridgeOpcodeNull:
  319. break;
  320. case kPluginBridgeOpcodeSetAudioPool: {
  321. const int64_t poolSize(fShmControl.readLong());
  322. CARLA_SAFE_ASSERT_BREAK(poolSize > 0);
  323. fShmAudioPool.data = (float*)jackbridge_shm_map(fShmAudioPool.shm, static_cast<size_t>(poolSize));
  324. break;
  325. }
  326. case kPluginBridgeOpcodeSetBufferSize: {
  327. const uint32_t bufferSize(fShmControl.readUInt());
  328. bufferSizeChanged(bufferSize);
  329. break;
  330. }
  331. case kPluginBridgeOpcodeSetSampleRate: {
  332. const float sampleRate(fShmControl.readFloat());
  333. sampleRateChanged(sampleRate);
  334. break;
  335. }
  336. case kPluginBridgeOpcodeSetParameterRt:
  337. case kPluginBridgeOpcodeSetParameterNonRt:{
  338. const int32_t index(fShmControl.readInt());
  339. const float value(fShmControl.readFloat());
  340. CarlaPlugin* const plugin(getPluginUnchecked(0));
  341. if (plugin != nullptr && plugin->isEnabled())
  342. {
  343. if (index == PARAMETER_ACTIVE)
  344. {
  345. plugin->setActive((value > 0.0f), false, false);
  346. break;
  347. }
  348. CARLA_SAFE_ASSERT_BREAK(index >= 0);
  349. plugin->setParameterValue(static_cast<uint32_t>(index), value, (opcode == kPluginBridgeOpcodeSetParameterNonRt), false, false);
  350. }
  351. break;
  352. }
  353. case kPluginBridgeOpcodeSetProgram: {
  354. const int32_t index(fShmControl.readInt());
  355. CARLA_SAFE_ASSERT_BREAK(index >= 0);
  356. CarlaPlugin* const plugin(getPluginUnchecked(0));
  357. if (plugin != nullptr && plugin->isEnabled())
  358. {
  359. plugin->setProgram(index, false, false, false);
  360. //plugin->postponeRtEvent(kPluginPostRtEventProgramChange, index, 0, 0.0f);
  361. }
  362. break;
  363. }
  364. case kPluginBridgeOpcodeSetMidiProgram: {
  365. const int32_t index(fShmControl.readInt());
  366. CARLA_SAFE_ASSERT_BREAK(index >= 0);
  367. CarlaPlugin* const plugin(getPluginUnchecked(0));
  368. if (plugin != nullptr && plugin->isEnabled())
  369. {
  370. plugin->setMidiProgram(index, false, false, false);
  371. //plugin->postponeRtEvent(kPluginPostRtEventMidiProgramChange, index, 0, 0.0f);
  372. }
  373. break;
  374. }
  375. case kPluginBridgeOpcodeSetChunkFile: {
  376. const uint32_t size(fShmControl.readUInt());
  377. CARLA_SAFE_ASSERT_BREAK(size > 0);
  378. char chunkFilePathTry[size+1];
  379. carla_zeroChar(chunkFilePathTry, size+1);
  380. fShmControl.readCustomData(chunkFilePathTry, size);
  381. CARLA_SAFE_ASSERT_BREAK(chunkFilePathTry[0] != '\0');
  382. String chunkFilePath(chunkFilePathTry);
  383. #ifdef CARLA_OS_WIN
  384. if (chunkFilePath.startsWith("/"))
  385. {
  386. // running under Wine, posix host
  387. chunkFilePath = chunkFilePath.replaceSection(0, 1, "Z:\\");
  388. chunkFilePath = chunkFilePath.replace("/", "\\");
  389. }
  390. #endif
  391. File chunkFile(chunkFilePath);
  392. CARLA_SAFE_ASSERT_BREAK(chunkFile.existsAsFile());
  393. String chunkData(chunkFile.loadFileAsString());
  394. chunkFile.deleteFile();
  395. CARLA_SAFE_ASSERT_BREAK(chunkData.isNotEmpty());
  396. carla_set_chunk_data(0, chunkData.toRawUTF8());
  397. carla_stdout("chunk sent, size:%i", chunkData.length());
  398. break;
  399. }
  400. case kPluginBridgeOpcodePrepareForSave: {
  401. carla_prepare_for_save(0);
  402. for (uint32_t i=0, count=carla_get_custom_data_count(0); i<count; ++i)
  403. {
  404. const CarlaBackend::CustomData* const cdata(carla_get_custom_data(0, i));
  405. CARLA_SAFE_ASSERT_CONTINUE(cdata != nullptr);
  406. oscSend_bridge_set_custom_data(cdata->type, cdata->key, cdata->value);
  407. }
  408. //if (fPlugin->getOptionsEnabled() & CarlaBackend::PLUGIN_OPTION_USE_CHUNKS)
  409. {
  410. if (const char* const chunkData = carla_get_chunk_data(0))
  411. {
  412. String filePath(File::getSpecialLocation(File::tempDirectory).getFullPathName());
  413. filePath += OS_SEP_STR;
  414. filePath += ".CarlaChunk_";
  415. filePath += fShmAudioPool.filename.buffer() + 18;
  416. if (File(filePath).replaceWithText(chunkData))
  417. oscSend_bridge_set_chunk_data(filePath.toRawUTF8());
  418. }
  419. }
  420. carla_stdout("-----------------------------------------------------, got prepare for save");
  421. oscSend_bridge_configure(CARLA_BRIDGE_MSG_SAVED, "");
  422. break;
  423. }
  424. case kPluginBridgeOpcodeMidiEvent: {
  425. const int64_t time(fShmControl.readLong());
  426. const int32_t size(fShmControl.readInt());
  427. CARLA_SAFE_ASSERT_BREAK(time >= 0);
  428. CARLA_SAFE_ASSERT_BREAK(size > 0 && size <= 4);
  429. uint8_t data[size];
  430. for (int32_t i=0; i < size; ++i)
  431. data[i] = fShmControl.readByte();
  432. CARLA_SAFE_ASSERT_BREAK(pData->events.in != nullptr);
  433. for (ushort i=0; i < kMaxEngineEventInternalCount; ++i)
  434. {
  435. EngineEvent& event(pData->events.in[i]);
  436. if (event.type != kEngineEventTypeNull)
  437. continue;
  438. event.fillFromMidiData(static_cast<uint8_t>(size), data);
  439. break;
  440. }
  441. break;
  442. }
  443. case kPluginBridgeOpcodeProcess: {
  444. CARLA_SAFE_ASSERT_BREAK(fShmAudioPool.data != nullptr);
  445. CarlaPlugin* const plugin(getPluginUnchecked(0));
  446. BridgeTimeInfo* const bridgeInfo(fShmTime.info);
  447. CARLA_SAFE_ASSERT_BREAK(bridgeInfo != nullptr);
  448. if (plugin != nullptr && plugin->isEnabled() && plugin->tryLock(true)) // FIXME - always lock?
  449. {
  450. const uint32_t inCount(plugin->getAudioInCount());
  451. const uint32_t outCount(plugin->getAudioOutCount());
  452. float* inBuffer[inCount];
  453. float* outBuffer[outCount];
  454. for (uint32_t i=0; i < inCount; ++i)
  455. inBuffer[i] = fShmAudioPool.data + i*pData->bufferSize;
  456. for (uint32_t i=0; i < outCount; ++i)
  457. outBuffer[i] = fShmAudioPool.data + (i+inCount)*pData->bufferSize;
  458. EngineTimeInfo& timeInfo(pData->timeInfo);
  459. timeInfo.playing = bridgeInfo->playing;
  460. timeInfo.frame = bridgeInfo->frame;
  461. timeInfo.usecs = bridgeInfo->usecs;
  462. timeInfo.valid = bridgeInfo->valid;
  463. if (timeInfo.valid & EngineTimeInfo::kValidBBT)
  464. {
  465. timeInfo.bbt.bar = bridgeInfo->bar;
  466. timeInfo.bbt.beat = bridgeInfo->beat;
  467. timeInfo.bbt.tick = bridgeInfo->tick;
  468. timeInfo.bbt.beatsPerBar = bridgeInfo->beatsPerBar;
  469. timeInfo.bbt.beatType = bridgeInfo->beatType;
  470. timeInfo.bbt.ticksPerBeat = bridgeInfo->ticksPerBeat;
  471. timeInfo.bbt.beatsPerMinute = bridgeInfo->beatsPerMinute;
  472. timeInfo.bbt.barStartTick = bridgeInfo->barStartTick;
  473. }
  474. plugin->initBuffers();
  475. plugin->process(inBuffer, outBuffer, pData->bufferSize);
  476. plugin->unlock();
  477. }
  478. // clear buffer
  479. CARLA_SAFE_ASSERT_BREAK(pData->events.in != nullptr);
  480. if (pData->events.in[0].type != kEngineEventTypeNull)
  481. carla_zeroStruct<EngineEvent>(pData->events.in, kMaxEngineEventInternalCount);
  482. break;
  483. }
  484. case kPluginBridgeOpcodeShowUI:
  485. carla_stdout("-----------------------------------------------------, got SHOW UI");
  486. fNextUIState = 1;
  487. break;
  488. case kPluginBridgeOpcodeHideUI:
  489. carla_stdout("-----------------------------------------------------, got HIDE UI");
  490. fNextUIState = 0;
  491. break;
  492. case kPluginBridgeOpcodeQuit:
  493. signalThreadShouldExit();
  494. fIsRunning = false;
  495. break;
  496. default:
  497. carla_stderr2("Unhandled Plugin opcode %i", opcode);
  498. break;
  499. }
  500. }
  501. if (! jackbridge_sem_post(&fShmControl.data->runClient))
  502. carla_stderr2("Could not post to semaphore");
  503. }
  504. fIsRunning = false;
  505. callback(ENGINE_CALLBACK_ENGINE_STOPPED, 0, 0, 0, 0.0f, nullptr);
  506. }
  507. private:
  508. BridgeAudioPool fShmAudioPool;
  509. BridgeControl fShmControl;
  510. BridgeTime fShmTime;
  511. volatile bool fIsRunning;
  512. volatile int fNextUIState;
  513. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineBridge)
  514. };
  515. // -----------------------------------------
  516. CarlaEngine* CarlaEngine::newBridge(const char* const audioBaseName, const char* const controlBaseName, const char* const timeBaseName)
  517. {
  518. return new CarlaEngineBridge(audioBaseName, controlBaseName, timeBaseName);
  519. }
  520. CARLA_BACKEND_END_NAMESPACE
  521. // -----------------------------------------------------------------------
  522. #if defined(CARLA_OS_WIN) && ! defined(__WINE__)
  523. extern "C" __declspec (dllexport)
  524. #else
  525. extern "C" __attribute__ ((visibility("default")))
  526. #endif
  527. void carla_register_native_plugin_carla();
  528. void carla_register_native_plugin_carla(){}
  529. // -----------------------------------------------------------------------