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.

564 lines
15KB

  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. }