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.

CarlaBridgeUI-VST.cpp 15KB

11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. /*
  2. * Carla Bridge UI, VST version
  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. #include "CarlaBridgeClient.hpp"
  18. #include "CarlaBridgeToolkit.hpp"
  19. #include "CarlaVstUtils.hpp"
  20. #include "CarlaMIDI.h"
  21. CARLA_BRIDGE_START_NAMESPACE
  22. // -------------------------------------------------------------------------
  23. // fake values
  24. uint32_t bufferSize = 512;
  25. double sampleRate = 44100.0;
  26. class CarlaVstClient : public CarlaBridgeClient
  27. {
  28. public:
  29. CarlaVstClient(const char* const uiTitle)
  30. : CarlaBridgeClient(uiTitle)
  31. {
  32. effect = nullptr;
  33. needIdle = false;
  34. // make client valid
  35. srand(uiTitle[0]);
  36. unique1 = unique2 = rand();
  37. }
  38. ~CarlaVstClient() override
  39. {
  40. // make client invalid
  41. unique2 += 1;
  42. }
  43. // ---------------------------------------------------------------------
  44. // ui initialization
  45. bool uiInit(const char* binary, const char*, const char*) override
  46. {
  47. // -----------------------------------------------------------------
  48. // init
  49. CarlaBridgeClient::uiInit(binary, nullptr, nullptr);
  50. // -----------------------------------------------------------------
  51. // open DLL
  52. if (! uiLibOpen(binary))
  53. {
  54. carla_stderr("%s", uiLibError());
  55. return false;
  56. }
  57. // -----------------------------------------------------------------
  58. // get DLL main entry
  59. VST_Function vstFn = (VST_Function)uiLibSymbol("VSTPluginMain");
  60. if (vstFn == nullptr)
  61. vstFn = (VST_Function)uiLibSymbol("main");
  62. if (vstFn == nullptr)
  63. return false;
  64. // -----------------------------------------------------------------
  65. // initialize plugin
  66. lastVstPlugin = this;
  67. effect = vstFn(hostCallback);
  68. lastVstPlugin = nullptr;
  69. if (! (effect && effect->magic == kEffectMagic))
  70. return false;
  71. // -----------------------------------------------------------------
  72. // initialize VST stuff
  73. #ifdef VESTIGE_HEADER
  74. effect->ptr1 = this;
  75. #else
  76. effect->resvd1 = ToVstPtr(this);
  77. #endif
  78. intptr_t value = 0;
  79. #if defined(HAVE_X11) && defined(BRIDGE_X11)
  80. value = (intptr_t)getContainerId2();
  81. #endif
  82. effect->dispatcher(effect, effOpen, 0, 0, nullptr, 0.0f);
  83. effect->dispatcher(effect, effMainsChanged, 0, 0, nullptr, 0.0f);
  84. #if ! VST_FORCE_DEPRECATED
  85. effect->dispatcher(effect, effSetBlockSizeAndSampleRate, 0, bufferSize, nullptr, sampleRate);
  86. #endif
  87. effect->dispatcher(effect, effSetSampleRate, 0, 0, nullptr, sampleRate);
  88. effect->dispatcher(effect, effSetBlockSize, 0, bufferSize, nullptr, 0.0f);
  89. effect->dispatcher(effect, effSetProcessPrecision, 0, kVstProcessPrecision32, nullptr, 0.0f);
  90. if (effect->dispatcher(effect, effEditOpen, 0, value, getContainerId(), 0.0f) != 1)
  91. {
  92. //effect->dispatcher(effect, effClose, 0, 0, nullptr, 0.0f);
  93. //return false;
  94. carla_stderr("VST UI failed to open, trying to init anyway...");
  95. }
  96. // -----------------------------------------------------------------
  97. // initialize gui stuff
  98. ERect* vstRect = nullptr;
  99. effect->dispatcher(effect, effEditGetRect, 0, 0, &vstRect, 0.0f);
  100. if (vstRect)
  101. {
  102. int width = vstRect->right - vstRect->left;
  103. int height = vstRect->bottom - vstRect->top;
  104. if (width > 0 && height > 0)
  105. toolkitResize(width, height);
  106. }
  107. return true;
  108. }
  109. void uiIdle() override
  110. {
  111. if (needIdle)
  112. effect->dispatcher(effect, effIdle, 0, 0, nullptr, 0.0f);
  113. effect->dispatcher(effect, effEditIdle, 0, 0, nullptr, 0.0f);
  114. }
  115. void uiClose() override
  116. {
  117. if (effect != nullptr)
  118. {
  119. effect->dispatcher(effect, effEditClose, 0, 0, nullptr, 0.0f);
  120. effect->dispatcher(effect, effClose, 0, 0, nullptr, 0.0f);
  121. effect = nullptr;
  122. }
  123. CarlaBridgeClient::uiClose();
  124. uiLibClose();
  125. }
  126. // ---------------------------------------------------------------------
  127. // ui management
  128. void* getWidget() const override
  129. {
  130. return nullptr; // VST always uses reparent
  131. }
  132. bool isResizable() const override
  133. {
  134. return false;
  135. }
  136. // ---------------------------------------------------------------------
  137. // ui processing
  138. void setParameter(const int32_t rindex, const float value) override
  139. {
  140. if (effect != nullptr)
  141. effect->setParameter(effect, rindex, value);
  142. }
  143. void setProgram(const uint32_t index) override
  144. {
  145. if (effect != nullptr)
  146. effect->dispatcher(effect, effSetProgram, 0, index, nullptr, 0.0f);
  147. }
  148. void setMidiProgram(const uint32_t, const uint32_t) override
  149. {
  150. }
  151. void noteOn(const uint8_t, const uint8_t, const uint8_t) override
  152. {
  153. }
  154. void noteOff(const uint8_t, const uint8_t) override
  155. {
  156. }
  157. // ---------------------------------------------------------------------
  158. void handleAudioMasterAutomate(const uint32_t index, const float value)
  159. {
  160. effect->setParameter(effect, index, value);
  161. if (isOscControlRegistered())
  162. sendOscControl(index, value);
  163. }
  164. intptr_t handleAudioMasterGetCurrentProcessLevel()
  165. {
  166. return kVstProcessLevelUser;
  167. }
  168. intptr_t handleAudioMasterGetBlockSize()
  169. {
  170. return bufferSize;
  171. }
  172. intptr_t handleAudioMasterGetSampleRate()
  173. {
  174. return sampleRate;
  175. }
  176. intptr_t handleAudioMasterGetTime()
  177. {
  178. memset(&vstTimeInfo, 0, sizeof(VstTimeInfo));
  179. vstTimeInfo.sampleRate = sampleRate;
  180. // Tempo
  181. vstTimeInfo.tempo = 120.0;
  182. vstTimeInfo.flags |= kVstTempoValid;
  183. // Time Signature
  184. vstTimeInfo.timeSigNumerator = 4;
  185. vstTimeInfo.timeSigDenominator = 4;
  186. vstTimeInfo.flags |= kVstTimeSigValid;
  187. return (intptr_t)&vstTimeInfo;
  188. }
  189. void handleAudioMasterNeedIdle()
  190. {
  191. needIdle = true;
  192. }
  193. intptr_t handleAudioMasterProcessEvents(const VstEvents* const vstEvents)
  194. {
  195. if (isOscControlRegistered())
  196. return 1;
  197. for (int32_t i=0; i < vstEvents->numEvents; ++i)
  198. {
  199. if (! vstEvents->events[i])
  200. break;
  201. const VstMidiEvent* const vstMidiEvent = (const VstMidiEvent*)vstEvents->events[i];
  202. if (vstMidiEvent->type != kVstMidiType)
  203. {
  204. uint8_t status = vstMidiEvent->midiData[0];
  205. // Fix bad note-off
  206. if (MIDI_IS_STATUS_NOTE_ON(status) && vstMidiEvent->midiData[2] == 0)
  207. status -= 0x10;
  208. uint8_t midiBuf[4] = { 0, status, (uint8_t)vstMidiEvent->midiData[1], (uint8_t)vstMidiEvent->midiData[2] };
  209. sendOscMidi(midiBuf);
  210. }
  211. }
  212. return 1;
  213. }
  214. intptr_t handleAdioMasterSizeWindow(int32_t width, int32_t height)
  215. {
  216. toolkitResize(width, height);
  217. return 1;
  218. }
  219. void handleAudioMasterUpdateDisplay()
  220. {
  221. if (isOscControlRegistered())
  222. sendOscConfigure("reloadprograms", "");
  223. }
  224. // ---------------------------------------------------------------------
  225. static intptr_t hostCanDo(const char* const feature)
  226. {
  227. carla_debug("CarlaVstClient::hostCanDo(\"%s\")", feature);
  228. if (std::strcmp(feature, "supplyIdle") == 0)
  229. return 1;
  230. if (std::strcmp(feature, "sendVstEvents") == 0)
  231. return 1;
  232. if (std::strcmp(feature, "sendVstMidiEvent") == 0)
  233. return 1;
  234. if (std::strcmp(feature, "sendVstMidiEventFlagIsRealtime") == 0)
  235. return -1;
  236. if (std::strcmp(feature, "sendVstTimeInfo") == 0)
  237. return 1;
  238. if (std::strcmp(feature, "receiveVstEvents") == 0)
  239. return 1;
  240. if (std::strcmp(feature, "receiveVstMidiEvent") == 0)
  241. return 1;
  242. if (std::strcmp(feature, "receiveVstTimeInfo") == 0)
  243. return -1;
  244. if (std::strcmp(feature, "reportConnectionChanges") == 0)
  245. return -1;
  246. if (std::strcmp(feature, "acceptIOChanges") == 0)
  247. return 1;
  248. if (std::strcmp(feature, "sizeWindow") == 0)
  249. return 1;
  250. if (std::strcmp(feature, "offline") == 0)
  251. return -1;
  252. if (std::strcmp(feature, "openFileSelector") == 0)
  253. return -1;
  254. if (std::strcmp(feature, "closeFileSelector") == 0)
  255. return -1;
  256. if (std::strcmp(feature, "startStopProcess") == 0)
  257. return 1;
  258. if (std::strcmp(feature, "supportShell") == 0)
  259. return -1;
  260. if (std::strcmp(feature, "shellCategory") == 0)
  261. return -1;
  262. // unimplemented
  263. carla_stderr("CarlaVstClient::hostCanDo(\"%s\") - unknown feature", feature);
  264. return 0;
  265. }
  266. static intptr_t VSTCALLBACK hostCallback(AEffect* const effect, const int32_t opcode, const int32_t index, const intptr_t value, void* const ptr, const float opt)
  267. {
  268. #if DEBUG
  269. carla_debug("CarlaVstClient::hostCallback(%p, %s, %i, " P_INTPTR ", %p, %f", effect, vstMasterOpcode2str(opcode), index, value, ptr, opt);
  270. #endif
  271. // Check if 'resvd1' points to this client, or register ourselfs if possible
  272. CarlaVstClient* self = nullptr;
  273. if (effect)
  274. {
  275. #ifdef VESTIGE_HEADER
  276. if (effect && effect->ptr1)
  277. {
  278. self = (CarlaVstClient*)effect->ptr1;
  279. #else
  280. if (effect && effect->resvd1)
  281. {
  282. self = FromVstPtr<CarlaVstClient>(effect->resvd1);
  283. #endif
  284. if (self->unique1 != self->unique2)
  285. self = nullptr;
  286. }
  287. if (self)
  288. {
  289. if (! self->effect)
  290. self->effect = effect;
  291. CARLA_ASSERT(self->effect == effect);
  292. if (self->effect != effect)
  293. {
  294. carla_stderr("CarlaVstClient::hostCallback() - host pointer mismatch: %p != %p", self->effect, effect);
  295. self = nullptr;
  296. }
  297. }
  298. else if (lastVstPlugin)
  299. {
  300. #ifdef VESTIGE_HEADER
  301. effect->ptr1 = lastVstPlugin;
  302. #else
  303. effect->resvd1 = ToVstPtr(lastVstPlugin);
  304. #endif
  305. self = lastVstPlugin;
  306. }
  307. }
  308. intptr_t ret = 0;
  309. switch (opcode)
  310. {
  311. case audioMasterAutomate:
  312. if (self)
  313. self->handleAudioMasterAutomate(index, opt);
  314. break;
  315. case audioMasterVersion:
  316. ret = kVstVersion;
  317. break;
  318. case audioMasterCurrentId:
  319. // TODO
  320. break;
  321. case audioMasterIdle:
  322. //if (effect)
  323. // effect->dispatcher(effect, effEditIdle, 0, 0, nullptr, 0.0f);
  324. break;
  325. case audioMasterGetTime:
  326. static VstTimeInfo timeInfo;
  327. memset(&timeInfo, 0, sizeof(VstTimeInfo));
  328. timeInfo.sampleRate = sampleRate;
  329. // Tempo
  330. timeInfo.tempo = 120.0;
  331. timeInfo.flags |= kVstTempoValid;
  332. // Time Signature
  333. timeInfo.timeSigNumerator = 4;
  334. timeInfo.timeSigDenominator = 4;
  335. timeInfo.flags |= kVstTimeSigValid;
  336. ret = (intptr_t)&timeInfo;
  337. break;
  338. case audioMasterProcessEvents:
  339. if (self && ptr)
  340. ret = self->handleAudioMasterProcessEvents((const VstEvents*)ptr);
  341. break;
  342. #if ! VST_FORCE_DEPRECATED
  343. case audioMasterTempoAt:
  344. // Deprecated in VST SDK 2.4
  345. ret = 120 * 10000;
  346. break;
  347. #endif
  348. case audioMasterSizeWindow:
  349. if (self && index > 0 && value > 0)
  350. ret = self->handleAdioMasterSizeWindow(index, value);
  351. break;
  352. case audioMasterGetSampleRate:
  353. ret = sampleRate;
  354. break;
  355. case audioMasterGetBlockSize:
  356. ret = bufferSize;
  357. break;
  358. case audioMasterGetCurrentProcessLevel:
  359. ret = kVstProcessLevelUser;
  360. break;
  361. case audioMasterGetAutomationState:
  362. ret = kVstAutomationReadWrite;
  363. break;
  364. case audioMasterGetVendorString:
  365. if (ptr)
  366. std::strcpy((char*)ptr, "falkTX");
  367. break;
  368. case audioMasterGetProductString:
  369. if (ptr)
  370. std::strcpy((char*)ptr, "Carla-Bridge");
  371. break;
  372. case audioMasterGetVendorVersion:
  373. ret = 0x110; // 1.1.0
  374. break;
  375. case audioMasterCanDo:
  376. if (ptr)
  377. ret = hostCanDo((const char*)ptr);
  378. break;
  379. case audioMasterGetLanguage:
  380. ret = kVstLangEnglish;
  381. break;
  382. case audioMasterUpdateDisplay:
  383. if (self)
  384. self->handleAudioMasterUpdateDisplay();
  385. break;
  386. default:
  387. #ifdef DEBUG
  388. carla_debug("CarlaVstClient::hostCallback(%p, %s, %i, " P_INTPTR ", %p, %f", effect, vstMasterOpcode2str(opcode), index, value, ptr, opt);
  389. #endif
  390. break;
  391. }
  392. return ret;
  393. }
  394. private:
  395. int unique1;
  396. AEffect* effect;
  397. VstTimeInfo vstTimeInfo;
  398. bool needIdle;
  399. static CarlaVstClient* lastVstPlugin;
  400. int unique2;
  401. };
  402. CarlaVstClient* CarlaVstClient::lastVstPlugin = nullptr;
  403. // -------------------------------------------------------------------------
  404. CARLA_BRIDGE_END_NAMESPACE
  405. int main(int argc, char* argv[])
  406. {
  407. CARLA_BRIDGE_USE_NAMESPACE
  408. if (argc != 4)
  409. {
  410. carla_stderr("usage: %s <osc-url|\"null\"> <binary> <ui-title>", argv[0]);
  411. return 1;
  412. }
  413. const char* oscUrl = argv[1];
  414. const char* binary = argv[2];
  415. const char* uiTitle = argv[3];
  416. const bool useOsc = std::strcmp(oscUrl, "null");
  417. // try to get sampleRate value
  418. if (const char* const sampleRateStr = std::getenv("CARLA_SAMPLE_RATE"))
  419. sampleRate = std::atof(sampleRateStr);
  420. // Init VST client
  421. CarlaVstClient client(uiTitle);
  422. // Init OSC
  423. if (useOsc)
  424. {
  425. client.oscInit(oscUrl);
  426. client.sendOscUpdate();
  427. }
  428. // Load UI
  429. int ret;
  430. if (client.uiInit(binary, nullptr, nullptr))
  431. {
  432. client.toolkitExec(!useOsc);
  433. ret = 0;
  434. }
  435. else
  436. {
  437. carla_stderr("Failed to load VST UI");
  438. ret = 1;
  439. }
  440. // Close OSC
  441. if (useOsc)
  442. client.oscClose();
  443. // Close VST client
  444. client.uiClose();
  445. return ret;
  446. }