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.

936 lines
31KB

  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 "CarlaBase64Utils.hpp"
  24. #include "CarlaBridgeUtils.hpp"
  25. #include "CarlaMIDI.h"
  26. #include "jackbridge/JackBridge.hpp"
  27. #include <cerrno>
  28. #include <ctime>
  29. using juce::File;
  30. using juce::MemoryBlock;
  31. using juce::String;
  32. // -------------------------------------------------------------------
  33. #ifdef JACKBRIDGE_EXPORT
  34. bool jackbridge_is_ok() noexcept
  35. {
  36. return true;
  37. }
  38. #endif
  39. template<typename T>
  40. bool jackbridge_shm_map2(char* shm, T*& value) noexcept
  41. {
  42. value = (T*)jackbridge_shm_map(shm, sizeof(T));
  43. return (value != nullptr);
  44. }
  45. // -------------------------------------------------------------------
  46. CARLA_BACKEND_START_NAMESPACE
  47. // -------------------------------------------------------------------
  48. struct BridgeAudioPool {
  49. CarlaString filename;
  50. float* data;
  51. char shm[32];
  52. BridgeAudioPool() noexcept
  53. : filename(),
  54. data(nullptr)
  55. {
  56. carla_zeroChar(shm, 32);
  57. jackbridge_shm_init(shm);
  58. }
  59. ~BridgeAudioPool() noexcept
  60. {
  61. // should be cleared by now
  62. CARLA_SAFE_ASSERT(data == nullptr);
  63. clear();
  64. }
  65. bool attach() noexcept
  66. {
  67. jackbridge_shm_attach(shm, filename);
  68. return jackbridge_shm_is_valid(shm);
  69. }
  70. void clear() noexcept
  71. {
  72. filename.clear();
  73. data = nullptr;
  74. if (jackbridge_shm_is_valid(shm))
  75. jackbridge_shm_close(shm);
  76. }
  77. CARLA_DECLARE_NON_COPY_STRUCT(BridgeAudioPool)
  78. };
  79. // -------------------------------------------------------------------
  80. struct BridgeRtControl : public CarlaRingBuffer<StackBuffer> {
  81. CarlaString filename;
  82. BridgeRtData* data;
  83. char shm[32];
  84. BridgeRtControl() noexcept
  85. : filename(),
  86. data(nullptr)
  87. {
  88. carla_zeroChar(shm, 32);
  89. jackbridge_shm_init(shm);
  90. }
  91. ~BridgeRtControl() noexcept
  92. {
  93. // should be cleared by now
  94. CARLA_SAFE_ASSERT(data == nullptr);
  95. clear();
  96. }
  97. bool attach() noexcept
  98. {
  99. jackbridge_shm_attach(shm, filename);
  100. return jackbridge_shm_is_valid(shm);
  101. }
  102. void clear() noexcept
  103. {
  104. filename.clear();
  105. data = nullptr;
  106. if (jackbridge_shm_is_valid(shm))
  107. jackbridge_shm_close(shm);
  108. }
  109. bool mapData() noexcept
  110. {
  111. CARLA_SAFE_ASSERT(data == nullptr);
  112. if (jackbridge_shm_map2<BridgeRtData>(shm, data))
  113. {
  114. setRingBuffer(&data->ringBuffer, false);
  115. return true;
  116. }
  117. return false;
  118. }
  119. PluginBridgeRtOpcode readOpcode() noexcept
  120. {
  121. return static_cast<PluginBridgeRtOpcode>(readInt());
  122. }
  123. CARLA_DECLARE_NON_COPY_STRUCT(BridgeRtControl)
  124. };
  125. // -------------------------------------------------------------------
  126. struct BridgeNonRtControl : public CarlaRingBuffer<BigStackBuffer> {
  127. CarlaString filename;
  128. BridgeNonRtData* data;
  129. char shm[32];
  130. BridgeNonRtControl() noexcept
  131. : filename(),
  132. data(nullptr)
  133. {
  134. carla_zeroChar(shm, 32);
  135. jackbridge_shm_init(shm);
  136. }
  137. ~BridgeNonRtControl() noexcept
  138. {
  139. // should be cleared by now
  140. CARLA_SAFE_ASSERT(data == nullptr);
  141. clear();
  142. }
  143. bool attach() noexcept
  144. {
  145. jackbridge_shm_attach(shm, filename);
  146. return jackbridge_shm_is_valid(shm);
  147. }
  148. void clear() noexcept
  149. {
  150. filename.clear();
  151. data = nullptr;
  152. if (jackbridge_shm_is_valid(shm))
  153. jackbridge_shm_close(shm);
  154. }
  155. bool mapData() noexcept
  156. {
  157. CARLA_SAFE_ASSERT(data == nullptr);
  158. if (jackbridge_shm_map2<BridgeNonRtData>(shm, data))
  159. {
  160. setRingBuffer(&data->ringBuffer, false);
  161. return true;
  162. }
  163. return false;
  164. }
  165. PluginBridgeNonRtOpcode readOpcode() noexcept
  166. {
  167. return static_cast<PluginBridgeNonRtOpcode>(readInt());
  168. }
  169. CARLA_DECLARE_NON_COPY_STRUCT(BridgeNonRtControl)
  170. };
  171. // -------------------------------------------------------------------
  172. class CarlaEngineBridge : public CarlaEngine,
  173. public CarlaThread
  174. {
  175. public:
  176. CarlaEngineBridge(const char* const audioPoolBaseName, const char* const rtBaseName, const char* const nonRtBaseName)
  177. : CarlaEngine(),
  178. CarlaThread("CarlaEngineBridge"),
  179. fShmAudioPool(),
  180. fShmRtControl(),
  181. fShmNonRtControl(),
  182. fIsRunning(false),
  183. fIsOffline(false),
  184. leakDetector_CarlaEngineBridge()
  185. {
  186. carla_stdout("CarlaEngineBridge::CarlaEngineBridge(\"%s\", \"%s\", \"%s\")", audioPoolBaseName, rtBaseName, nonRtBaseName);
  187. fShmAudioPool.filename = "/carla-bridge_shm_ap_";
  188. fShmAudioPool.filename += audioPoolBaseName;
  189. fShmRtControl.filename = "/carla-bridge_shm_rt_";
  190. fShmRtControl.filename += rtBaseName;
  191. fShmNonRtControl.filename = "/carla-bridge_shm_nonrt_";
  192. fShmNonRtControl.filename += nonRtBaseName;
  193. }
  194. ~CarlaEngineBridge() noexcept override
  195. {
  196. carla_debug("CarlaEngineBridge::~CarlaEngineBridge()");
  197. }
  198. // -------------------------------------
  199. // CarlaEngine virtual calls
  200. bool init(const char* const clientName) override
  201. {
  202. carla_debug("CarlaEngineBridge::init(\"%s\")", clientName);
  203. if (! fShmAudioPool.attach())
  204. {
  205. carla_stdout("Failed to attach to audio pool shared memory");
  206. return false;
  207. }
  208. if (! fShmRtControl.attach())
  209. {
  210. clear();
  211. carla_stdout("Failed to attach to rt control shared memory");
  212. return false;
  213. }
  214. if (! fShmRtControl.mapData())
  215. {
  216. clear();
  217. carla_stdout("Failed to map rt control shared memory");
  218. return false;
  219. }
  220. if (! fShmNonRtControl.attach())
  221. {
  222. clear();
  223. carla_stdout("Failed to attach to non-rt control shared memory");
  224. return false;
  225. }
  226. if (! fShmNonRtControl.mapData())
  227. {
  228. clear();
  229. carla_stdout("Failed to map non-rt control shared memory");
  230. return false;
  231. }
  232. PluginBridgeNonRtOpcode opcode;
  233. opcode = fShmNonRtControl.readOpcode();
  234. CARLA_SAFE_ASSERT_INT(opcode == kPluginBridgeNonRtNull, opcode);
  235. const uint32_t shmRtDataSize = fShmNonRtControl.readUInt();
  236. CARLA_SAFE_ASSERT_INT2(shmRtDataSize == sizeof(BridgeRtData), shmRtDataSize, sizeof(BridgeRtData));
  237. const uint32_t shmNonRtDataSize = fShmNonRtControl.readUInt();
  238. CARLA_SAFE_ASSERT_INT2(shmNonRtDataSize == sizeof(BridgeNonRtData), shmNonRtDataSize, sizeof(BridgeNonRtData));
  239. opcode = fShmNonRtControl.readOpcode();
  240. CARLA_SAFE_ASSERT_INT(opcode == kPluginBridgeNonRtSetBufferSize, opcode);
  241. pData->bufferSize = fShmNonRtControl.readUInt();
  242. opcode = fShmNonRtControl.readOpcode();
  243. CARLA_SAFE_ASSERT_INT(opcode == kPluginBridgeNonRtSetSampleRate, opcode);
  244. pData->sampleRate = fShmNonRtControl.readDouble();
  245. carla_stdout("Carla Client Info:");
  246. carla_stdout(" BufferSize: %i", pData->bufferSize);
  247. carla_stdout(" SampleRate: %g", pData->sampleRate);
  248. carla_stdout(" sizeof(BridgeRtData): %i/" P_SIZE, shmRtDataSize, sizeof(BridgeRtData));
  249. carla_stdout(" sizeof(BridgeNonRtData): %i/" P_SIZE, shmNonRtDataSize, sizeof(BridgeNonRtData));
  250. startThread();
  251. CarlaEngine::init(clientName);
  252. return true;
  253. }
  254. bool close() override
  255. {
  256. carla_debug("CarlaEnginePlugin::close()");
  257. CarlaEngine::close();
  258. stopThread(5000);
  259. clear();
  260. return true;
  261. }
  262. bool isRunning() const noexcept override
  263. {
  264. return isThreadRunning();
  265. }
  266. bool isOffline() const noexcept override
  267. {
  268. return fIsOffline;
  269. }
  270. EngineType getType() const noexcept override
  271. {
  272. return kEngineTypeBridge;
  273. }
  274. const char* getCurrentDriverName() const noexcept
  275. {
  276. return "Bridge";
  277. }
  278. void idle() noexcept override
  279. {
  280. CarlaEngine::idle();
  281. try {
  282. handleNonRtData();
  283. } CARLA_SAFE_EXCEPTION("handleNonRtData");
  284. }
  285. // -------------------------------------------------------------------
  286. void clear() noexcept
  287. {
  288. fShmAudioPool.clear();
  289. fShmRtControl.clear();
  290. fShmNonRtControl.clear();
  291. }
  292. void handleNonRtData()
  293. {
  294. for (; fShmNonRtControl.isDataAvailableForReading();)
  295. {
  296. const PluginBridgeNonRtOpcode opcode(fShmNonRtControl.readOpcode());
  297. CarlaPlugin* const plugin(pData->plugins[0].plugin);
  298. if (opcode != kPluginBridgeNonRtPing)
  299. carla_stdout("CarlaEngineBridge::handleNonRtData() - got opcode: %s", PluginBridgeNonRtOpcode2str(opcode));
  300. switch (opcode)
  301. {
  302. case kPluginBridgeNonRtNull:
  303. break;
  304. case kPluginBridgeNonRtPing:
  305. oscSend_bridge_pong();
  306. break;
  307. case kPluginBridgeNonRtActivate:
  308. if (plugin != nullptr && plugin->isEnabled())
  309. plugin->setActive(true, false, false);
  310. break;
  311. case kPluginBridgeNonRtDeactivate:
  312. if (plugin != nullptr && plugin->isEnabled())
  313. plugin->setActive(false, false, false);
  314. break;
  315. case kPluginBridgeNonRtSetBufferSize: {
  316. const uint32_t bufferSize(fShmNonRtControl.readUInt());
  317. pData->bufferSize = bufferSize;
  318. bufferSizeChanged(bufferSize);
  319. break;
  320. }
  321. case kPluginBridgeNonRtSetSampleRate: {
  322. const double sampleRate(fShmNonRtControl.readDouble());
  323. pData->sampleRate = sampleRate;
  324. sampleRateChanged(sampleRate);
  325. break;
  326. }
  327. case kPluginBridgeNonRtSetOffline:
  328. fIsOffline = true;
  329. offlineModeChanged(true);
  330. break;
  331. case kPluginBridgeNonRtSetOnline:
  332. fIsOffline = false;
  333. offlineModeChanged(false);
  334. break;
  335. case kPluginBridgeNonRtSetParameterValue: {
  336. const uint32_t index(fShmNonRtControl.readUInt());
  337. const float value(fShmNonRtControl.readFloat());
  338. if (plugin != nullptr && plugin->isEnabled())
  339. plugin->setParameterValue(index, value, false, false, false);
  340. break;
  341. }
  342. case kPluginBridgeNonRtSetParameterMidiChannel: {
  343. const uint32_t index(fShmNonRtControl.readUInt());
  344. const uint8_t channel(fShmNonRtControl.readByte());
  345. if (plugin != nullptr && plugin->isEnabled())
  346. plugin->setParameterMidiChannel(index, channel, false, false);
  347. break;
  348. }
  349. case kPluginBridgeNonRtSetParameterMidiCC: {
  350. const uint32_t index(fShmNonRtControl.readUInt());
  351. const int16_t cc(fShmNonRtControl.readShort());
  352. if (plugin != nullptr && plugin->isEnabled())
  353. plugin->setParameterMidiCC(index, cc, false, false);
  354. break;
  355. }
  356. case kPluginBridgeNonRtSetProgram: {
  357. const int32_t index(fShmNonRtControl.readInt());
  358. if (plugin != nullptr && plugin->isEnabled())
  359. plugin->setProgram(index, false, false, false);
  360. break;
  361. }
  362. case kPluginBridgeNonRtSetMidiProgram: {
  363. const int32_t index(fShmNonRtControl.readInt());
  364. if (plugin != nullptr && plugin->isEnabled())
  365. plugin->setMidiProgram(index, false, false, false);
  366. break;
  367. }
  368. case kPluginBridgeNonRtSetCustomData: {
  369. // type
  370. const uint32_t typeSize(fShmNonRtControl.readUInt());
  371. char typeStr[typeSize+1];
  372. carla_zeroChar(typeStr, typeSize+1);
  373. fShmNonRtControl.readCustomData(typeStr, typeSize);
  374. // key
  375. const uint32_t keySize(fShmNonRtControl.readUInt());
  376. char keyStr[keySize+1];
  377. carla_zeroChar(keyStr, keySize+1);
  378. fShmNonRtControl.readCustomData(keyStr, keySize);
  379. // value
  380. const uint32_t valueSize(fShmNonRtControl.readUInt());
  381. char valueStr[valueSize+1];
  382. carla_zeroChar(valueStr, valueSize+1);
  383. fShmNonRtControl.readCustomData(valueStr, valueSize);
  384. if (plugin != nullptr && plugin->isEnabled())
  385. plugin->setCustomData(typeStr, keyStr, valueStr, true);
  386. break;
  387. }
  388. case kPluginBridgeNonRtSetChunkDataFile: {
  389. const uint32_t size(fShmNonRtControl.readUInt());
  390. CARLA_SAFE_ASSERT_BREAK(size > 0);
  391. char chunkFilePathTry[size+1];
  392. carla_zeroChar(chunkFilePathTry, size+1);
  393. fShmNonRtControl.readCustomData(chunkFilePathTry, size);
  394. CARLA_SAFE_ASSERT_BREAK(chunkFilePathTry[0] != '\0');
  395. if (plugin == nullptr || ! plugin->isEnabled()) break;
  396. String chunkFilePath(chunkFilePathTry);
  397. #ifdef CARLA_OS_WIN
  398. // check if running under Wine
  399. if (chunkFilePath.startsWith("/"))
  400. chunkFilePath = chunkFilePath.replaceSection(0, 1, "Z:\\").replace("/", "\\");
  401. #endif
  402. File chunkFile(chunkFilePath);
  403. CARLA_SAFE_ASSERT_BREAK(chunkFile.existsAsFile());
  404. String chunkDataBase64(chunkFile.loadFileAsString());
  405. chunkFile.deleteFile();
  406. CARLA_SAFE_ASSERT_BREAK(chunkDataBase64.isNotEmpty());
  407. std::vector<uint8_t> chunk(carla_getChunkFromBase64String(chunkDataBase64.toRawUTF8()));
  408. plugin->setChunkData(chunk.data(), chunk.size());
  409. break;
  410. }
  411. case kPluginBridgeNonRtSetCtrlChannel: {
  412. const int16_t channel(fShmNonRtControl.readShort());
  413. CARLA_SAFE_ASSERT_BREAK(channel >= -1 && channel < MAX_MIDI_CHANNELS);
  414. if (plugin != nullptr && plugin->isEnabled())
  415. plugin->setCtrlChannel(static_cast<int8_t>(channel), false, false);
  416. break;
  417. }
  418. case kPluginBridgeNonRtSetOscURL: {
  419. const uint32_t size(fShmNonRtControl.readUInt());
  420. char url[size+1];
  421. carla_zeroChar(url, size+1);
  422. fShmNonRtControl.readCustomData(url, size);
  423. CARLA_SAFE_ASSERT_BREAK(url[0] != '\0');
  424. if (plugin == nullptr || ! plugin->isEnabled()) break;
  425. pData->oscData->setNewURL(url);
  426. break;
  427. }
  428. case kPluginBridgeNonRtSetOption: {
  429. const uint32_t option(fShmNonRtControl.readUInt());
  430. const bool yesNo(fShmNonRtControl.readBool());
  431. if (plugin != nullptr && plugin->isEnabled())
  432. plugin->setOption(option, yesNo, false);
  433. break;
  434. }
  435. case kPluginBridgeNonRtPrepareForSave: {
  436. if (plugin == nullptr || ! plugin->isEnabled()) break;
  437. plugin->prepareForSave();
  438. for (uint32_t i=0, count=plugin->getCustomDataCount(); i<count; ++i)
  439. {
  440. const CustomData& cdata(plugin->getCustomData(i));
  441. oscSend_bridge_set_custom_data(cdata.type, cdata.key, cdata.value);
  442. }
  443. if (plugin->getOptionsEnabled() & PLUGIN_OPTION_USE_CHUNKS)
  444. {
  445. void* data = nullptr;
  446. if (const std::size_t dataSize = plugin->getChunkData(&data))
  447. {
  448. CARLA_SAFE_ASSERT_BREAK(data != nullptr);
  449. CarlaString dataBase64 = CarlaString::asBase64(data, dataSize);
  450. CARLA_SAFE_ASSERT_RETURN(dataBase64.length() > 0,);
  451. String filePath(File::getSpecialLocation(File::tempDirectory).getFullPathName());
  452. filePath += CARLA_OS_SEP_STR;
  453. filePath += ".CarlaChunk_";
  454. filePath += fShmNonRtControl.filename.buffer() + 24;
  455. if (File(filePath).replaceWithText(dataBase64.buffer()))
  456. oscSend_bridge_set_chunk_data_file(filePath.toRawUTF8());
  457. }
  458. }
  459. oscSend_bridge_configure(CARLA_BRIDGE_MSG_SAVED, "");
  460. break;
  461. }
  462. case kPluginBridgeNonRtShowUI:
  463. if (plugin != nullptr && plugin->isEnabled())
  464. plugin->showCustomUI(true);
  465. break;
  466. case kPluginBridgeNonRtHideUI:
  467. if (plugin != nullptr && plugin->isEnabled())
  468. plugin->showCustomUI(false);
  469. break;
  470. case kPluginBridgeNonRtUiParameterChange: {
  471. const uint32_t index(fShmNonRtControl.readUInt());
  472. const float value(fShmNonRtControl.readFloat());
  473. if (plugin != nullptr && plugin->isEnabled())
  474. plugin->uiParameterChange(index, value);
  475. break;
  476. }
  477. case kPluginBridgeNonRtUiProgramChange: {
  478. const uint32_t index(fShmNonRtControl.readUInt());
  479. if (plugin != nullptr && plugin->isEnabled())
  480. plugin->uiProgramChange(index);
  481. break;
  482. }
  483. case kPluginBridgeNonRtUiMidiProgramChange: {
  484. const uint32_t index(fShmNonRtControl.readUInt());
  485. if (plugin != nullptr && plugin->isEnabled())
  486. plugin->uiMidiProgramChange(index);
  487. break;
  488. }
  489. case kPluginBridgeNonRtUiNoteOn: {
  490. const uint8_t chnl(fShmNonRtControl.readByte());
  491. const uint8_t note(fShmNonRtControl.readByte());
  492. const uint8_t velo(fShmNonRtControl.readByte());
  493. if (plugin != nullptr && plugin->isEnabled())
  494. plugin->uiNoteOn(chnl, note, velo);
  495. break;
  496. }
  497. case kPluginBridgeNonRtUiNoteOff: {
  498. const uint8_t chnl(fShmNonRtControl.readByte());
  499. const uint8_t note(fShmNonRtControl.readByte());
  500. if (plugin != nullptr && plugin->isEnabled())
  501. plugin->uiNoteOff(chnl, note);
  502. break;
  503. }
  504. case kPluginBridgeNonRtQuit:
  505. signalThreadShouldExit();
  506. break;
  507. }
  508. }
  509. }
  510. // -------------------------------------------------------------------
  511. protected:
  512. void run() override
  513. {
  514. for (; ! shouldThreadExit();)
  515. {
  516. if (! jackbridge_sem_timedwait(&fShmRtControl.data->sem.server, 5))
  517. {
  518. if (errno == ETIMEDOUT)
  519. {
  520. signalThreadShouldExit();
  521. break;
  522. }
  523. }
  524. for (; fShmRtControl.isDataAvailableForReading();)
  525. {
  526. const PluginBridgeRtOpcode opcode(fShmRtControl.readOpcode());
  527. CarlaPlugin* const plugin(pData->plugins[0].plugin);
  528. if (opcode != kPluginBridgeRtProcess && opcode != kPluginBridgeRtMidiEvent) {
  529. carla_stdout("CarlaEngineBridgeRtThread::run() - got opcode: %s", PluginBridgeRtOpcode2str(opcode));
  530. }
  531. switch (opcode)
  532. {
  533. case kPluginBridgeRtNull:
  534. break;
  535. case kPluginBridgeRtSetAudioPool: {
  536. const uint64_t poolSize(fShmRtControl.readULong());
  537. CARLA_SAFE_ASSERT_BREAK(poolSize > 0);
  538. fShmAudioPool.data = (float*)jackbridge_shm_map(fShmAudioPool.shm, static_cast<size_t>(poolSize));
  539. break;
  540. }
  541. case kPluginBridgeRtControlEventParameter: {
  542. const uint32_t time(fShmRtControl.readUInt());
  543. const uint8_t channel(fShmRtControl.readByte());
  544. const uint16_t param(fShmRtControl.readUShort());
  545. const float value(fShmRtControl.readFloat());
  546. if (EngineEvent* const event = getNextFreeInputEvent())
  547. {
  548. event->type = kEngineEventTypeControl;
  549. event->time = time;
  550. event->channel = channel;
  551. event->ctrl.type = kEngineControlEventTypeParameter;
  552. event->ctrl.param = param;
  553. event->ctrl.value = value;
  554. }
  555. break;
  556. }
  557. case kPluginBridgeRtControlEventMidiBank: {
  558. const uint32_t time(fShmRtControl.readUInt());
  559. const uint8_t channel(fShmRtControl.readByte());
  560. const uint16_t index(fShmRtControl.readUShort());
  561. if (EngineEvent* const event = getNextFreeInputEvent())
  562. {
  563. event->type = kEngineEventTypeControl;
  564. event->time = time;
  565. event->channel = channel;
  566. event->ctrl.type = kEngineControlEventTypeMidiBank;
  567. event->ctrl.param = index;
  568. event->ctrl.value = 0.0f;
  569. }
  570. break;
  571. }
  572. case kPluginBridgeRtControlEventMidiProgram: {
  573. const uint32_t time(fShmRtControl.readUInt());
  574. const uint8_t channel(fShmRtControl.readByte());
  575. const uint16_t index(fShmRtControl.readUShort());
  576. if (EngineEvent* const event = getNextFreeInputEvent())
  577. {
  578. event->type = kEngineEventTypeControl;
  579. event->time = time;
  580. event->channel = channel;
  581. event->ctrl.type = kEngineControlEventTypeMidiProgram;
  582. event->ctrl.param = index;
  583. event->ctrl.value = 0.0f;
  584. }
  585. break;
  586. }
  587. case kPluginBridgeRtControlEventAllSoundOff: {
  588. const uint32_t time(fShmRtControl.readUInt());
  589. const uint8_t channel(fShmRtControl.readByte());
  590. if (EngineEvent* const event = getNextFreeInputEvent())
  591. {
  592. event->type = kEngineEventTypeControl;
  593. event->time = time;
  594. event->channel = channel;
  595. event->ctrl.type = kEngineControlEventTypeAllSoundOff;
  596. event->ctrl.param = 0;
  597. event->ctrl.value = 0.0f;
  598. }
  599. }
  600. case kPluginBridgeRtControlEventAllNotesOff: {
  601. const uint32_t time(fShmRtControl.readUInt());
  602. const uint8_t channel(fShmRtControl.readByte());
  603. if (EngineEvent* const event = getNextFreeInputEvent())
  604. {
  605. event->type = kEngineEventTypeControl;
  606. event->time = time;
  607. event->channel = channel;
  608. event->ctrl.type = kEngineControlEventTypeAllNotesOff;
  609. event->ctrl.param = 0;
  610. event->ctrl.value = 0.0f;
  611. }
  612. }
  613. case kPluginBridgeRtMidiEvent: {
  614. const uint32_t time(fShmRtControl.readUInt());
  615. const uint8_t port(fShmRtControl.readByte());
  616. const uint8_t size(fShmRtControl.readByte());
  617. CARLA_SAFE_ASSERT_BREAK(size > 0);
  618. uint8_t data[size];
  619. for (uint8_t i=0; i<size; ++i)
  620. data[i] = fShmRtControl.readByte();
  621. if (EngineEvent* const event = getNextFreeInputEvent())
  622. {
  623. event->type = kEngineEventTypeMidi;
  624. event->time = time;
  625. event->channel = MIDI_GET_CHANNEL_FROM_DATA(data);
  626. event->midi.port = port;
  627. event->midi.size = size;
  628. if (size > EngineMidiEvent::kDataSize)
  629. {
  630. event->midi.dataExt = data;
  631. std::memset(event->midi.data, 0, sizeof(uint8_t)*EngineMidiEvent::kDataSize);
  632. }
  633. else
  634. {
  635. event->midi.data[0] = MIDI_GET_STATUS_FROM_DATA(data);
  636. uint8_t i=1;
  637. for (; i < size; ++i)
  638. event->midi.data[i] = data[i];
  639. for (; i < EngineMidiEvent::kDataSize; ++i)
  640. event->midi.data[i] = 0;
  641. event->midi.dataExt = nullptr;
  642. }
  643. }
  644. break;
  645. }
  646. case kPluginBridgeRtProcess: {
  647. CARLA_SAFE_ASSERT_BREAK(fShmAudioPool.data != nullptr);
  648. if (plugin != nullptr && plugin->isEnabled() && plugin->tryLock(false))
  649. {
  650. const BridgeTimeInfo& bridgeTimeInfo(fShmRtControl.data->timeInfo);
  651. const uint32_t inCount(plugin->getAudioInCount());
  652. const uint32_t outCount(plugin->getAudioOutCount());
  653. float* inBuffer[inCount];
  654. float* outBuffer[outCount];
  655. for (uint32_t i=0; i < inCount; ++i)
  656. inBuffer[i] = fShmAudioPool.data + i*pData->bufferSize;
  657. for (uint32_t i=0; i < outCount; ++i)
  658. outBuffer[i] = fShmAudioPool.data + (i+inCount)*pData->bufferSize;
  659. EngineTimeInfo& timeInfo(pData->timeInfo);
  660. timeInfo.playing = bridgeTimeInfo.playing;
  661. timeInfo.frame = bridgeTimeInfo.frame;
  662. timeInfo.usecs = bridgeTimeInfo.usecs;
  663. timeInfo.valid = bridgeTimeInfo.valid;
  664. if (timeInfo.valid & EngineTimeInfo::kValidBBT)
  665. {
  666. timeInfo.bbt.bar = bridgeTimeInfo.bar;
  667. timeInfo.bbt.beat = bridgeTimeInfo.beat;
  668. timeInfo.bbt.tick = bridgeTimeInfo.tick;
  669. timeInfo.bbt.beatsPerBar = bridgeTimeInfo.beatsPerBar;
  670. timeInfo.bbt.beatType = bridgeTimeInfo.beatType;
  671. timeInfo.bbt.ticksPerBeat = bridgeTimeInfo.ticksPerBeat;
  672. timeInfo.bbt.beatsPerMinute = bridgeTimeInfo.beatsPerMinute;
  673. timeInfo.bbt.barStartTick = bridgeTimeInfo.barStartTick;
  674. }
  675. plugin->initBuffers();
  676. plugin->process(inBuffer, outBuffer, pData->bufferSize);
  677. plugin->unlock();
  678. }
  679. // clear buffer
  680. CARLA_SAFE_ASSERT_BREAK(pData->events.in != nullptr);
  681. if (pData->events.in[0].type != kEngineEventTypeNull)
  682. carla_zeroStruct<EngineEvent>(pData->events.in, kMaxEngineEventInternalCount);
  683. break;
  684. }
  685. }
  686. }
  687. if (! jackbridge_sem_post(&fShmRtControl.data->sem.client))
  688. carla_stderr2("Could not post to rt semaphore");
  689. }
  690. fIsRunning = false;
  691. callback(ENGINE_CALLBACK_ENGINE_STOPPED, 0, 0, 0, 0.0f, nullptr);
  692. }
  693. // called from process thread above
  694. EngineEvent* getNextFreeInputEvent() const noexcept
  695. {
  696. for (ushort i=0; i < kMaxEngineEventInternalCount; ++i)
  697. {
  698. EngineEvent& event(pData->events.in[i]);
  699. if (event.type == kEngineEventTypeNull)
  700. return &event;
  701. }
  702. return nullptr;
  703. }
  704. // -------------------------------------------------------------------
  705. private:
  706. BridgeAudioPool fShmAudioPool;
  707. BridgeRtControl fShmRtControl;
  708. BridgeNonRtControl fShmNonRtControl;
  709. bool fIsRunning;
  710. bool fIsOffline;
  711. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineBridge)
  712. };
  713. // -----------------------------------------------------------------------
  714. CarlaEngine* CarlaEngine::newBridge(const char* const audioPoolBaseName, const char* const rtBaseName, const char* const nonRtBaseName)
  715. {
  716. return new CarlaEngineBridge(audioPoolBaseName, rtBaseName, nonRtBaseName);
  717. }
  718. // -----------------------------------------------------------------------
  719. #ifdef BRIDGE_PLUGIN
  720. CarlaPlugin* CarlaPlugin::newNative(const CarlaPlugin::Initializer&) { return nullptr; }
  721. CarlaPlugin* CarlaPlugin::newFileGIG(const CarlaPlugin::Initializer&, const bool) { return nullptr; }
  722. CarlaPlugin* CarlaPlugin::newFileSF2(const CarlaPlugin::Initializer&, const bool) { return nullptr; }
  723. CarlaPlugin* CarlaPlugin::newFileSFZ(const CarlaPlugin::Initializer&) { return nullptr; }
  724. #endif
  725. CARLA_BACKEND_END_NAMESPACE
  726. // -----------------------------------------------------------------------
  727. #if defined(CARLA_OS_WIN) && ! defined(__WINE__)
  728. extern "C" __declspec (dllexport)
  729. #else
  730. extern "C" __attribute__ ((visibility("default")))
  731. #endif
  732. void carla_register_native_plugin_carla();
  733. void carla_register_native_plugin_carla(){}
  734. // -----------------------------------------------------------------------