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.

CarlaEngineBridge.cpp 31KB

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