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 32KB

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