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.

408 lines
11KB

  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 <QtGui/QDialog>
  22. CARLA_BRIDGE_START_NAMESPACE
  23. // -------------------------------------------------------------------------
  24. #define FAKE_SAMPLE_RATE 44100.0
  25. #define FAKE_BUFFER_SIZE 512
  26. void* getPointer(const quintptr addr)
  27. {
  28. Q_ASSERT(addr != 0);
  29. qDebug("getPointer(" P_UINTPTR ")", addr);
  30. quintptr* const ptr = (quintptr*)addr;
  31. return (void*)ptr;
  32. }
  33. class CarlaVstClient : public CarlaClient
  34. {
  35. public:
  36. CarlaVstClient(CarlaToolkit* const toolkit)
  37. : CarlaClient(toolkit)
  38. {
  39. effect = nullptr;
  40. widget = new QDialog;
  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. return false;
  57. // -----------------------------------------------------------------
  58. // get DLL main entry
  59. VST_Function vstfn = (VST_Function)libSymbol("VSTPluginMain");
  60. if (! vstfn)
  61. vstfn = (VST_Function)libSymbol("main");
  62. if (! vstfn)
  63. return false;
  64. // -----------------------------------------------------------------
  65. // initialize plugin
  66. effect = vstfn(VstHostCallback);
  67. if ((! effect) || effect->magic != kEffectMagic)
  68. return false;
  69. // -----------------------------------------------------------------
  70. // initialize VST stuff
  71. effect->dispatcher(effect, effOpen, 0, 0, nullptr, 0.0f);
  72. #if ! VST_FORCE_DEPRECATED
  73. effect->dispatcher(effect, effSetBlockSizeAndSampleRate, 0, FAKE_BUFFER_SIZE, nullptr, FAKE_SAMPLE_RATE);
  74. #endif
  75. effect->dispatcher(effect, effSetSampleRate, 0, 0, nullptr, FAKE_SAMPLE_RATE);
  76. effect->dispatcher(effect, effSetBlockSize, 0, FAKE_BUFFER_SIZE, nullptr, 0.0f);
  77. effect->dispatcher(effect, effEditOpen, 0, 0, (void*)widget->winId(), 0.0f);
  78. #ifdef VESTIGE_HEADER
  79. effect->ptr1 = this;
  80. #else
  81. effect->resvd1 = (intptr_t)this;
  82. #endif
  83. // -----------------------------------------------------------------
  84. // initialize gui stuff
  85. ERect* vstRect = nullptr;
  86. if (effect->dispatcher(effect, effEditGetRect, 0, 0, &vstRect, 0.0f) && vstRect)
  87. {
  88. int width = vstRect->right - vstRect->left;
  89. int height = vstRect->bottom - vstRect->top;
  90. widget->setFixedSize(width, height);
  91. //return true;
  92. }
  93. return true;
  94. //return false;
  95. }
  96. void close()
  97. {
  98. if (effect)
  99. {
  100. effect->dispatcher(effect, effEditClose, 0, 0, nullptr, 0.0f);
  101. effect->dispatcher(effect, effClose, 0, 0, nullptr, 0.0f);
  102. }
  103. }
  104. // ---------------------------------------------------------------------
  105. // processing
  106. void setParameter(const int32_t rindex, const double value)
  107. {
  108. if (effect)
  109. effect->setParameter(effect, rindex, value);
  110. }
  111. void setProgram(const uint32_t index)
  112. {
  113. if (effect)
  114. effect->dispatcher(effect, effSetProgram, 0, index, nullptr, 0.0f);
  115. }
  116. void setMidiProgram(const uint32_t, const uint32_t)
  117. {
  118. }
  119. void noteOn(const uint8_t, const uint8_t, const uint8_t)
  120. {
  121. }
  122. void noteOff(const uint8_t, const uint8_t)
  123. {
  124. }
  125. // ---------------------------------------------------------------------
  126. // gui
  127. void* getWidget() const
  128. {
  129. return widget;
  130. }
  131. bool isResizable() const
  132. {
  133. return false;
  134. }
  135. bool needsReparent() const
  136. {
  137. return true;
  138. }
  139. // ---------------------------------------------------------------------
  140. static intptr_t VstHostCallback(AEffect* effect, int32_t opcode, int32_t index, intptr_t value, void* ptr, float opt)
  141. {
  142. // Check if 'resvd1' points to this client
  143. CarlaVstClient* self = nullptr;
  144. #ifdef VESTIGE_HEADER
  145. if (effect && effect->ptr1)
  146. {
  147. self = (CarlaVstClient*)effect->ptr1;
  148. #else
  149. if (effect && effect->resvd1)
  150. {
  151. self = (CarlaVstClient*)getPointer(effect->resvd1);
  152. #endif
  153. if (self->unique1 != self->unique2)
  154. self = nullptr;
  155. }
  156. switch (opcode)
  157. {
  158. case audioMasterAutomate:
  159. if (self)
  160. self->sendOscControl(index, opt);
  161. break;
  162. case audioMasterVersion:
  163. return kVstVersion;
  164. case audioMasterCurrentId:
  165. return 0; // TODO
  166. case audioMasterIdle:
  167. if (effect)
  168. effect->dispatcher(effect, effEditIdle, 0, 0, nullptr, 0.0f);
  169. break;
  170. case audioMasterGetTime:
  171. static VstTimeInfo_R timeInfo;
  172. memset(&timeInfo, 0, sizeof(VstTimeInfo_R));
  173. timeInfo.sampleRate = FAKE_SAMPLE_RATE;
  174. return (intptr_t)&timeInfo;
  175. case audioMasterProcessEvents:
  176. #if 0
  177. if (client && ptr)
  178. {
  179. const VstEvents* const events = (VstEvents*)ptr;
  180. for (int32_t i=0; i < events->numEvents; i++)
  181. {
  182. const VstMidiEvent* const midi_event = (VstMidiEvent*)events->events[i];
  183. uint8_t status = midi_event->midiData[0];
  184. // Fix bad note-off
  185. if (MIDI_IS_STATUS_NOTE_ON(status) && midi_event->midiData[2] == 0)
  186. status -= 0x10;
  187. uint8_t midi_buf[4] = { 0, status, (uint8_t)midi_event->midiData[1], (uint8_t)midi_event->midiData[2] };
  188. osc_send_midi(midi_buf);
  189. }
  190. }
  191. else
  192. qDebug("VstHostCallback:audioMasterProcessEvents - Some MIDI Out events were ignored");
  193. #endif
  194. break;
  195. #if ! VST_FORCE_DEPRECATED
  196. case audioMasterTempoAt:
  197. // Deprecated in VST SDK 2.4
  198. return 120.0 * 10000;
  199. #endif
  200. case audioMasterSizeWindow:
  201. if (self)
  202. self->quequeMessage(MESSAGE_RESIZE_GUI, index, value, 0.0);
  203. return 1;
  204. case audioMasterGetSampleRate:
  205. return FAKE_SAMPLE_RATE;
  206. case audioMasterGetBlockSize:
  207. return FAKE_BUFFER_SIZE;
  208. case audioMasterGetVendorString:
  209. strcpy((char*)ptr, "Cadence");
  210. break;
  211. case audioMasterGetProductString:
  212. strcpy((char*)ptr, "Carla-Bridge");
  213. break;
  214. case audioMasterGetVendorVersion:
  215. return 0x05; // 0.5
  216. case audioMasterVendorSpecific:
  217. break;
  218. case audioMasterCanDo:
  219. #if DEBUG
  220. qDebug("VstHostCallback:audioMasterCanDo - %s", (char*)ptr);
  221. #endif
  222. if (strcmp((char*)ptr, "supplyIdle") == 0)
  223. return 1;
  224. if (strcmp((char*)ptr, "sendVstEvents") == 0)
  225. return 1;
  226. if (strcmp((char*)ptr, "sendVstMidiEvent") == 0)
  227. return 1;
  228. if (strcmp((char*)ptr, "sendVstMidiEventFlagIsRealtime") == 0)
  229. return -1;
  230. if (strcmp((char*)ptr, "sendVstTimeInfo") == 0)
  231. return 1;
  232. if (strcmp((char*)ptr, "receiveVstEvents") == 0)
  233. return 1;
  234. if (strcmp((char*)ptr, "receiveVstMidiEvent") == 0)
  235. return 1;
  236. if (strcmp((char*)ptr, "receiveVstTimeInfo") == 0)
  237. return -1;
  238. if (strcmp((char*)ptr, "reportConnectionChanges") == 0)
  239. return -1;
  240. if (strcmp((char*)ptr, "acceptIOChanges") == 0)
  241. return 1;
  242. if (strcmp((char*)ptr, "sizeWindow") == 0)
  243. return 1;
  244. if (strcmp((char*)ptr, "offline") == 0)
  245. return -1;
  246. if (strcmp((char*)ptr, "openFileSelector") == 0)
  247. return -1;
  248. if (strcmp((char*)ptr, "closeFileSelector") == 0)
  249. return -1;
  250. if (strcmp((char*)ptr, "startStopProcess") == 0)
  251. return 1;
  252. if (strcmp((char*)ptr, "supportShell") == 0)
  253. return -1;
  254. if (strcmp((char*)ptr, "shellCategory") == 0)
  255. return -1;
  256. // unimplemented
  257. qWarning("VstHostCallback:audioMasterCanDo - Got unknown feature request '%s'", (char*)ptr);
  258. return 0;
  259. case audioMasterGetLanguage:
  260. return kVstLangEnglish;
  261. case audioMasterUpdateDisplay:
  262. if (self)
  263. self->sendOscConfigure("reloadprograms", "");
  264. break;
  265. default:
  266. #if DEBUG
  267. qDebug("VstHostCallback() - code: %s, index: %i, value: " P_INTPTR ", opt: %f", VstMasterOpcode2str(opcode), index, value, opt);
  268. #endif
  269. break;
  270. }
  271. return 0;
  272. }
  273. private:
  274. int unique1;
  275. AEffect* effect;
  276. QDialog* widget;
  277. int unique2;
  278. };
  279. CARLA_BRIDGE_END_NAMESPACE
  280. int main(int argc, char* argv[])
  281. {
  282. if (argc != 4)
  283. {
  284. qCritical("%s: bad arguments", argv[0]);
  285. return 1;
  286. }
  287. const char* osc_url = argv[1];
  288. const char* binary = argv[2];
  289. const char* ui_title = argv[3];
  290. using namespace CarlaBridge;
  291. // Init toolkit
  292. CarlaToolkit* const toolkit = CarlaToolkit::createNew(ui_title);
  293. toolkit->init();
  294. // Init VST-UI
  295. CarlaVstClient client(toolkit);
  296. // Init OSC
  297. if (! client.oscInit(osc_url))
  298. {
  299. toolkit->quit();
  300. delete toolkit;
  301. return -1;
  302. }
  303. // Load UI
  304. int ret;
  305. if (client.init(binary, nullptr))
  306. {
  307. toolkit->exec(&client);
  308. ret = 0;
  309. }
  310. else
  311. {
  312. qCritical("Failed to load VST UI");
  313. ret = 1;
  314. }
  315. // Close OSC
  316. client.sendOscExiting();
  317. client.oscClose();
  318. // Close VST-UI
  319. client.close();
  320. // Close toolkit
  321. toolkit->quit();
  322. delete toolkit;
  323. return ret;
  324. }
  325. #endif