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