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.

592 lines
15KB

  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. carla_debug("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. carla_debug("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 = 0x080; // 0.8.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. carla_debug("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. carla_stderr("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