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