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.

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