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.

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