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.

595 lines
16KB

  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 = 0x100; // 1.0.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. }