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.

364 lines
9.8KB

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