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.

466 lines
16KB

  1. #include <aeffect.h>
  2. #include <aeffectx.h>
  3. #include <stdio.h>
  4. #if defined(_WIN32) || defined(_WIN64)
  5. #include <windows.h>
  6. #include <wingdi.h>
  7. #define VST_EXPORT extern "C" __declspec(dllexport)
  8. #else
  9. #include <GL/gl.h>
  10. #include <X11/Xlib.h>
  11. #include <X11/Xutil.h>
  12. #include <X11/Xos.h>
  13. #define VST_EXPORT extern
  14. #endif
  15. #include "lglw.h"
  16. #define EDITWIN_X 20
  17. #define EDITWIN_Y 20
  18. #define EDITWIN_W 640
  19. #define EDITWIN_H 480
  20. /*
  21. * I find the naming a bit confusing so I decided to use more meaningful names instead.
  22. */
  23. /**
  24. * The VSTHostCallback is a function pointer so that the plugin can communicate with the host (not used in this small example)
  25. */
  26. typedef audioMasterCallback VSTHostCallback;
  27. /**
  28. * The VSTPlugin structure (AEffect) contains information about the plugin (like version, number of inputs, ...) and
  29. * callbacks so that the host can call the plugin to do its work. The primary callback will be `processReplacing` for
  30. * single precision (float) sample processing (or `processDoubleReplacing` for double precision (double)).
  31. */
  32. typedef AEffect VSTPlugin;
  33. // Since the host is expecting a very specific API we need to make sure it has C linkage (not C++)
  34. extern "C" {
  35. /*
  36. * This is the main entry point to the VST plugin.
  37. *
  38. * The host (DAW like Maschine, Ableton Live, Reason, ...) will look for this function with this exact API.
  39. *
  40. * It is the equivalent to `int main(int argc, char *argv[])` for a C executable.
  41. *
  42. * @param vstHostCallback is a callback so that the plugin can communicate with the host (not used in this small example)
  43. * @return a pointer to the AEffect structure
  44. */
  45. VST_EXPORT VSTPlugin *VSTPluginMain(VSTHostCallback vstHostCallback);
  46. // note this looks like this without the type aliases (and is obviously 100% equivalent)
  47. // extern AEffect *VSTPluginMain(audioMasterCallback audioMaster);
  48. }
  49. /*
  50. * Constant for the version of the plugin. For example 1100 for version 1.1.0.0
  51. */
  52. const VstInt32 PLUGIN_VERSION = 1000;
  53. // extern "C" LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
  54. void loc_mouse_cbk(lglw_t _lglw, int32_t _x, int32_t _y, uint32_t _buttonState, uint32_t _changedButtonState) {
  55. printf("xxx lglw_mouse_cbk: lglw=%p p=(%d; %d) bt=0x%08x changedBt=0x%08x\n", _lglw, _x, _y, _buttonState, _changedButtonState);
  56. if(LGLW_IS_MOUSE_LBUTTON_DOWN())
  57. {
  58. // lglw_mouse_grab(_lglw, LGLW_MOUSE_GRAB_CAPTURE);
  59. lglw_mouse_grab(_lglw, LGLW_MOUSE_GRAB_WARP);
  60. }
  61. else if(LGLW_IS_MOUSE_LBUTTON_UP())
  62. {
  63. lglw_mouse_ungrab(_lglw);
  64. }
  65. }
  66. void loc_focus_cbk(lglw_t _lglw, uint32_t _focusState, uint32_t _changedFocusState) {
  67. printf("xxx lglw_focus_cbk: lglw=%p focusState=0x%08x changedFocusState=0x%08x\n", _lglw, _focusState, _changedFocusState);
  68. }
  69. lglw_bool_t loc_keyboard_cbk(lglw_t _lglw, uint32_t _vkey, uint32_t _kmod, lglw_bool_t _bPressed) {
  70. printf("xxx lglw_keyboard_cbk: lglw=%p vkey=0x%08x (\'%c\') kmod=0x%08x bPressed=%d\n", _lglw, _vkey, _vkey, _kmod, _bPressed);
  71. return LGLW_FALSE;
  72. }
  73. void loc_timer_cbk(lglw_t _lglw) {
  74. printf("xxx lglw_timer_cbk: tick\n");
  75. }
  76. /**
  77. * Encapsulates the plugin as a C++ class. It will keep both the host callback and the structure required by the
  78. * host (VSTPlugin). This class will be stored in the `VSTPlugin.object` field (circular reference) so that it can
  79. * be accessed when the host calls the plugin back (for example in `processDoubleReplacing`).
  80. */
  81. class VSTPluginWrapper
  82. {
  83. public:
  84. ERect editor_rect;
  85. lglw_t lglw;
  86. float clear_color = 0.0f;
  87. static VSTPluginWrapper *window_to_wrapper;
  88. public:
  89. VSTPluginWrapper(VSTHostCallback vstHostCallback,
  90. VstInt32 vendorUniqueID,
  91. VstInt32 vendorVersion,
  92. VstInt32 numParams,
  93. VstInt32 numPrograms,
  94. VstInt32 numInputs,
  95. VstInt32 numOutputs);
  96. ~VSTPluginWrapper();
  97. inline VSTPlugin *getVSTPlugin()
  98. {
  99. return &_vstPlugin;
  100. }
  101. inline VstInt32 getNumInputs() const
  102. {
  103. return _vstPlugin.numInputs;
  104. }
  105. inline VstInt32 getNumOutputs() const
  106. {
  107. return _vstPlugin.numOutputs;
  108. }
  109. void openEditor(void *_hwnd) {
  110. (void)lglw_window_open(lglw, _hwnd, 0/*x*/, 0/*y*/, EDITWIN_W, EDITWIN_H);
  111. lglw_mouse_callback_set(lglw, &loc_mouse_cbk);
  112. lglw_focus_callback_set(lglw, &loc_focus_cbk);
  113. lglw_keyboard_callback_set(lglw, &loc_keyboard_cbk);
  114. lglw_timer_callback_set(lglw, &loc_timer_cbk);
  115. lglw_timer_start(lglw, 200);
  116. window_to_wrapper = this;
  117. }
  118. void closeEditor(void) {
  119. if(NULL != window_to_wrapper)
  120. {
  121. lglw_window_close(lglw);
  122. window_to_wrapper = NULL;
  123. }
  124. }
  125. static VSTPluginWrapper *FindWrapperByWindow(Window hwnd) {
  126. return window_to_wrapper;
  127. }
  128. void redrawWindow(void) {
  129. #if 0
  130. // Save host GL context
  131. lglw_glcontext_push(lglw);
  132. // Draw something
  133. ::glClearColor(0.0, 1.0, clear_color, 1.0);
  134. clear_color += 0.05f;
  135. if(clear_color >= 1.0f)
  136. clear_color -= 1.0f;
  137. ::glClear(GL_COLOR_BUFFER_BIT);
  138. ::glFlush();
  139. lglw_swap_buffers(lglw);
  140. // Restore host GL context
  141. lglw_glcontext_pop(lglw);
  142. #endif
  143. }
  144. private:
  145. // the host callback (a function pointer)
  146. VSTHostCallback _vstHostCallback;
  147. // the actual structure required by the host
  148. VSTPlugin _vstPlugin;
  149. };
  150. VSTPluginWrapper *VSTPluginWrapper::window_to_wrapper = NULL;
  151. /*******************************************
  152. * Callbacks: Host -> Plugin
  153. *
  154. * Defined here because they are used in the rest of the code later
  155. */
  156. /**
  157. * This is the callback that will be called to process the samples in the case of single precision. This is where the
  158. * meat of the logic happens!
  159. *
  160. * @param vstPlugin the object returned by VSTPluginMain
  161. * @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]
  162. * @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]
  163. * @param sampleFrames the number of samples (second dimension in both arrays)
  164. */
  165. void VSTPluginProcessSamplesFloat32(VSTPlugin *vstPlugin, float **inputs, float **outputs, VstInt32 sampleFrames)
  166. {
  167. // we can get a hold to our C++ class since we stored it in the `object` field (see constructor)
  168. VSTPluginWrapper *wrapper = static_cast<VSTPluginWrapper *>(vstPlugin->object);
  169. // code speaks for itself: for each input (2 when stereo input), iterating over every sample and writing the
  170. // result in the outputs array after multiplying by 0.5 (which result in a 3dB attenuation of the sound)
  171. for(int i = 0; i < wrapper->getNumInputs(); i++)
  172. {
  173. auto inputSamples = inputs[i];
  174. auto outputSamples = outputs[i];
  175. for(int j = 0; j < sampleFrames; j++)
  176. {
  177. outputSamples[j] = inputSamples[j] * 0.5f;
  178. }
  179. }
  180. }
  181. /**
  182. * This is the callback that will be called to process the samples in the case of double precision. This is where the
  183. * meat of the logic happens!
  184. *
  185. * @param vstPlugin the object returned by VSTPluginMain
  186. * @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]
  187. * @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]
  188. * @param sampleFrames the number of samples (second dimension in both arrays)
  189. */
  190. void VSTPluginProcessSamplesFloat64(VSTPlugin *vstPlugin, double **inputs, double **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.5;
  203. }
  204. }
  205. }
  206. /**
  207. * This is the plugin called by the host to communicate with the plugin, mainly to request information (like the
  208. * vendor string, the plugin category...) or communicate state/changes (like open/close, frame rate...)
  209. *
  210. * @param vstPlugin the object returned by VSTPluginMain
  211. * @param opCode defined in aeffect.h/AEffectOpcodes and which continues in aeffectx.h/AEffectXOpcodes for a grand
  212. * total of 79 of them! Only a few of them are implemented in this small plugin.
  213. * @param index depend on the opcode
  214. * @param value depend on the opcode
  215. * @param ptr depend on the opcode
  216. * @param opt depend on the opcode
  217. * @return depend on the opcode (0 is ok when you don't implement an opcode...)
  218. */
  219. VstIntPtr VSTPluginDispatcher(VSTPlugin *vstPlugin, VstInt32 opCode, VstInt32 index, VstIntPtr value, void *ptr, float opt)
  220. {
  221. // printf("vstgltest: called VSTPluginDispatcher(%d)\n", opCode);
  222. VstIntPtr r = 0;
  223. // we can get a hold to our C++ class since we stored it in the `object` field (see constructor)
  224. VSTPluginWrapper *wrapper = static_cast<VSTPluginWrapper *>(vstPlugin->object);
  225. // see aeffect.h/AEffectOpcodes and aeffectx.h/AEffectXOpcodes for details on all of them
  226. switch(opCode)
  227. {
  228. // request for the category of the plugin: in this case it is an effect since it is modifying the input (as opposed
  229. // to generating sound)
  230. case effGetPlugCategory:
  231. // return kPlugCategEffect;
  232. return kPlugCategSynth;
  233. // called by the host when the plugin was called... time to reclaim memory!
  234. case effClose:
  235. delete wrapper;
  236. break;
  237. case effGetEffectName:
  238. ::strncpy((char*)ptr, "VST GL Test", kVstMaxEffectNameLen);
  239. r = 1;
  240. break;
  241. // request for the vendor string (usually used in the UI for plugin grouping)
  242. case effGetVendorString:
  243. strncpy(static_cast<char *>(ptr), "bsp", kVstMaxVendorStrLen);
  244. r = 1;
  245. break;
  246. // request for the version
  247. case effGetVendorVersion:
  248. return PLUGIN_VERSION;
  249. case effGetParamName:
  250. strncpy(static_cast<char *>(ptr), "myparam", kVstMaxParamStrLen);
  251. r = 1;
  252. break;
  253. case effEditIdle:
  254. printf("xxx vstgltest: redraw window\n");
  255. // (void)::RedrawWindow(wrapper->hwnd, NULL, NULL, RDW_INTERNALPAINT);
  256. //(void)::UpdateWindow(wrapper->hwnd);
  257. if(lglw_window_is_visible(wrapper->lglw))
  258. {
  259. wrapper->redrawWindow();
  260. }
  261. break;
  262. case effEditGetRect:
  263. // Query editor window geometry
  264. // ptr: ERect* (on Windows)
  265. if(NULL != ptr) // yeah, this should never be NULL
  266. {
  267. // ...
  268. wrapper->editor_rect.left = EDITWIN_X;
  269. wrapper->editor_rect.top = EDITWIN_Y;
  270. wrapper->editor_rect.right = EDITWIN_X + EDITWIN_W;
  271. wrapper->editor_rect.bottom = EDITWIN_Y + EDITWIN_H;
  272. *(void**)ptr = (void*) &wrapper->editor_rect;
  273. r = 1;
  274. }
  275. else
  276. {
  277. r = 0;
  278. }
  279. break;
  280. #if 0
  281. case effEditTop:
  282. // deprecated in vst2.4
  283. r = 0;
  284. break;
  285. #endif
  286. case effEditOpen:
  287. // Show editor window
  288. // ptr: native window handle (hWnd on Windows)
  289. wrapper->openEditor(ptr);
  290. r = 1;
  291. break;
  292. case effEditClose:
  293. // Hide editor window
  294. wrapper->closeEditor();
  295. r = 1;
  296. break;
  297. // ignoring all other opcodes
  298. default:
  299. // printf("Unknown opCode %d [ignored] \n", opCode);
  300. break;
  301. }
  302. return r;
  303. }
  304. /**
  305. * Used for parameter setting (not used by this plugin)
  306. */
  307. void VSTPluginSetParameter(VSTPlugin *vstPlugin, VstInt32 index, float parameter)
  308. {
  309. printf("called VSTPluginSetParameter(%d, %f)\n", index, parameter);
  310. // we can get a hold to our C++ class since we stored it in the `object` field (see constructor)
  311. VSTPluginWrapper *wrapper = static_cast<VSTPluginWrapper *>(vstPlugin->object);
  312. }
  313. /**
  314. * Used for parameter (not used by this plugin)
  315. */
  316. float VSTPluginGetParameter(VSTPlugin *vstPlugin, VstInt32 index)
  317. {
  318. printf("called VSTPluginGetParameter(%d)\n", index);
  319. // we can get a hold to our C++ class since we stored it in the `object` field (see constructor)
  320. VSTPluginWrapper *wrapper = static_cast<VSTPluginWrapper *>(vstPlugin->object);
  321. return 0;
  322. }
  323. /**
  324. * Main constructor for our C++ class
  325. */
  326. VSTPluginWrapper::VSTPluginWrapper(audioMasterCallback vstHostCallback,
  327. VstInt32 vendorUniqueID,
  328. VstInt32 vendorVersion,
  329. VstInt32 numParams,
  330. VstInt32 numPrograms,
  331. VstInt32 numInputs,
  332. VstInt32 numOutputs) :
  333. _vstHostCallback(vstHostCallback)
  334. {
  335. // Make sure that the memory is properly initialized
  336. memset(&_vstPlugin, 0, sizeof(_vstPlugin));
  337. // this field must be set with this constant...
  338. _vstPlugin.magic = kEffectMagic;
  339. // storing this object into the VSTPlugin so that it can be retrieved when called back (see callbacks for use)
  340. _vstPlugin.object = this;
  341. // specifying that we handle both single and double precision (there are other flags see aeffect.h/VstAEffectFlags)
  342. _vstPlugin.flags = effFlagsCanReplacing | effFlagsCanDoubleReplacing | effFlagsHasEditor;
  343. // initializing the plugin with the various values
  344. _vstPlugin.uniqueID = vendorUniqueID;
  345. _vstPlugin.version = vendorVersion;
  346. _vstPlugin.numParams = numParams;
  347. _vstPlugin.numPrograms = numPrograms;
  348. _vstPlugin.numInputs = numInputs;
  349. _vstPlugin.numOutputs = numOutputs;
  350. // setting the callbacks to the previously defined functions
  351. _vstPlugin.dispatcher = VSTPluginDispatcher;
  352. _vstPlugin.getParameter = VSTPluginGetParameter;
  353. _vstPlugin.setParameter = VSTPluginSetParameter;
  354. _vstPlugin.processReplacing = VSTPluginProcessSamplesFloat32;
  355. _vstPlugin.processDoubleReplacing = VSTPluginProcessSamplesFloat64;
  356. printf("xxx debug_plugin: calling lglw_init()\n");
  357. lglw = lglw_init(EDITWIN_W, EDITWIN_H);
  358. printf("xxx debug_plugin: lglw_init() returned lglw=%p\n", lglw);
  359. }
  360. /**
  361. * Destructor called when the plugin is closed (see VSTPluginDispatcher with effClose opCode). In this very simply plugin
  362. * there is nothing to do but in general the memory that gets allocated MUST be freed here otherwise there might be a
  363. * memory leak which may end up slowing down and/or crashing the host
  364. */
  365. VSTPluginWrapper::~VSTPluginWrapper() {
  366. lglw_exit(lglw);
  367. }
  368. /**
  369. * Implementation of the main entry point of the plugin
  370. */
  371. VST_EXPORT VSTPlugin *VSTPluginMain(VSTHostCallback vstHostCallback)
  372. {
  373. printf("called VSTPluginMain... \n");
  374. // simply create our plugin C++ class
  375. VSTPluginWrapper *plugin =
  376. new VSTPluginWrapper(vstHostCallback,
  377. CCONST('u', 's', 'a', 'ยง'), // registered with Steinberg (http://service.steinberg.de/databases/plugin.nsf/plugIn?openForm)
  378. PLUGIN_VERSION, // version
  379. 2, // no params
  380. 0, // no programs
  381. 2, // 2 inputs
  382. 2); // 2 outputs
  383. // return the plugin per the contract of the API
  384. return plugin->getVSTPlugin();
  385. }