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.

514 lines
13KB

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