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.

692 lines
21KB

  1. #define USE_LGLW defined
  2. #include <aeffect.h>
  3. #include <aeffectx.h>
  4. #include <stdio.h>
  5. #if defined(_WIN32) || defined(_WIN64)
  6. #include <windows.h>
  7. #include <wingdi.h>
  8. #define VST_EXPORT extern "C" __declspec(dllexport)
  9. #else
  10. #include <GL/gl.h>
  11. #include <X11/Xlib.h>
  12. #include <X11/Xutil.h>
  13. #include <X11/Xos.h>
  14. #define VST_EXPORT extern
  15. #include <dlfcn.h>
  16. #endif
  17. #include "lglw.h"
  18. #define EDITWIN_X 20
  19. #define EDITWIN_Y 20
  20. #define EDITWIN_W 640
  21. #define EDITWIN_H 480
  22. /*
  23. * I find the naming a bit confusing so I decided to use more meaningful names instead.
  24. */
  25. /**
  26. * The VSTHostCallback is a function pointer so that the plugin can communicate with the host (not used in this small example)
  27. */
  28. typedef audioMasterCallback VSTHostCallback;
  29. /**
  30. * The VSTPlugin structure (AEffect) contains information about the plugin (like version, number of inputs, ...) and
  31. * callbacks so that the host can call the plugin to do its work. The primary callback will be `processReplacing` for
  32. * single precision (float) sample processing (or `processDoubleReplacing` for double precision (double)).
  33. */
  34. typedef AEffect VSTPlugin;
  35. // Since the host is expecting a very specific API we need to make sure it has C linkage (not C++)
  36. extern "C" {
  37. /*
  38. * This is the main entry point to the VST plugin.
  39. *
  40. * The host (DAW like Maschine, Ableton Live, Reason, ...) will look for this function with this exact API.
  41. *
  42. * It is the equivalent to `int main(int argc, char *argv[])` for a C executable.
  43. *
  44. * @param vstHostCallback is a callback so that the plugin can communicate with the host (not used in this small example)
  45. * @return a pointer to the AEffect structure
  46. */
  47. VST_EXPORT VSTPlugin *VSTPluginMain(VSTHostCallback vstHostCallback);
  48. // note this looks like this without the type aliases (and is obviously 100% equivalent)
  49. // extern AEffect *VSTPluginMain(audioMasterCallback audioMaster);
  50. }
  51. /*
  52. * Constant for the version of the plugin. For example 1100 for version 1.1.0.0
  53. */
  54. const VstInt32 PLUGIN_VERSION = 1000;
  55. // extern "C" LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
  56. #ifdef USE_LGLW
  57. extern "C" {
  58. static void loc_mouse_cbk(lglw_t _lglw, int32_t _x, int32_t _y, uint32_t _buttonState, uint32_t _changedButtonState) {
  59. printf("vstgltest: lglw_mouse_cbk: lglw=%p p=(%d; %d) bt=0x%08x changedBt=0x%08x\n", _lglw, _x, _y, _buttonState, _changedButtonState);
  60. if(LGLW_IS_MOUSE_LBUTTON_DOWN())
  61. {
  62. // lglw_mouse_grab(_lglw, LGLW_MOUSE_GRAB_CAPTURE);
  63. lglw_mouse_grab(_lglw, LGLW_MOUSE_GRAB_WARP);
  64. }
  65. else if(LGLW_IS_MOUSE_LBUTTON_UP())
  66. {
  67. lglw_mouse_ungrab(_lglw);
  68. }
  69. }
  70. static void loc_focus_cbk(lglw_t _lglw, uint32_t _focusState, uint32_t _changedFocusState) {
  71. printf("vstgltest: lglw_focus_cbk: lglw=%p focusState=0x%08x changedFocusState=0x%08x\n", _lglw, _focusState, _changedFocusState);
  72. }
  73. static lglw_bool_t loc_keyboard_cbk(lglw_t _lglw, uint32_t _vkey, uint32_t _kmod, lglw_bool_t _bPressed) {
  74. printf("vstgltest: lglw_keyboard_cbk: lglw=%p vkey=0x%08x (\'%c\') kmod=0x%08x bPressed=%d\n", _lglw, _vkey, _vkey, _kmod, _bPressed);
  75. return LGLW_FALSE;
  76. }
  77. static void loc_timer_cbk(lglw_t _lglw) {
  78. printf("vstgltest: lglw_timer_cbk: tick\n");
  79. }
  80. static void loc_redraw_cbk (lglw_t _lglw);
  81. }
  82. #endif // USE_LGLW
  83. /**
  84. * Encapsulates the plugin as a C++ class. It will keep both the host callback and the structure required by the
  85. * host (VSTPlugin). This class will be stored in the `VSTPlugin.object` field (circular reference) so that it can
  86. * be accessed when the host calls the plugin back (for example in `processDoubleReplacing`).
  87. */
  88. class VSTPluginWrapper
  89. {
  90. public:
  91. ERect editor_rect;
  92. #ifdef USE_LGLW
  93. lglw_t lglw;
  94. #endif // USE_LGLW
  95. float clear_color = 0.0f;
  96. static VSTPluginWrapper *window_to_wrapper;
  97. public:
  98. VSTPluginWrapper(VSTHostCallback vstHostCallback,
  99. VstInt32 vendorUniqueID,
  100. VstInt32 vendorVersion,
  101. VstInt32 numParams,
  102. VstInt32 numPrograms,
  103. VstInt32 numInputs,
  104. VstInt32 numOutputs);
  105. ~VSTPluginWrapper();
  106. inline VSTPlugin *getVSTPlugin()
  107. {
  108. return &_vstPlugin;
  109. }
  110. inline VstInt32 getNumInputs() const
  111. {
  112. return _vstPlugin.numInputs;
  113. }
  114. inline VstInt32 getNumOutputs() const
  115. {
  116. return _vstPlugin.numOutputs;
  117. }
  118. int openEffect(void) {
  119. printf("vstgltest: openEffect()\n");
  120. return 1;
  121. }
  122. void closeEffect(void) {
  123. closeEditor();
  124. }
  125. void openEditor(void *_hwnd) {
  126. #ifdef USE_LGLW
  127. (void)lglw_window_open(lglw, _hwnd, 0/*x*/, 0/*y*/, EDITWIN_W, EDITWIN_H);
  128. lglw_mouse_callback_set(lglw, &loc_mouse_cbk);
  129. lglw_focus_callback_set(lglw, &loc_focus_cbk);
  130. lglw_keyboard_callback_set(lglw, &loc_keyboard_cbk);
  131. lglw_timer_callback_set(lglw, &loc_timer_cbk);
  132. lglw_redraw_callback_set(lglw, &loc_redraw_cbk);
  133. lglw_timer_start(lglw, 200);
  134. #endif // USE_LGLW
  135. window_to_wrapper = this;
  136. }
  137. void closeEditor(void) {
  138. if(NULL != window_to_wrapper)
  139. {
  140. #ifdef USE_LGLW
  141. lglw_window_close(lglw);
  142. #endif // USE_LGLW
  143. window_to_wrapper = NULL;
  144. }
  145. }
  146. static VSTPluginWrapper *FindWrapperByWindow(Window hwnd) {
  147. return window_to_wrapper;
  148. }
  149. void redrawWindow(void) {
  150. #if 1
  151. #ifdef USE_LGLW
  152. printf("vstgltest: redrawWindow()\n");
  153. // Save host GL context
  154. lglw_glcontext_push(lglw);
  155. // Draw something
  156. ::glClearColor(0.0, 1.0, clear_color, 1.0);
  157. clear_color += 0.05f;
  158. if(clear_color >= 1.0f)
  159. clear_color -= 1.0f;
  160. ::glClear(GL_COLOR_BUFFER_BIT);
  161. ::glFlush();
  162. lglw_swap_buffers(lglw);
  163. // Restore host GL context
  164. lglw_glcontext_pop(lglw);
  165. #endif // USE_LGLW
  166. #endif
  167. }
  168. private:
  169. // the host callback (a function pointer)
  170. VSTHostCallback _vstHostCallback;
  171. // the actual structure required by the host
  172. VSTPlugin _vstPlugin;
  173. };
  174. VSTPluginWrapper *VSTPluginWrapper::window_to_wrapper = NULL;
  175. /*******************************************
  176. * Callbacks: Host -> Plugin
  177. *
  178. * Defined here because they are used in the rest of the code later
  179. */
  180. /**
  181. * This is the callback that will be called to process the samples in the case of single precision. This is where the
  182. * meat of the logic happens!
  183. *
  184. * @param vstPlugin the object returned by VSTPluginMain
  185. * @param inputs an array of array of input samples. You read from it. First dimension is for inputs, second dimension is for samples: inputs[numInputs][sampleFrames]
  186. * @param outputs an array of array of output samples. You write to it. First dimension is for outputs, second dimension is for samples: outputs[numOuputs][sampleFrames]
  187. * @param sampleFrames the number of samples (second dimension in both arrays)
  188. */
  189. extern "C" {
  190. void VSTPluginProcessSamplesFloat32(VSTPlugin *vstPlugin, float **inputs, float **outputs, VstInt32 sampleFrames)
  191. {
  192. // we can get a hold to our C++ class since we stored it in the `object` field (see constructor)
  193. VSTPluginWrapper *wrapper = static_cast<VSTPluginWrapper *>(vstPlugin->object);
  194. // code speaks for itself: for each input (2 when stereo input), iterating over every sample and writing the
  195. // result in the outputs array after multiplying by 0.5 (which result in a 3dB attenuation of the sound)
  196. for(int i = 0; i < wrapper->getNumInputs(); i++)
  197. {
  198. auto inputSamples = inputs[i];
  199. auto outputSamples = outputs[i];
  200. for(int j = 0; j < sampleFrames; j++)
  201. {
  202. outputSamples[j] = inputSamples[j] * 0.5f;
  203. }
  204. }
  205. }
  206. }
  207. /**
  208. * This is the callback that will be called to process the samples in the case of double precision. This is where the
  209. * meat of the logic happens!
  210. *
  211. * @param vstPlugin the object returned by VSTPluginMain
  212. * @param inputs an array of array of input samples. You read from it. First dimension is for inputs, second dimension is for samples: inputs[numInputs][sampleFrames]
  213. * @param outputs an array of array of output samples. You write to it. First dimension is for outputs, second dimension is for samples: outputs[numOuputs][sampleFrames]
  214. * @param sampleFrames the number of samples (second dimension in both arrays)
  215. */
  216. extern "C" {
  217. void VSTPluginProcessSamplesFloat64(VSTPlugin *vstPlugin, double **inputs, double **outputs, VstInt32 sampleFrames)
  218. {
  219. // we can get a hold to our C++ class since we stored it in the `object` field (see constructor)
  220. VSTPluginWrapper *wrapper = static_cast<VSTPluginWrapper *>(vstPlugin->object);
  221. // code speaks for itself: for each input (2 when stereo input), iterating over every sample and writing the
  222. // result in the outputs array after multiplying by 0.5 (which result in a 3dB attenuation of the sound)
  223. for(int i = 0; i < wrapper->getNumInputs(); i++)
  224. {
  225. auto inputSamples = inputs[i];
  226. auto outputSamples = outputs[i];
  227. for(int j = 0; j < sampleFrames; j++)
  228. {
  229. outputSamples[j] = inputSamples[j] * 0.5;
  230. }
  231. }
  232. }
  233. }
  234. /**
  235. * This is the plugin called by the host to communicate with the plugin, mainly to request information (like the
  236. * vendor string, the plugin category...) or communicate state/changes (like open/close, frame rate...)
  237. *
  238. * @param vstPlugin the object returned by VSTPluginMain
  239. * @param opCode defined in aeffect.h/AEffectOpcodes and which continues in aeffectx.h/AEffectXOpcodes for a grand
  240. * total of 79 of them! Only a few of them are implemented in this small plugin.
  241. * @param index depend on the opcode
  242. * @param value depend on the opcode
  243. * @param ptr depend on the opcode
  244. * @param opt depend on the opcode
  245. * @return depend on the opcode (0 is ok when you don't implement an opcode...)
  246. */
  247. extern "C" {
  248. VstIntPtr VSTPluginDispatcher(VSTPlugin *vstPlugin, VstInt32 opCode, VstInt32 index, VstIntPtr value, void *ptr, float opt)
  249. {
  250. // printf("vstgltest: called VSTPluginDispatcher(%d)\n", opCode);
  251. VstIntPtr r = 0;
  252. // we can get a hold to our C++ class since we stored it in the `object` field (see constructor)
  253. VSTPluginWrapper *wrapper = static_cast<VSTPluginWrapper *>(vstPlugin->object);
  254. // see aeffect.h/AEffectOpcodes and aeffectx.h/AEffectXOpcodes for details on all of them
  255. switch(opCode)
  256. {
  257. default:
  258. printf("vstgltest: unhandled VSTPluginDispatcher opcode=%d\n", opCode);
  259. break;
  260. case effGetVstVersion: /*58*/
  261. r = 0;
  262. break;
  263. // request for the category of the plugin: in this case it is an effect since it is modifying the input (as opposed
  264. // to generating sound)
  265. case effGetPlugCategory:
  266. // return kPlugCategEffect;
  267. return kPlugCategSynth;
  268. case effOpen:
  269. // called by the host after it has obtained the effect instance (but _not_ during plugin scans)
  270. // (note) any heavy-lifting init code should go here
  271. printf("vstgltest: effOpen\n");
  272. r = wrapper->openEffect();
  273. break;
  274. // called by the host when the plugin was called... time to reclaim memory!
  275. case effClose:
  276. printf("vstgltest: effClose\n");
  277. wrapper->closeEffect();
  278. delete wrapper;
  279. break;
  280. case effGetEffectName:
  281. ::strncpy((char*)ptr, "VST GL Test", kVstMaxEffectNameLen);
  282. r = 1;
  283. break;
  284. case effGetProductString:
  285. ::strncpy((char*)ptr, "VST GL Test ProdStr", kVstMaxProductStrLen);
  286. r = 1;
  287. break;
  288. // request for the vendor string (usually used in the UI for plugin grouping)
  289. case effGetVendorString:
  290. strncpy(static_cast<char *>(ptr), "bsp", kVstMaxVendorStrLen);
  291. r = 1;
  292. break;
  293. // request for the version
  294. case effGetVendorVersion:
  295. return PLUGIN_VERSION;
  296. case effGetNumMidiInputChannels:
  297. r = 16;
  298. break;
  299. case effGetNumMidiOutputChannels:
  300. r = 0;
  301. break;
  302. case effCanDo:
  303. // ptr:
  304. // "sendVstEvents"
  305. // "sendVstMidiEvent"
  306. // "sendVstTimeInfo"
  307. // "receiveVstEvents"
  308. // "receiveVstMidiEvent"
  309. // "receiveVstTimeInfo"
  310. // "offline"
  311. // "plugAsChannelInsert"
  312. // "plugAsSend"
  313. // "mixDryWet"
  314. // "noRealTime"
  315. // "multipass"
  316. // "metapass"
  317. // "1in1out"
  318. // "1in2out"
  319. // "2in1out"
  320. // "2in2out"
  321. // "2in4out"
  322. // "4in2out"
  323. // "4in4out"
  324. // "4in8out"
  325. // "8in4out"
  326. // "8in8out"
  327. // "midiProgramNames"
  328. // "conformsToWindowRules"
  329. if(!strcmp((char*)ptr, "receiveVstEvents"))
  330. r = 1;
  331. else if(!strcmp((char*)ptr, "receiveVstMidiEvent")) // (note) required by Jeskola Buzz
  332. r = 1;
  333. else if(!strcmp((char*)ptr, "noRealTime"))
  334. r = 1;
  335. else
  336. r = 0;
  337. break;
  338. case effGetInputProperties:
  339. {
  340. VstPinProperties *pin = (VstPinProperties*)ptr;
  341. ::snprintf(pin->label, kVstMaxLabelLen, "Input #%d", index);
  342. pin->flags = kVstPinIsActive | ((0 == (index & 1)) ? kVstPinIsStereo : 0);
  343. pin->arrangementType = ((0 == (index & 1)) ? kSpeakerArrStereo : kSpeakerArrMono);
  344. ::snprintf(pin->shortLabel, kVstMaxShortLabelLen, "in%d", index);
  345. memset((void*)pin->future, 0, 48);
  346. r = 1;
  347. }
  348. break;
  349. case effGetOutputProperties:
  350. {
  351. VstPinProperties *pin = (VstPinProperties*)ptr;
  352. ::snprintf(pin->label, kVstMaxLabelLen, "Output #%d", index);
  353. pin->flags = kVstPinIsActive | ((0 == (index & 1)) ? kVstPinIsStereo : 0);
  354. pin->arrangementType = ((0 == (index & 1)) ? kSpeakerArrStereo : kSpeakerArrMono);
  355. ::snprintf(pin->shortLabel, kVstMaxShortLabelLen, "out%d", index);
  356. memset((void*)pin->future, 0, 48);
  357. r = 1;
  358. }
  359. break;
  360. case effSetSampleRate:
  361. printf("vstgltest: effSetSampleRate(%f)\n", opt);
  362. r = 1;////wrapper->setSampleRate(opt) ? 1 : 0;
  363. break;
  364. case effSetBlockSize:
  365. printf("vstgltest: effSetBlockSize(%u)\n", uint32_t(value));
  366. r = 1;////wrapper->setBlockSize(uint32_t(value)) ? 1 : 0;
  367. break;
  368. case effMainsChanged:
  369. printf("vstgltest: effMainsChanged(%ld)\n", value);
  370. // value = 0=suspend, 1=resume
  371. // wrapper->setEnableProcessingActive((value > 0) ? true : false);
  372. r = 1;
  373. break;
  374. case effSetProgram:
  375. r = 1;
  376. break;
  377. case effGetProgram:
  378. r = 0;
  379. break;
  380. case effGetProgramName:
  381. ::snprintf((char*)ptr, kVstMaxProgNameLen, "default");
  382. r = 1;
  383. break;
  384. case effSetProgramName:
  385. r = 1;
  386. break;
  387. case effGetProgramNameIndexed:
  388. ::sprintf((char*)ptr, "default");
  389. r = 1;
  390. break;
  391. case effGetParamName:
  392. strncpy(static_cast<char *>(ptr), "myparam", kVstMaxParamStrLen);
  393. r = 1;
  394. break;
  395. case effCanBeAutomated:
  396. // fix Propellerhead Reason VST parameter support
  397. r = 1;
  398. break;
  399. case effStartProcess:
  400. r = 1;
  401. break;
  402. case effStopProcess:
  403. r = 1;
  404. break;
  405. case effEditIdle:
  406. // printf("vstgltest: redraw window\n");
  407. // (void)::RedrawWindow(wrapper->hwnd, NULL, NULL, RDW_INTERNALPAINT);
  408. //(void)::UpdateWindow(wrapper->hwnd);
  409. #ifdef USE_LGLW
  410. if(lglw_window_is_visible(wrapper->lglw))
  411. {
  412. wrapper->redrawWindow();
  413. }
  414. #endif // USE_LGLW
  415. break;
  416. case effEditGetRect:
  417. // Query editor window geometry
  418. // ptr: ERect* (on Windows)
  419. if(NULL != ptr) // yeah, this should never be NULL
  420. {
  421. // ...
  422. wrapper->editor_rect.left = EDITWIN_X;
  423. wrapper->editor_rect.top = EDITWIN_Y;
  424. wrapper->editor_rect.right = EDITWIN_X + EDITWIN_W;
  425. wrapper->editor_rect.bottom = EDITWIN_Y + EDITWIN_H;
  426. *(void**)ptr = (void*) &wrapper->editor_rect;
  427. r = 1;
  428. }
  429. else
  430. {
  431. r = 0;
  432. }
  433. break;
  434. #if 0
  435. case effEditTop:
  436. // deprecated in vst2.4
  437. r = 0;
  438. break;
  439. #endif
  440. case effEditOpen:
  441. // Show editor window
  442. // ptr: native window handle (hWnd on Windows)
  443. wrapper->openEditor(ptr);
  444. r = 1;
  445. break;
  446. case effEditClose:
  447. // Hide editor window
  448. wrapper->closeEditor();
  449. r = 1;
  450. break;
  451. }
  452. return r;
  453. }
  454. }
  455. /**
  456. * Used for parameter setting (not used by this plugin)
  457. */
  458. extern "C" {
  459. void VSTPluginSetParameter(VSTPlugin *vstPlugin, VstInt32 index, float parameter)
  460. {
  461. printf("vstgltest: VSTPluginSetParameter(%d, %f)\n", index, parameter);
  462. // we can get a hold to our C++ class since we stored it in the `object` field (see constructor)
  463. VSTPluginWrapper *wrapper = static_cast<VSTPluginWrapper *>(vstPlugin->object);
  464. (void)wrapper;
  465. }
  466. }
  467. /**
  468. * Used for parameter (not used by this plugin)
  469. */
  470. extern "C" {
  471. float VSTPluginGetParameter(VSTPlugin *vstPlugin, VstInt32 index)
  472. {
  473. printf("vstgltest: VSTPluginGetParameter(%d)\n", index);
  474. // we can get a hold to our C++ class since we stored it in the `object` field (see constructor)
  475. VSTPluginWrapper *wrapper = static_cast<VSTPluginWrapper *>(vstPlugin->object);
  476. (void)wrapper;
  477. return 0;
  478. }
  479. }
  480. extern "C" {
  481. static void loc_redraw_cbk(lglw_t _lglw) {
  482. VSTPluginWrapper *wrapper = (VSTPluginWrapper*)lglw_userdata_get(_lglw);
  483. wrapper->redrawWindow();
  484. }
  485. }
  486. /**
  487. * Main constructor for our C++ class
  488. */
  489. VSTPluginWrapper::VSTPluginWrapper(audioMasterCallback vstHostCallback,
  490. VstInt32 vendorUniqueID,
  491. VstInt32 vendorVersion,
  492. VstInt32 numParams,
  493. VstInt32 numPrograms,
  494. VstInt32 numInputs,
  495. VstInt32 numOutputs) :
  496. _vstHostCallback(vstHostCallback)
  497. {
  498. // Make sure that the memory is properly initialized
  499. memset(&_vstPlugin, 0, sizeof(_vstPlugin));
  500. // this field must be set with this constant...
  501. _vstPlugin.magic = kEffectMagic;
  502. // storing this object into the VSTPlugin so that it can be retrieved when called back (see callbacks for use)
  503. _vstPlugin.object = this;
  504. // specifying that we handle both single and double precision (there are other flags see aeffect.h/VstAEffectFlags)
  505. _vstPlugin.flags =
  506. effFlagsIsSynth |
  507. effFlagsCanReplacing |
  508. effFlagsCanDoubleReplacing |
  509. effFlagsHasEditor
  510. ;
  511. // initializing the plugin with the various values
  512. _vstPlugin.uniqueID = vendorUniqueID;
  513. _vstPlugin.version = vendorVersion;
  514. _vstPlugin.numParams = numParams;
  515. _vstPlugin.numPrograms = numPrograms;
  516. _vstPlugin.numInputs = numInputs;
  517. _vstPlugin.numOutputs = numOutputs;
  518. // setting the callbacks to the previously defined functions
  519. _vstPlugin.dispatcher = VSTPluginDispatcher;
  520. _vstPlugin.getParameter = VSTPluginGetParameter;
  521. _vstPlugin.setParameter = VSTPluginSetParameter;
  522. _vstPlugin.processReplacing = VSTPluginProcessSamplesFloat32;
  523. _vstPlugin.processDoubleReplacing = VSTPluginProcessSamplesFloat64;
  524. #ifdef USE_LGLW
  525. printf("vstgltest: calling lglw_init()\n");
  526. lglw = lglw_init(EDITWIN_W, EDITWIN_H);
  527. lglw_userdata_set(lglw, this);
  528. printf("vstgltest: lglw_init() returned lglw=%p\n", lglw);
  529. #endif // USE_LGLW
  530. }
  531. /**
  532. * Destructor called when the plugin is closed (see VSTPluginDispatcher with effClose opCode). In this very simply plugin
  533. * there is nothing to do but in general the memory that gets allocated MUST be freed here otherwise there might be a
  534. * memory leak which may end up slowing down and/or crashing the host
  535. */
  536. VSTPluginWrapper::~VSTPluginWrapper() {
  537. #ifdef USE_LGLW
  538. lglw_exit(lglw);
  539. #endif // USE_LGLW
  540. }
  541. /**
  542. * Implementation of the main entry point of the plugin
  543. */
  544. VST_EXPORT VSTPlugin *VSTPluginMain(VSTHostCallback vstHostCallback)
  545. {
  546. printf("vstgltest: entering VSTPluginMain... \n");
  547. {
  548. FILE *fh = fopen("/tmp/debug_lglw.txt", "w");
  549. fprintf(fh, "hello\n");
  550. fflush(fh);
  551. fclose(fh);
  552. }
  553. {
  554. Dl_info dlInfo;
  555. char dllnameraw[1024];
  556. char *dllnamerawp = dllnameraw;
  557. char oldCWD[1024];
  558. getcwd(oldCWD, 1024);
  559. ::dladdr((void*)VSTPluginMain, &dlInfo);
  560. if('/' != dlInfo.dli_fname[0])
  561. {
  562. // (note) 'dli_fname' can be a relative path (e.g. when loaded from vst2_debug_host)
  563. sprintf(dllnameraw, "%s/%s", oldCWD, dlInfo.dli_fname);
  564. }
  565. else
  566. {
  567. // Absolute path (e.g. when loaded from Renoise host)
  568. dllnamerawp = (char*)dlInfo.dli_fname;
  569. }
  570. printf("vstgltest: dllname=\"%s\"\n", dllnamerawp);
  571. }
  572. // simply create our plugin C++ class
  573. VSTPluginWrapper *plugin =
  574. new VSTPluginWrapper(vstHostCallback,
  575. //CCONST('u', 's', 'a', 'ยง'), // registered with Steinberg (http://service.steinberg.de/databases/plugin.nsf/plugIn?openForm)
  576. CCONST('t', 'e', 's', 't'), // unregistered
  577. PLUGIN_VERSION, // version
  578. 0, // no params
  579. 1, // no programs
  580. 0, // 2 inputs
  581. 2); // 2 outputs
  582. // return the plugin per the contract of the API
  583. return plugin->getVSTPlugin();
  584. }