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.

349 lines
13KB

  1. #pragma once
  2. #include "global_pre.hpp"
  3. #include <string>
  4. #include <stdio.h> // debug
  5. #include <list>
  6. #include "tags.hpp"
  7. #include "util/common.hpp"
  8. #define RACK_PLUGIN_INIT_ID_INTERNAL p->slug = TOSTRING(SLUG); p->version = TOSTRING(VERSION)
  9. #ifdef USE_BEGIN_REDRAW_FXN
  10. extern "C" {
  11. #include <lglw.h>
  12. }
  13. #endif // USE_BEGIN_REDRAW_FXN
  14. #ifdef USE_VST2
  15. namespace rack {
  16. struct Plugin;
  17. typedef void (*InitCallback)(Plugin *);
  18. }
  19. typedef void (*vst2_handle_ui_param_fxn_t) (int uniqueParamId, float normValue);
  20. typedef void (*vst2_queue_param_sync_fxn_t) (int uniqueParamId, float value, bool _bNormalized);
  21. typedef void (*rack_set_tls_globals_fxn_t) (rack::Plugin *p);
  22. #ifdef USE_BEGIN_REDRAW_FXN
  23. typedef void (*rack_begin_redraw_fxn_t) (void);
  24. #endif // USE_BEGIN_REDRAW_FXN
  25. #ifdef RACK_HOST
  26. // Rack host build:
  27. extern void vst2_handle_ui_param (int uniqueParamId, float normValue);
  28. extern void vst2_queue_param_sync (int _uniqueParamId, float _value, bool _bNormalized);
  29. #define RACK_PLUGIN_DECLARE(pluginname)
  30. #ifdef _MSC_VER
  31. #define RACK_PLUGIN_INIT(pluginname) extern "C" void init_plugin_##pluginname##(rack::Plugin *p)
  32. #else
  33. #define RACK_PLUGIN_INIT(pluginname) static void loc_init_plugin(rack::Plugin *p); extern "C" { void CONCAT(init_plugin_, pluginname) (rack::Plugin *p) { loc_init_plugin(p); } } static void loc_init_plugin(rack::Plugin *p)
  34. #endif // _MSC_VER
  35. #define RACK_PLUGIN_INIT_ID() RACK_PLUGIN_INIT_ID_INTERNAL
  36. #else
  37. // Plugin build:
  38. #ifdef _MSC_VER
  39. #ifdef RACK_PLUGIN_SHARED
  40. #define RACK_PLUGIN_EXPORT extern "C" __declspec(dllexport)
  41. #else
  42. #define RACK_PLUGIN_EXPORT extern "C"
  43. #endif // RACK_PLUGIN_SHARED
  44. #define RACK_TLS __declspec(thread)
  45. #else
  46. #define RACK_PLUGIN_EXPORT extern "C"
  47. #define RACK_TLS __thread
  48. #endif // _MSC_VER
  49. extern vst2_handle_ui_param_fxn_t vst2_handle_ui_param;
  50. extern vst2_queue_param_sync_fxn_t vst2_queue_param_sync;
  51. #ifndef RACK_PLUGIN_SHARED_LIB_BUILD
  52. #ifdef RACK_PLUGIN_SHARED
  53. // Dynamically loaded plugin build
  54. #define RACK_PLUGIN_DECLARE(pluginname) namespace rack { extern RACK_TLS Plugin *plugin; } extern void __rack_unused_symbol(void)
  55. #ifdef ARCH_WIN
  56. #define JSON_SEED_INIT_EXTERNAL extern "C" { extern long seed_initialized; }
  57. #else
  58. #define JSON_SEED_INIT_EXTERNAL extern "C" { extern volatile char seed_initialized; }
  59. #endif
  60. #ifdef USE_BEGIN_REDRAW_FXN
  61. // a hack that rebinds the GL context in shared plugins (may fix shared module redraw issues on Linux)
  62. #define BEGIN_REDRAW_FXN_SET \
  63. rack::plugin->begin_redraw_fxn = &rack::loc_begin_redraw;
  64. #define BEGIN_REDRAW_FXN_IMP \
  65. static void loc_begin_redraw(void) { \
  66. lglw_glcontext_rebind(global_ui->window.lglw); \
  67. }
  68. #else
  69. #define BEGIN_REDRAW_FXN_SET
  70. #define BEGIN_REDRAW_FXN_IMP
  71. #endif // USE_BEGIN_REDRAW_FXN
  72. #define RACK_PLUGIN_INIT(pluginname) \
  73. vst2_handle_ui_param_fxn_t vst2_handle_ui_param; \
  74. vst2_queue_param_sync_fxn_t vst2_queue_param_sync; \
  75. JSON_SEED_INIT_EXTERNAL \
  76. extern "C" { extern volatile uint32_t hashtable_seed; } \
  77. namespace rack { \
  78. RACK_TLS Plugin *plugin; \
  79. RACK_TLS Global *global; \
  80. RACK_TLS GlobalUI *global_ui; \
  81. static void loc_set_tls_globals(rack::Plugin *p) { \
  82. plugin = p; \
  83. global = plugin->global; \
  84. global_ui = plugin->global_ui; \
  85. /*printf("xxx plugin:loc_set_tls_globals: &global=%p global=%p\n", &global, plugin->global);*/ \
  86. hashtable_seed = p->json.hashtable_seed; \
  87. seed_initialized = p->json.seed_initialized; \
  88. } \
  89. BEGIN_REDRAW_FXN_IMP \
  90. } \
  91. static void loc_init_plugin(rack::Plugin *p); extern "C" { RACK_PLUGIN_EXPORT void init_plugin(rack::Plugin *p) { loc_init_plugin(p); } } static void loc_init_plugin(rack::Plugin *p)
  92. #define RACK_PLUGIN_INIT_ID() \
  93. rack::plugin = p; \
  94. rack::plugin->set_tls_globals_fxn = &rack::loc_set_tls_globals; \
  95. BEGIN_REDRAW_FXN_SET \
  96. vst2_handle_ui_param = p->vst2_handle_ui_param_fxn; \
  97. vst2_queue_param_sync = p->vst2_queue_param_sync_fxn; \
  98. rack::global = p->global; \
  99. rack::global_ui = p->global_ui; \
  100. RACK_PLUGIN_INIT_ID_INTERNAL
  101. #else
  102. // Statically linked plugin build
  103. #define RACK_PLUGIN_DECLARE(pluginname)
  104. #ifdef _MSC_VER
  105. #define RACK_PLUGIN_INIT(pluginname) extern "C" void init_plugin_##pluginname##(rack::Plugin *p)
  106. #else
  107. #define RACK_PLUGIN_INIT(pluginname) static void loc_init_plugin(rack::Plugin *p); extern "C" { void CONCAT(init_plugin_, pluginname) (rack::Plugin *p) { loc_init_plugin(p); } } static void loc_init_plugin(rack::Plugin *p)
  108. #endif
  109. #define RACK_PLUGIN_INIT_ID() RACK_PLUGIN_INIT_ID_INTERNAL
  110. #endif // RACK_PLUGIN_SHARED
  111. #endif // RACK_PLUGIN_SHARED_LIB_BUILD
  112. #endif // RACK_HOST
  113. #else
  114. #define RACK_PLUGIN_DECLARE(pluginname) extern Plugin *plugin
  115. #define RACK_PLUGIN_INIT(pluginname) extern "C" RACK_PLUGIN_EXPORT void init(rack::Plugin *p)
  116. #define RACK_PLUGIN_INIT_ID() plugin = p; RACK_PLUGIN_INIT_ID_INTERNAL
  117. #endif // USE_VST2
  118. #define RACK_PLUGIN_INIT_WEBSITE(url) p->website = url
  119. #define RACK_PLUGIN_INIT_MANUAL(url) p->manual = url
  120. #define RACK_PLUGIN_INIT_VERSION(ver) p->version = ver
  121. #ifdef _MSC_VER
  122. #define RACK_PLUGIN_MODEL_DECLARE(pluginname, modelname) extern Model *create_model_##pluginname##_##modelname##(void)
  123. #define RACK_PLUGIN_MODEL_INIT(pluginname, modelname) Model *create_model_##pluginname##_##modelname##(void)
  124. #define RACK_PLUGIN_MODEL_ADD(pluginname, modelname) p->addModel(create_model_##pluginname##_##modelname##())
  125. #else
  126. #define CONCAT_USCORE_LITERAL(x, y) x ## _ ## y
  127. #define CONCAT_USCORE(x, y) CONCAT_USCORE_LITERAL(x, y)
  128. #define RACK_PLUGIN_MODEL_DECLARE(pluginname, modelname) extern Model *CONCAT(create_model_, CONCAT_USCORE(pluginname, modelname))(void)
  129. #define RACK_PLUGIN_MODEL_INIT(pluginname, modelname) Model *CONCAT(create_model_, CONCAT_USCORE(pluginname, modelname))(void)
  130. #define RACK_PLUGIN_MODEL_ADD(pluginname, modelname) p->addModel(CONCAT(create_model_, CONCAT_USCORE(pluginname, modelname))())
  131. #endif // _MSC_VER
  132. namespace rack {
  133. struct ModuleWidget;
  134. struct Module;
  135. struct Model;
  136. // Subclass this and return a pointer to a new one when init() is called
  137. struct Plugin {
  138. /** A list of the models available by this plugin, add with addModel() */
  139. std::list<Model*> models;
  140. /** The file path of the plugin's directory */
  141. std::string path;
  142. /** OS-dependent library handle */
  143. void *handle = NULL;
  144. /** Must be unique. Used for patch files and the VCV store API.
  145. To guarantee uniqueness, it is a good idea to prefix the slug by your "company name" if available, e.g. "MyCompany-MyPlugin"
  146. */
  147. std::string slug;
  148. /** The version of your plugin
  149. Plugins should follow the versioning scheme described at https://github.com/VCVRack/Rack/issues/266
  150. Do not include the "v" in "v1.0" for example.
  151. */
  152. std::string version;
  153. /** Deprecated, do not use. */
  154. std::string website;
  155. std::string manual;
  156. #ifdef USE_VST2
  157. //
  158. // Set by Rack host (before init_plugin()):
  159. //
  160. vst2_handle_ui_param_fxn_t vst2_handle_ui_param_fxn = NULL;
  161. vst2_queue_param_sync_fxn_t vst2_queue_param_sync_fxn = NULL;
  162. Global *global = NULL;
  163. GlobalUI *global_ui = NULL;
  164. // Set by Rack host immediately before set_tls_globals_fxn is called:
  165. // (note) must be copied by the plugin or json import won't function properly
  166. struct {
  167. uint32_t hashtable_seed;
  168. #ifdef ARCH_WIN
  169. long seed_initialized;
  170. #else
  171. char seed_initialized;
  172. #endif
  173. } json;
  174. //
  175. // Set by plugin:
  176. // - in init_plugin()
  177. // - called by Rack host in audio+UI threads
  178. // - NULL if this is a statically linked add-on
  179. //
  180. rack_set_tls_globals_fxn_t set_tls_globals_fxn = NULL;
  181. #ifdef USE_BEGIN_REDRAW_FXN
  182. // Called when redrawing the UI.
  183. // An attempt to fix the GL issue with shared modules on Cameron's machine.
  184. rack_begin_redraw_fxn_t begin_redraw_fxn = NULL;
  185. #endif // USE_BEGIN_REDRAW_FXN
  186. #endif // USE_VST2
  187. virtual ~Plugin();
  188. void addModel(Model *model);
  189. };
  190. struct Model {
  191. Plugin *plugin = NULL;
  192. /** An identifier for the model, e.g. "VCO". Used for saving patches.
  193. The model slug must be unique in your plugin, but it doesn't need to be unique among different plugins.
  194. */
  195. std::string slug;
  196. /** Human readable name for your model, e.g. "Voltage Controlled Oscillator" */
  197. std::string name;
  198. /** The author name of the module.
  199. This might be different than the plugin slug. For example, if you create multiple plugins but want them to be branded similarly, you may use the same author in multiple plugins.
  200. You may even have multiple authors in one plugin, although this property will be moved to Plugin for Rack 1.0.
  201. */
  202. std::string author;
  203. /** List of tags representing the function(s) of the module (optional) */
  204. std::list<ModelTag> tags;
  205. virtual ~Model() {}
  206. /** Creates a headless Module */
  207. virtual Module *createModule() { return NULL; }
  208. /** Creates a ModuleWidget with a Module attached */
  209. virtual ModuleWidget *createModuleWidget() { return NULL; }
  210. /** Creates a ModuleWidget with no Module, useful for previews */
  211. virtual ModuleWidget *createModuleWidgetNull() { return NULL; }
  212. /** Create Model subclass which constructs a specific Module and ModuleWidget subclass */
  213. template <typename TModule, typename TModuleWidget, typename... Tags>
  214. static Model *create(std::string author, std::string slug, std::string name, Tags... tags) {
  215. struct TModel : Model {
  216. Module *createModule() override {
  217. TModule *module = new TModule();
  218. return module;
  219. }
  220. ModuleWidget *createModuleWidget() override {
  221. printf("xxx createModuleWidget: ENTER\n");
  222. TModule *module = new TModule();
  223. printf("xxx createModuleWidget: module=%p\n", module);
  224. TModuleWidget *moduleWidget = new TModuleWidget(module);
  225. printf("xxx createModuleWidget: moduleWidget=%p\n", moduleWidget);
  226. moduleWidget->model = this;
  227. printf("xxx createModuleWidget: LEAVE\n");
  228. return moduleWidget;
  229. }
  230. ModuleWidget *createModuleWidgetNull() override {
  231. TModuleWidget *moduleWidget = new TModuleWidget(NULL);
  232. moduleWidget->model = this;
  233. return moduleWidget;
  234. }
  235. };
  236. TModel *o = new TModel();
  237. o->author = author;
  238. o->slug = slug;
  239. o->name = name;
  240. o->tags = {tags...};
  241. return o;
  242. }
  243. };
  244. void pluginInit(bool devMode, bool _bFX);
  245. void pluginDestroy();
  246. void pluginLogIn(std::string email, std::string password);
  247. void pluginLogOut();
  248. /** Returns whether a new plugin is available, and downloads it unless doing a dry run */
  249. bool pluginSync(bool dryRun);
  250. void pluginCancelDownload();
  251. bool pluginIsLoggedIn();
  252. bool pluginIsDownloading();
  253. float pluginGetDownloadProgress();
  254. std::string pluginGetDownloadName();
  255. std::string pluginGetLoginStatus();
  256. Plugin *pluginGetPlugin(std::string pluginSlug);
  257. Model *pluginGetModel(std::string pluginSlug, std::string modelSlug);
  258. extern std::list<Plugin*> gPlugins;
  259. extern std::string gToken;
  260. } // namespace rack
  261. // Access helpers for global UI vars
  262. //
  263. // (note) these avoid accessing the global rack vars directly
  264. // (global TLS vars cannot be exported to dynamically loaded plugins)
  265. //
  266. // (note) please use the macros and do _not_ call the functions directly!
  267. //
  268. #include "global_pre.hpp"
  269. #include "global_ui.hpp"
  270. extern rack::RackScene *rack_plugin_ui_get_rackscene(void);
  271. #define RACK_PLUGIN_UI_RACKSCENE rack_plugin_ui_get_rackscene()
  272. extern rack::RackWidget *rack_plugin_ui_get_rackwidget(void);
  273. #define RACK_PLUGIN_UI_RACKWIDGET rack_plugin_ui_get_rackwidget()
  274. extern rack::Toolbar *rack_plugin_ui_get_toolbar(void);
  275. #define RACK_PLUGIN_UI_TOOLBAR rack_plugin_ui_get_toolbar()
  276. extern rack::Widget *rack_plugin_ui_get_hovered_widget(void);
  277. #define RACK_PLUGIN_UI_HOVERED_WIDGET rack_plugin_ui_get_hovered_widget()
  278. extern rack::Widget *rack_plugin_ui_get_dragged_widget(void);
  279. #define RACK_PLUGIN_UI_DRAGGED_WIDGET rack_plugin_ui_get_dragged_widget()
  280. extern void rack_plugin_ui_set_dragged_widget(rack::Widget *);
  281. #define RACK_PLUGIN_UI_DRAGGED_WIDGET_SET(a) rack_plugin_ui_set_dragged_widget(a)
  282. extern rack::Widget *rack_plugin_ui_get_draghovered_widget(void);
  283. #define RACK_PLUGIN_UI_DRAGHOVERED_WIDGET rack_plugin_ui_get_draghovered_widget()
  284. extern rack::Widget *rack_plugin_ui_get_focused_widget(void);
  285. #define RACK_PLUGIN_UI_FOCUSED_WIDGET rack_plugin_ui_get_focused_widget()
  286. extern void rack_plugin_ui_set_focused_widget(rack::Widget *);
  287. #define RACK_PLUGIN_UI_FOCUSED_WIDGET_SET(a) rack_plugin_ui_set_focused_widget(a)