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

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