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.

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