Collection of tools useful for audio production
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.

518 lines
13KB

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