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.

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