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.

939 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 override
  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 override
  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. if (shmRtDataSize != sizeof(BridgeRtData) || shmNonRtDataSize != sizeof(BridgeNonRtData))
  251. return false;
  252. startThread();
  253. CarlaEngine::init(clientName);
  254. return true;
  255. }
  256. bool close() override
  257. {
  258. carla_debug("CarlaEnginePlugin::close()");
  259. CarlaEngine::close();
  260. stopThread(5000);
  261. clear();
  262. return true;
  263. }
  264. bool isRunning() const noexcept override
  265. {
  266. return isThreadRunning();
  267. }
  268. bool isOffline() const noexcept override
  269. {
  270. return fIsOffline;
  271. }
  272. EngineType getType() const noexcept override
  273. {
  274. return kEngineTypeBridge;
  275. }
  276. const char* getCurrentDriverName() const noexcept
  277. {
  278. return "Bridge";
  279. }
  280. void idle() noexcept override
  281. {
  282. CarlaEngine::idle();
  283. try {
  284. handleNonRtData();
  285. } CARLA_SAFE_EXCEPTION("handleNonRtData");
  286. }
  287. // -------------------------------------------------------------------
  288. void clear() noexcept
  289. {
  290. fShmAudioPool.clear();
  291. fShmRtControl.clear();
  292. fShmNonRtControl.clear();
  293. }
  294. void handleNonRtData()
  295. {
  296. for (; fShmNonRtControl.isDataAvailableForReading();)
  297. {
  298. const PluginBridgeNonRtOpcode opcode(fShmNonRtControl.readOpcode());
  299. CarlaPlugin* const plugin(pData->plugins[0].plugin);
  300. if (opcode != kPluginBridgeNonRtPing)
  301. carla_stdout("CarlaEngineBridge::handleNonRtData() - got opcode: %s", PluginBridgeNonRtOpcode2str(opcode));
  302. switch (opcode)
  303. {
  304. case kPluginBridgeNonRtNull:
  305. break;
  306. case kPluginBridgeNonRtPing:
  307. oscSend_bridge_pong();
  308. break;
  309. case kPluginBridgeNonRtActivate:
  310. if (plugin != nullptr && plugin->isEnabled())
  311. plugin->setActive(true, false, false);
  312. break;
  313. case kPluginBridgeNonRtDeactivate:
  314. if (plugin != nullptr && plugin->isEnabled())
  315. plugin->setActive(false, false, false);
  316. break;
  317. case kPluginBridgeNonRtSetBufferSize: {
  318. const uint32_t bufferSize(fShmNonRtControl.readUInt());
  319. pData->bufferSize = bufferSize;
  320. bufferSizeChanged(bufferSize);
  321. break;
  322. }
  323. case kPluginBridgeNonRtSetSampleRate: {
  324. const double sampleRate(fShmNonRtControl.readDouble());
  325. pData->sampleRate = sampleRate;
  326. sampleRateChanged(sampleRate);
  327. break;
  328. }
  329. case kPluginBridgeNonRtSetOffline:
  330. fIsOffline = true;
  331. offlineModeChanged(true);
  332. break;
  333. case kPluginBridgeNonRtSetOnline:
  334. fIsOffline = false;
  335. offlineModeChanged(false);
  336. break;
  337. case kPluginBridgeNonRtSetParameterValue: {
  338. const uint32_t index(fShmNonRtControl.readUInt());
  339. const float value(fShmNonRtControl.readFloat());
  340. if (plugin != nullptr && plugin->isEnabled())
  341. plugin->setParameterValue(index, value, false, false, false);
  342. break;
  343. }
  344. case kPluginBridgeNonRtSetParameterMidiChannel: {
  345. const uint32_t index(fShmNonRtControl.readUInt());
  346. const uint8_t channel(fShmNonRtControl.readByte());
  347. if (plugin != nullptr && plugin->isEnabled())
  348. plugin->setParameterMidiChannel(index, channel, false, false);
  349. break;
  350. }
  351. case kPluginBridgeNonRtSetParameterMidiCC: {
  352. const uint32_t index(fShmNonRtControl.readUInt());
  353. const int16_t cc(fShmNonRtControl.readShort());
  354. if (plugin != nullptr && plugin->isEnabled())
  355. plugin->setParameterMidiCC(index, cc, false, false);
  356. break;
  357. }
  358. case kPluginBridgeNonRtSetProgram: {
  359. const int32_t index(fShmNonRtControl.readInt());
  360. if (plugin != nullptr && plugin->isEnabled())
  361. plugin->setProgram(index, false, false, false);
  362. break;
  363. }
  364. case kPluginBridgeNonRtSetMidiProgram: {
  365. const int32_t index(fShmNonRtControl.readInt());
  366. if (plugin != nullptr && plugin->isEnabled())
  367. plugin->setMidiProgram(index, false, false, false);
  368. break;
  369. }
  370. case kPluginBridgeNonRtSetCustomData: {
  371. // type
  372. const uint32_t typeSize(fShmNonRtControl.readUInt());
  373. char typeStr[typeSize+1];
  374. carla_zeroChar(typeStr, typeSize+1);
  375. fShmNonRtControl.readCustomData(typeStr, typeSize);
  376. // key
  377. const uint32_t keySize(fShmNonRtControl.readUInt());
  378. char keyStr[keySize+1];
  379. carla_zeroChar(keyStr, keySize+1);
  380. fShmNonRtControl.readCustomData(keyStr, keySize);
  381. // value
  382. const uint32_t valueSize(fShmNonRtControl.readUInt());
  383. char valueStr[valueSize+1];
  384. carla_zeroChar(valueStr, valueSize+1);
  385. fShmNonRtControl.readCustomData(valueStr, valueSize);
  386. if (plugin != nullptr && plugin->isEnabled())
  387. plugin->setCustomData(typeStr, keyStr, valueStr, true);
  388. break;
  389. }
  390. case kPluginBridgeNonRtSetChunkDataFile: {
  391. const uint32_t size(fShmNonRtControl.readUInt());
  392. CARLA_SAFE_ASSERT_BREAK(size > 0);
  393. char chunkFilePathTry[size+1];
  394. carla_zeroChar(chunkFilePathTry, size+1);
  395. fShmNonRtControl.readCustomData(chunkFilePathTry, size);
  396. CARLA_SAFE_ASSERT_BREAK(chunkFilePathTry[0] != '\0');
  397. if (plugin == nullptr || ! plugin->isEnabled()) break;
  398. String chunkFilePath(chunkFilePathTry);
  399. #ifdef CARLA_OS_WIN
  400. // check if running under Wine
  401. if (chunkFilePath.startsWith("/"))
  402. chunkFilePath = chunkFilePath.replaceSection(0, 1, "Z:\\").replace("/", "\\");
  403. #endif
  404. File chunkFile(chunkFilePath);
  405. CARLA_SAFE_ASSERT_BREAK(chunkFile.existsAsFile());
  406. String chunkDataBase64(chunkFile.loadFileAsString());
  407. chunkFile.deleteFile();
  408. CARLA_SAFE_ASSERT_BREAK(chunkDataBase64.isNotEmpty());
  409. std::vector<uint8_t> chunk(carla_getChunkFromBase64String(chunkDataBase64.toRawUTF8()));
  410. plugin->setChunkData(chunk.data(), chunk.size());
  411. break;
  412. }
  413. case kPluginBridgeNonRtSetCtrlChannel: {
  414. const int16_t channel(fShmNonRtControl.readShort());
  415. CARLA_SAFE_ASSERT_BREAK(channel >= -1 && channel < MAX_MIDI_CHANNELS);
  416. if (plugin != nullptr && plugin->isEnabled())
  417. plugin->setCtrlChannel(static_cast<int8_t>(channel), false, false);
  418. break;
  419. }
  420. case kPluginBridgeNonRtSetOscURL: {
  421. const uint32_t size(fShmNonRtControl.readUInt());
  422. char url[size+1];
  423. carla_zeroChar(url, size+1);
  424. fShmNonRtControl.readCustomData(url, size);
  425. CARLA_SAFE_ASSERT_BREAK(url[0] != '\0');
  426. if (plugin == nullptr || ! plugin->isEnabled()) break;
  427. pData->oscData->setNewURL(url);
  428. break;
  429. }
  430. case kPluginBridgeNonRtSetOption: {
  431. const uint32_t option(fShmNonRtControl.readUInt());
  432. const bool yesNo(fShmNonRtControl.readBool());
  433. if (plugin != nullptr && plugin->isEnabled())
  434. plugin->setOption(option, yesNo, false);
  435. break;
  436. }
  437. case kPluginBridgeNonRtPrepareForSave: {
  438. if (plugin == nullptr || ! plugin->isEnabled()) break;
  439. plugin->prepareForSave();
  440. for (uint32_t i=0, count=plugin->getCustomDataCount(); i<count; ++i)
  441. {
  442. const CustomData& cdata(plugin->getCustomData(i));
  443. oscSend_bridge_set_custom_data(cdata.type, cdata.key, cdata.value);
  444. }
  445. if (plugin->getOptionsEnabled() & PLUGIN_OPTION_USE_CHUNKS)
  446. {
  447. void* data = nullptr;
  448. if (const std::size_t dataSize = plugin->getChunkData(&data))
  449. {
  450. CARLA_SAFE_ASSERT_BREAK(data != nullptr);
  451. CarlaString dataBase64 = CarlaString::asBase64(data, dataSize);
  452. CARLA_SAFE_ASSERT_RETURN(dataBase64.length() > 0,);
  453. String filePath(File::getSpecialLocation(File::tempDirectory).getFullPathName());
  454. filePath += CARLA_OS_SEP_STR;
  455. filePath += ".CarlaChunk_";
  456. filePath += fShmNonRtControl.filename.buffer() + 24;
  457. if (File(filePath).replaceWithText(dataBase64.buffer()))
  458. oscSend_bridge_set_chunk_data_file(filePath.toRawUTF8());
  459. }
  460. }
  461. oscSend_bridge_configure(CARLA_BRIDGE_MSG_SAVED, "");
  462. break;
  463. }
  464. case kPluginBridgeNonRtShowUI:
  465. if (plugin != nullptr && plugin->isEnabled())
  466. plugin->showCustomUI(true);
  467. break;
  468. case kPluginBridgeNonRtHideUI:
  469. if (plugin != nullptr && plugin->isEnabled())
  470. plugin->showCustomUI(false);
  471. break;
  472. case kPluginBridgeNonRtUiParameterChange: {
  473. const uint32_t index(fShmNonRtControl.readUInt());
  474. const float value(fShmNonRtControl.readFloat());
  475. if (plugin != nullptr && plugin->isEnabled())
  476. plugin->uiParameterChange(index, value);
  477. break;
  478. }
  479. case kPluginBridgeNonRtUiProgramChange: {
  480. const uint32_t index(fShmNonRtControl.readUInt());
  481. if (plugin != nullptr && plugin->isEnabled())
  482. plugin->uiProgramChange(index);
  483. break;
  484. }
  485. case kPluginBridgeNonRtUiMidiProgramChange: {
  486. const uint32_t index(fShmNonRtControl.readUInt());
  487. if (plugin != nullptr && plugin->isEnabled())
  488. plugin->uiMidiProgramChange(index);
  489. break;
  490. }
  491. case kPluginBridgeNonRtUiNoteOn: {
  492. const uint8_t chnl(fShmNonRtControl.readByte());
  493. const uint8_t note(fShmNonRtControl.readByte());
  494. const uint8_t velo(fShmNonRtControl.readByte());
  495. if (plugin != nullptr && plugin->isEnabled())
  496. plugin->uiNoteOn(chnl, note, velo);
  497. break;
  498. }
  499. case kPluginBridgeNonRtUiNoteOff: {
  500. const uint8_t chnl(fShmNonRtControl.readByte());
  501. const uint8_t note(fShmNonRtControl.readByte());
  502. if (plugin != nullptr && plugin->isEnabled())
  503. plugin->uiNoteOff(chnl, note);
  504. break;
  505. }
  506. case kPluginBridgeNonRtQuit:
  507. signalThreadShouldExit();
  508. break;
  509. }
  510. }
  511. }
  512. // -------------------------------------------------------------------
  513. protected:
  514. void run() override
  515. {
  516. for (; ! shouldThreadExit();)
  517. {
  518. if (! jackbridge_sem_timedwait(&fShmRtControl.data->sem.server, 5))
  519. {
  520. if (errno == ETIMEDOUT)
  521. {
  522. signalThreadShouldExit();
  523. break;
  524. }
  525. }
  526. for (; fShmRtControl.isDataAvailableForReading();)
  527. {
  528. const PluginBridgeRtOpcode opcode(fShmRtControl.readOpcode());
  529. CarlaPlugin* const plugin(pData->plugins[0].plugin);
  530. if (opcode != kPluginBridgeRtProcess && opcode != kPluginBridgeRtMidiEvent) {
  531. carla_stdout("CarlaEngineBridgeRtThread::run() - got opcode: %s", PluginBridgeRtOpcode2str(opcode));
  532. }
  533. switch (opcode)
  534. {
  535. case kPluginBridgeRtNull:
  536. break;
  537. case kPluginBridgeRtSetAudioPool: {
  538. const uint64_t poolSize(fShmRtControl.readULong());
  539. CARLA_SAFE_ASSERT_BREAK(poolSize > 0);
  540. fShmAudioPool.data = (float*)jackbridge_shm_map(fShmAudioPool.shm, static_cast<size_t>(poolSize));
  541. break;
  542. }
  543. case kPluginBridgeRtControlEventParameter: {
  544. const uint32_t time(fShmRtControl.readUInt());
  545. const uint8_t channel(fShmRtControl.readByte());
  546. const uint16_t param(fShmRtControl.readUShort());
  547. const float value(fShmRtControl.readFloat());
  548. if (EngineEvent* const event = getNextFreeInputEvent())
  549. {
  550. event->type = kEngineEventTypeControl;
  551. event->time = time;
  552. event->channel = channel;
  553. event->ctrl.type = kEngineControlEventTypeParameter;
  554. event->ctrl.param = param;
  555. event->ctrl.value = value;
  556. }
  557. break;
  558. }
  559. case kPluginBridgeRtControlEventMidiBank: {
  560. const uint32_t time(fShmRtControl.readUInt());
  561. const uint8_t channel(fShmRtControl.readByte());
  562. const uint16_t index(fShmRtControl.readUShort());
  563. if (EngineEvent* const event = getNextFreeInputEvent())
  564. {
  565. event->type = kEngineEventTypeControl;
  566. event->time = time;
  567. event->channel = channel;
  568. event->ctrl.type = kEngineControlEventTypeMidiBank;
  569. event->ctrl.param = index;
  570. event->ctrl.value = 0.0f;
  571. }
  572. break;
  573. }
  574. case kPluginBridgeRtControlEventMidiProgram: {
  575. const uint32_t time(fShmRtControl.readUInt());
  576. const uint8_t channel(fShmRtControl.readByte());
  577. const uint16_t index(fShmRtControl.readUShort());
  578. if (EngineEvent* const event = getNextFreeInputEvent())
  579. {
  580. event->type = kEngineEventTypeControl;
  581. event->time = time;
  582. event->channel = channel;
  583. event->ctrl.type = kEngineControlEventTypeMidiProgram;
  584. event->ctrl.param = index;
  585. event->ctrl.value = 0.0f;
  586. }
  587. break;
  588. }
  589. case kPluginBridgeRtControlEventAllSoundOff: {
  590. const uint32_t time(fShmRtControl.readUInt());
  591. const uint8_t channel(fShmRtControl.readByte());
  592. if (EngineEvent* const event = getNextFreeInputEvent())
  593. {
  594. event->type = kEngineEventTypeControl;
  595. event->time = time;
  596. event->channel = channel;
  597. event->ctrl.type = kEngineControlEventTypeAllSoundOff;
  598. event->ctrl.param = 0;
  599. event->ctrl.value = 0.0f;
  600. }
  601. }
  602. case kPluginBridgeRtControlEventAllNotesOff: {
  603. const uint32_t time(fShmRtControl.readUInt());
  604. const uint8_t channel(fShmRtControl.readByte());
  605. if (EngineEvent* const event = getNextFreeInputEvent())
  606. {
  607. event->type = kEngineEventTypeControl;
  608. event->time = time;
  609. event->channel = channel;
  610. event->ctrl.type = kEngineControlEventTypeAllNotesOff;
  611. event->ctrl.param = 0;
  612. event->ctrl.value = 0.0f;
  613. }
  614. }
  615. case kPluginBridgeRtMidiEvent: {
  616. const uint32_t time(fShmRtControl.readUInt());
  617. const uint8_t port(fShmRtControl.readByte());
  618. const uint8_t size(fShmRtControl.readByte());
  619. CARLA_SAFE_ASSERT_BREAK(size > 0);
  620. uint8_t data[size];
  621. for (uint8_t i=0; i<size; ++i)
  622. data[i] = fShmRtControl.readByte();
  623. if (EngineEvent* const event = getNextFreeInputEvent())
  624. {
  625. event->type = kEngineEventTypeMidi;
  626. event->time = time;
  627. event->channel = MIDI_GET_CHANNEL_FROM_DATA(data);
  628. event->midi.port = port;
  629. event->midi.size = size;
  630. if (size > EngineMidiEvent::kDataSize)
  631. {
  632. event->midi.dataExt = data;
  633. std::memset(event->midi.data, 0, sizeof(uint8_t)*EngineMidiEvent::kDataSize);
  634. }
  635. else
  636. {
  637. event->midi.data[0] = MIDI_GET_STATUS_FROM_DATA(data);
  638. uint8_t i=1;
  639. for (; i < size; ++i)
  640. event->midi.data[i] = data[i];
  641. for (; i < EngineMidiEvent::kDataSize; ++i)
  642. event->midi.data[i] = 0;
  643. event->midi.dataExt = nullptr;
  644. }
  645. }
  646. break;
  647. }
  648. case kPluginBridgeRtProcess: {
  649. CARLA_SAFE_ASSERT_BREAK(fShmAudioPool.data != nullptr);
  650. if (plugin != nullptr && plugin->isEnabled() && plugin->tryLock(false))
  651. {
  652. const BridgeTimeInfo& bridgeTimeInfo(fShmRtControl.data->timeInfo);
  653. const uint32_t inCount(plugin->getAudioInCount());
  654. const uint32_t outCount(plugin->getAudioOutCount());
  655. float* inBuffer[inCount];
  656. float* outBuffer[outCount];
  657. for (uint32_t i=0; i < inCount; ++i)
  658. inBuffer[i] = fShmAudioPool.data + i*pData->bufferSize;
  659. for (uint32_t i=0; i < outCount; ++i)
  660. outBuffer[i] = fShmAudioPool.data + (i+inCount)*pData->bufferSize;
  661. EngineTimeInfo& timeInfo(pData->timeInfo);
  662. timeInfo.playing = bridgeTimeInfo.playing;
  663. timeInfo.frame = bridgeTimeInfo.frame;
  664. timeInfo.usecs = bridgeTimeInfo.usecs;
  665. timeInfo.valid = bridgeTimeInfo.valid;
  666. if (timeInfo.valid & EngineTimeInfo::kValidBBT)
  667. {
  668. timeInfo.bbt.bar = bridgeTimeInfo.bar;
  669. timeInfo.bbt.beat = bridgeTimeInfo.beat;
  670. timeInfo.bbt.tick = bridgeTimeInfo.tick;
  671. timeInfo.bbt.beatsPerBar = bridgeTimeInfo.beatsPerBar;
  672. timeInfo.bbt.beatType = bridgeTimeInfo.beatType;
  673. timeInfo.bbt.ticksPerBeat = bridgeTimeInfo.ticksPerBeat;
  674. timeInfo.bbt.beatsPerMinute = bridgeTimeInfo.beatsPerMinute;
  675. timeInfo.bbt.barStartTick = bridgeTimeInfo.barStartTick;
  676. }
  677. plugin->initBuffers();
  678. plugin->process(inBuffer, outBuffer, pData->bufferSize);
  679. plugin->unlock();
  680. }
  681. // clear buffer
  682. CARLA_SAFE_ASSERT_BREAK(pData->events.in != nullptr);
  683. if (pData->events.in[0].type != kEngineEventTypeNull)
  684. carla_zeroStruct<EngineEvent>(pData->events.in, kMaxEngineEventInternalCount);
  685. break;
  686. }
  687. }
  688. }
  689. if (! jackbridge_sem_post(&fShmRtControl.data->sem.client))
  690. carla_stderr2("Could not post to rt semaphore");
  691. }
  692. fIsRunning = false;
  693. callback(ENGINE_CALLBACK_ENGINE_STOPPED, 0, 0, 0, 0.0f, nullptr);
  694. }
  695. // called from process thread above
  696. EngineEvent* getNextFreeInputEvent() const noexcept
  697. {
  698. for (ushort i=0; i < kMaxEngineEventInternalCount; ++i)
  699. {
  700. EngineEvent& event(pData->events.in[i]);
  701. if (event.type == kEngineEventTypeNull)
  702. return &event;
  703. }
  704. return nullptr;
  705. }
  706. // -------------------------------------------------------------------
  707. private:
  708. BridgeAudioPool fShmAudioPool;
  709. BridgeRtControl fShmRtControl;
  710. BridgeNonRtControl fShmNonRtControl;
  711. bool fIsRunning;
  712. bool fIsOffline;
  713. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineBridge)
  714. };
  715. // -----------------------------------------------------------------------
  716. CarlaEngine* CarlaEngine::newBridge(const char* const audioPoolBaseName, const char* const rtBaseName, const char* const nonRtBaseName)
  717. {
  718. return new CarlaEngineBridge(audioPoolBaseName, rtBaseName, nonRtBaseName);
  719. }
  720. // -----------------------------------------------------------------------
  721. #ifdef BRIDGE_PLUGIN
  722. CarlaPlugin* CarlaPlugin::newNative(const CarlaPlugin::Initializer&) { return nullptr; }
  723. CarlaPlugin* CarlaPlugin::newFileGIG(const CarlaPlugin::Initializer&, const bool) { return nullptr; }
  724. CarlaPlugin* CarlaPlugin::newFileSF2(const CarlaPlugin::Initializer&, const bool) { return nullptr; }
  725. CarlaPlugin* CarlaPlugin::newFileSFZ(const CarlaPlugin::Initializer&) { return nullptr; }
  726. #endif
  727. CARLA_BACKEND_END_NAMESPACE
  728. // -----------------------------------------------------------------------
  729. #if defined(CARLA_OS_WIN) && ! defined(__WINE__)
  730. extern "C" __declspec (dllexport)
  731. #else
  732. extern "C" __attribute__ ((visibility("default")))
  733. #endif
  734. void carla_register_native_plugin_carla();
  735. void carla_register_native_plugin_carla(){}
  736. // -----------------------------------------------------------------------