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.

517 lines
16KB

  1. #include "global_pre.hpp"
  2. #include "app.hpp"
  3. #include "window.hpp"
  4. #include "engine.hpp"
  5. #include "asset.hpp"
  6. #include "settings.hpp"
  7. #include "global.hpp"
  8. #include "global_ui.hpp"
  9. #ifdef RACK_HOST
  10. #define Dfltequal(a, b) ( (((a)-(b)) < 0.0f) ? (((a)-(b)) > -0.0001f) : (((a)-(b)) < 0.0001f) )
  11. extern void vst2_oversample_realtime_set (float _factor, int _quality);
  12. extern void vst2_oversample_realtime_get (float *_factor, int *_quality);
  13. extern void vst2_oversample_channels_set (int _numIn, int _numOut);
  14. extern void vst2_oversample_channels_get (int *_numIn, int *_numOut);
  15. extern void vst2_idle_detect_mode_set (int _mode);
  16. extern void vst2_idle_detect_mode_get (int *_mode);
  17. extern void vst2_refresh_rate_set (float _hz);
  18. extern float vst2_refresh_rate_get (void);
  19. extern void vst2_window_size_set (int _width, int _height);
  20. #endif // RACK_HOST
  21. namespace rack {
  22. struct TooltipIconButton : IconButton {
  23. Tooltip *tooltip = NULL;
  24. std::string tooltipText;
  25. void onMouseEnter(EventMouseEnter &e) override {
  26. if (!tooltip) {
  27. tooltip = new Tooltip();
  28. tooltip->box.pos = getAbsoluteOffset(Vec(0, BND_WIDGET_HEIGHT));
  29. tooltip->text = tooltipText;
  30. global_ui->ui.gScene->addChild(tooltip);
  31. }
  32. IconButton::onMouseEnter(e);
  33. }
  34. void onMouseLeave(EventMouseLeave &e) override {
  35. if (tooltip) {
  36. global_ui->ui.gScene->removeChild(tooltip);
  37. delete tooltip;
  38. tooltip = NULL;
  39. }
  40. IconButton::onMouseLeave(e);
  41. }
  42. };
  43. struct NewButton : TooltipIconButton {
  44. NewButton() {
  45. setSVG(SVG::load(assetGlobal("res/icons/noun_146097_cc.svg")));
  46. tooltipText = "New (" WINDOW_MOD_KEY_NAME "+N)";
  47. }
  48. void onAction(EventAction &e) override {
  49. global_ui->app.gRackWidget->reset();
  50. }
  51. };
  52. struct OpenButton : TooltipIconButton {
  53. OpenButton() {
  54. setSVG(SVG::load(assetGlobal("res/icons/noun_31859_cc.svg")));
  55. tooltipText = "Open (" WINDOW_MOD_KEY_NAME "+O)";
  56. }
  57. void onAction(EventAction &e) override {
  58. global_ui->app.gRackWidget->openDialog();
  59. }
  60. };
  61. struct SaveButton : TooltipIconButton {
  62. SaveButton() {
  63. setSVG(SVG::load(assetGlobal("res/icons/noun_1343816_cc.svg")));
  64. tooltipText = "Save (" WINDOW_MOD_KEY_NAME "+S)";
  65. }
  66. void onAction(EventAction &e) override {
  67. global_ui->app.gRackWidget->saveDialog();
  68. }
  69. };
  70. struct SaveAsButton : TooltipIconButton {
  71. SaveAsButton() {
  72. setSVG(SVG::load(assetGlobal("res/icons/noun_1343811_cc.svg")));
  73. tooltipText = "Save as (" WINDOW_MOD_KEY_NAME "+Shift+S)";
  74. }
  75. void onAction(EventAction &e) override {
  76. global_ui->app.gRackWidget->saveAsDialog();
  77. }
  78. };
  79. struct RevertButton : TooltipIconButton {
  80. RevertButton() {
  81. setSVG(SVG::load(assetGlobal("res/icons/noun_1084369_cc.svg")));
  82. tooltipText = "Revert";
  83. }
  84. void onAction(EventAction &e) override {
  85. global_ui->app.gRackWidget->revert();
  86. }
  87. };
  88. struct DisconnectCablesButton : TooltipIconButton {
  89. DisconnectCablesButton() {
  90. setSVG(SVG::load(assetGlobal("res/icons/noun_1745061_cc.svg")));
  91. tooltipText = "Disconnect cables";
  92. }
  93. void onAction(EventAction &e) override {
  94. global_ui->app.gRackWidget->disconnect();
  95. }
  96. };
  97. struct PowerMeterButton : TooltipIconButton {
  98. PowerMeterButton() {
  99. setSVG(SVG::load(assetGlobal("res/icons/noun_305536_cc.svg")));
  100. tooltipText = "Toggle power meter (see manual for explanation)";
  101. }
  102. void onAction(EventAction &e) override {
  103. global->gPowerMeter ^= true;
  104. }
  105. };
  106. struct EnginePauseItem : MenuItem {
  107. void onAction(EventAction &e) override {
  108. global->gPaused ^= true;
  109. }
  110. };
  111. struct SampleRateItem : MenuItem {
  112. float sampleRate;
  113. void onAction(EventAction &e) override {
  114. engineSetSampleRate(sampleRate);
  115. global->gPaused = false;
  116. }
  117. };
  118. #ifdef RACK_HOST
  119. struct OversampleSetting {
  120. const char *name;
  121. float factor;
  122. int quality;
  123. };
  124. static OversampleSetting oversample_settings[] = {
  125. /* 0 */ { "No resampling", 1.0f, 0 },
  126. // /* 1 */ { "Undersample /6 (low)", 0.166666666667f, 4 },
  127. // /* 2 */ { "Undersample /6 (medium)", 0.166666666667f, 7 },
  128. // /* 3 */ { "Undersample /6 (high)", 0.166666666667f, 10 },
  129. /* 4 */ { "Undersample /4 (low)", 0.25f, 4 },
  130. /* 5 */ { "Undersample /4 (medium)", 0.25f, 7 },
  131. /* 6 */ { "Undersample /4 (high)", 0.25f, 10 },
  132. /* 7 */ { "Undersample /2 (low)", 0.5f, 4 },
  133. /* 8 */ { "Undersample /2 (medium)", 0.5f, 7 },
  134. /* 9 */ { "Undersample /2 (high)", 0.5f, 10 },
  135. /* 10 */ { "Oversample x2 (low)", 2.0f, 4 },
  136. /* 11 */ { "Oversample x2 (medium)", 2.0f, 7 },
  137. /* 12 */ { "Oversample x2 (high)", 2.0f, 10 },
  138. /* 13 */ { "Oversample x4 (low)", 4.0f, 4 },
  139. /* 14 */ { "Oversample x4 (medium)", 4.0f, 7 },
  140. /* 15 */ { "Oversample x4 (high)", 4.0f, 10 },
  141. /* 16 */ { "Oversample x6 (low)", 6.0f, 4 },
  142. /* 17 */ { "Oversample x6 (medium)", 6.0f, 7 },
  143. /* 18 */ { "Oversample x6 (high)", 6.0f, 10 },
  144. /* 19 */ { "Oversample x8 (low)", 8.0f, 4 },
  145. /* 20 */ { "Oversample x8 (medium)", 8.0f, 7 },
  146. /* 21 */ { "Oversample x8 (high)", 8.0f, 10 },
  147. /* 22 */ { "Oversample x12 (low)", 12.0f, 4 },
  148. /* 23 */ { "Oversample x12 (medium)", 12.0f, 7 },
  149. /* 24 */ { "Oversample x12 (high)", 12.0f, 10 },
  150. /* 25 */ { "Oversample x16 (low)", 16.0f, 4 },
  151. /* 26 */ { "Oversample x16 (medium)", 16.0f, 7 },
  152. /* 27 */ { "Oversample x16 (high)", 16.0f, 10 },
  153. };
  154. #define NUM_OVERSAMPLE_SETTINGS (sizeof(oversample_settings) / sizeof(OversampleSetting))
  155. struct OversampleItem : MenuItem {
  156. const OversampleSetting *setting;
  157. void onAction(EventAction &e) override {
  158. vst2_oversample_realtime_set(setting->factor, setting->quality);
  159. global->gPaused = false;
  160. }
  161. };
  162. struct OversampleChannelSetting {
  163. const char *name;
  164. int num_in;
  165. int num_out;
  166. };
  167. static OversampleChannelSetting oversample_channel_settings[] = {
  168. /* 0 */ { "Oversample: 0 in, 1 out", 0, 1 },
  169. /* 1 */ { "Oversample: 0 in, 2 out", 0, 2 },
  170. /* 2 */ { "Oversample: 0 in, 4 out", 0, 4 },
  171. /* 3 */ { "Oversample: 0 in, 8 out", 0, 8 },
  172. /* 4 */ { "Oversample: 2 in, 2 out", 2, 2 },
  173. /* 5 */ { "Oversample: 2 in, 4 out", 2, 4 },
  174. /* 6 */ { "Oversample: 4 in, 2 out", 4, 2 },
  175. /* 7 */ { "Oversample: 4 in, 8 out", 4, 8 },
  176. /* 8 */ { "Oversample: 8 in, 8 out", 8, 8 },
  177. };
  178. #define NUM_OVERSAMPLE_CHANNEL_SETTINGS (sizeof(oversample_channel_settings) / sizeof(OversampleChannelSetting))
  179. struct OversampleChannelItem : MenuItem {
  180. const OversampleChannelSetting *setting;
  181. void onAction(EventAction &e) override {
  182. vst2_oversample_channels_set(setting->num_in, setting->num_out);
  183. global->gPaused = false;
  184. }
  185. };
  186. struct IdleModeItem : MenuItem {
  187. int idle_mode;
  188. void onAction(EventAction &e) override {
  189. vst2_idle_detect_mode_set(idle_mode);
  190. }
  191. };
  192. #endif // RACK_HOST
  193. struct SampleRateButton : TooltipIconButton {
  194. SampleRateButton() {
  195. setSVG(SVG::load(assetGlobal("res/icons/noun_1240789_cc.svg")));
  196. tooltipText = "Internal sample rate";
  197. }
  198. void onAction(EventAction &e) override {
  199. Menu *menu = global_ui->ui.gScene->createMenu();
  200. menu->box.pos = getAbsoluteOffset(Vec(0, box.size.y));
  201. menu->box.size.x = box.size.x;
  202. menu->addChild(MenuLabel::create("Internal sample rate"));
  203. EnginePauseItem *pauseItem = new EnginePauseItem();
  204. pauseItem->text = global->gPaused ? "Resume engine" : "Pause engine";
  205. menu->addChild(pauseItem);
  206. #if defined(USE_VST2) && defined(RACK_HOST)
  207. {
  208. int numIn;
  209. int numOut;
  210. vst2_oversample_channels_get(&numIn, &numOut);
  211. for(unsigned int overIdx = 0u; overIdx < NUM_OVERSAMPLE_CHANNEL_SETTINGS; overIdx++)
  212. {
  213. const OversampleChannelSetting *setting = &oversample_channel_settings[overIdx];
  214. OversampleChannelItem *item = new OversampleChannelItem();
  215. item->text = setting->name;
  216. item->rightText = CHECKMARK( (setting->num_in == numIn) && (setting->num_out == numOut) );
  217. item->setting = setting;
  218. menu->addChild(item);
  219. }
  220. }
  221. {
  222. float factor;
  223. int quality;
  224. vst2_oversample_realtime_get(&factor, &quality);
  225. for(unsigned int overIdx = 0u; overIdx < NUM_OVERSAMPLE_SETTINGS; overIdx++)
  226. {
  227. const OversampleSetting *setting = &oversample_settings[overIdx];
  228. OversampleItem *item = new OversampleItem();
  229. item->text = setting->name;
  230. item->rightText = CHECKMARK( Dfltequal(setting->factor, factor) && (setting->quality == quality) );
  231. item->setting = setting;
  232. menu->addChild(item);
  233. }
  234. }
  235. #else
  236. std::vector<float> sampleRates = {44100, 48000, 88200, 96000, 176400, 192000};
  237. for (float sampleRate : sampleRates) {
  238. SampleRateItem *item = new SampleRateItem();
  239. item->text = stringf("%.0f Hz", sampleRate);
  240. item->rightText = CHECKMARK(engineGetSampleRate() == sampleRate);
  241. item->sampleRate = sampleRate;
  242. menu->addChild(item);
  243. }
  244. #endif // USE_VST2 && RACK_HOST
  245. }
  246. };
  247. struct RackLockButton : TooltipIconButton {
  248. RackLockButton() {
  249. setSVG(SVG::load(assetGlobal("res/icons/noun_468341_cc.svg")));
  250. tooltipText = "Lock modules";
  251. }
  252. void onAction(EventAction &e) override {
  253. global_ui->app.gRackWidget->lockModules ^= true;
  254. }
  255. };
  256. struct IdleModeButton : TooltipIconButton {
  257. IdleModeButton() {
  258. setSVG(SVG::load(assetGlobal("res/icons/idle_mode_icon_cc.svg")));
  259. tooltipText = "Idle Mode";
  260. }
  261. void onAction(EventAction &e) override {
  262. #ifdef RACK_HOST
  263. Menu *menu = global_ui->ui.gScene->createMenu();
  264. menu->box.pos = getAbsoluteOffset(Vec(0, box.size.y));
  265. menu->box.size.x = box.size.x;
  266. menu->addChild(MenuLabel::create("Idle Mode"));
  267. int idleMode; vst2_idle_detect_mode_get(&idleMode);
  268. IdleModeItem *item;
  269. item = new IdleModeItem();
  270. item->text = "Always Active";
  271. item->rightText = CHECKMARK(0/*IDLE_DETECT_NONE*/ == idleMode);
  272. item->idle_mode = 0;
  273. menu->addChild(item);
  274. item = new IdleModeItem();
  275. item->text = "Wake on MIDI Note-On";
  276. item->rightText = CHECKMARK(1/*IDLE_DETECT_MIDI*/ == idleMode);
  277. item->idle_mode = 1;
  278. menu->addChild(item);
  279. item = new IdleModeItem();
  280. item->text = "Wake on Audio Input";
  281. item->rightText = CHECKMARK(2/*IDLE_DETECT_AUDIO*/ == idleMode);
  282. item->idle_mode = 2;
  283. menu->addChild(item);
  284. #endif // RACK_HOST
  285. }
  286. };
  287. struct settings_win_size_entry_t {
  288. int w;
  289. int h;
  290. };
  291. static settings_win_size_entry_t loc_settings_win_sizes[] = {
  292. { 1002, 600 },
  293. { 1272, 820 },
  294. { 1408, 850 },
  295. { 1588, 1100 },
  296. { 1902, 1100 },
  297. { 2500, 1980 },
  298. { 3000, 1980 },
  299. };
  300. #define NUM_SETTINGS_WIN_SIZE (sizeof(loc_settings_win_sizes) / sizeof(settings_win_size_entry_t))
  301. struct SettingsWinSizeItem : MenuItem {
  302. const settings_win_size_entry_t *setting;
  303. void onAction(EventAction &e) override {
  304. #ifdef RACK_HOST
  305. global_ui->window.windowWidth = setting->w;
  306. global_ui->window.windowHeight = setting->h;
  307. vst2_window_size_set(setting->w, setting->h);
  308. #endif // RACK_HOST
  309. }
  310. };
  311. struct settings_refresh_rate_entry_t {
  312. int rate;
  313. const char *caption;
  314. };
  315. static settings_refresh_rate_entry_t loc_settings_refresh_rates[] = {
  316. { 0, "<host fps>" },
  317. { 15, "15 fps" },
  318. { 30, "30 fps" },
  319. { 60, "60 fps" },
  320. { 75, "75 fps" },
  321. { 100, "100 fps" },
  322. };
  323. #define NUM_SETTINGS_REFRESH_RATE (sizeof(loc_settings_refresh_rates) / sizeof(settings_refresh_rate_entry_t))
  324. struct SettingsRefreshRateItem : MenuItem {
  325. const settings_refresh_rate_entry_t *setting;
  326. void onAction(EventAction &e) override {
  327. #ifdef RACK_HOST
  328. vst2_refresh_rate_set(float(setting->rate));
  329. #endif // RACK_HOST
  330. }
  331. };
  332. struct SettingsVsyncItem : MenuItem {
  333. void onAction(EventAction &e) override {
  334. lglw_swap_interval_set(global_ui->window.lglw, lglw_swap_interval_get(global_ui->window.lglw) ^ 1);
  335. }
  336. };
  337. struct SettingsSaveItem : MenuItem {
  338. void onAction(EventAction &e) override {
  339. settingsSave(assetLocal("settings.json"));
  340. }
  341. };
  342. struct SettingsButton : TooltipIconButton {
  343. SettingsButton() {
  344. setSVG(SVG::load(assetGlobal("res/icons/settings_icon_cc.svg")));
  345. tooltipText = "Global Settings";
  346. }
  347. void onAction(EventAction &e) override {
  348. Menu *menu = global_ui->ui.gScene->createMenu();
  349. menu->box.pos = getAbsoluteOffset(Vec(0, box.size.y));
  350. menu->box.size.x = box.size.x;
  351. menu->addChild(MenuLabel::create("Global Settings"));
  352. #ifdef RACK_HOST
  353. int cWinW = int(global_ui->window.windowWidth);
  354. int cWinH = int(global_ui->window.windowHeight);
  355. for(int i = 0; i < NUM_SETTINGS_WIN_SIZE; i++)
  356. {
  357. const settings_win_size_entry_t *en = &loc_settings_win_sizes[i];
  358. SettingsWinSizeItem *winSizeItem = new SettingsWinSizeItem();
  359. char buf[256];
  360. sprintf(buf, "%dx%d", en->w, en->h);
  361. winSizeItem->text = buf;
  362. winSizeItem->setting = en;
  363. winSizeItem->rightText = CHECKMARK( (cWinW == en->w) && (cWinH == en->h) );
  364. menu->addChild(winSizeItem);
  365. }
  366. int cRate = int(vst2_refresh_rate_get());
  367. for(int i = 0; i < NUM_SETTINGS_REFRESH_RATE; i++)
  368. {
  369. const settings_refresh_rate_entry_t *en = &loc_settings_refresh_rates[i];
  370. SettingsRefreshRateItem *rateItem = new SettingsRefreshRateItem();
  371. rateItem->text = en->caption;
  372. rateItem->setting = en;
  373. rateItem->rightText = CHECKMARK( (cRate == en->rate) );
  374. menu->addChild(rateItem);
  375. }
  376. SettingsVsyncItem *vsyncItem = new SettingsVsyncItem();
  377. vsyncItem->text = "Vsync";
  378. vsyncItem->rightText = CHECKMARK( (0 != lglw_swap_interval_get(global_ui->window.lglw)) );
  379. menu->addChild(vsyncItem);
  380. SettingsSaveItem *saveItem = new SettingsSaveItem();
  381. saveItem->text = "Save Settings (+Favourites)";
  382. menu->addChild(saveItem);
  383. #endif // RACK_HOST
  384. }
  385. };
  386. struct ZoomSlider : Slider {
  387. void onAction(EventAction &e) override {
  388. Slider::onAction(e);
  389. global_ui->app.gRackScene->zoomWidget->setZoom(roundf(value) / 100.0);
  390. }
  391. };
  392. Toolbar::Toolbar() {
  393. box.size.y = BND_WIDGET_HEIGHT + 2*5;
  394. SequentialLayout *layout = new SequentialLayout();
  395. layout->box.pos = Vec(5, 5);
  396. layout->spacing = 5;
  397. addChild(layout);
  398. layout->addChild(new NewButton());
  399. layout->addChild(new OpenButton());
  400. layout->addChild(new SaveButton());
  401. layout->addChild(new SaveAsButton());
  402. layout->addChild(new RevertButton());
  403. layout->addChild(new DisconnectCablesButton());
  404. layout->addChild(new SampleRateButton());
  405. layout->addChild(new PowerMeterButton());
  406. layout->addChild(new RackLockButton());
  407. layout->addChild(new IdleModeButton());
  408. layout->addChild(new SettingsButton());
  409. wireOpacitySlider = new Slider();
  410. wireOpacitySlider->box.size.x = 150;
  411. wireOpacitySlider->label = "Cable opacity";
  412. wireOpacitySlider->precision = 0;
  413. wireOpacitySlider->unit = "%";
  414. wireOpacitySlider->setLimits(0.0, 100.0);
  415. wireOpacitySlider->setDefaultValue(50.0);
  416. layout->addChild(wireOpacitySlider);
  417. wireTensionSlider = new Slider();
  418. wireTensionSlider->box.size.x = 150;
  419. wireTensionSlider->label = "Cable tension";
  420. wireTensionSlider->unit = "";
  421. wireTensionSlider->setLimits(0.0, 1.0);
  422. wireTensionSlider->setDefaultValue(0.5);
  423. layout->addChild(wireTensionSlider);
  424. zoomSlider = new ZoomSlider();
  425. zoomSlider->box.size.x = 150;
  426. zoomSlider->precision = 0;
  427. zoomSlider->label = "Zoom";
  428. zoomSlider->unit = "%";
  429. zoomSlider->setLimits(25.0, 200.0);
  430. zoomSlider->setDefaultValue(100.0);
  431. layout->addChild(zoomSlider);
  432. // Kind of hacky, but display the PluginManagerWidget only if the local directory is not the development directory
  433. if (assetLocal("") != "./") {
  434. Widget *pluginManager = new PluginManagerWidget();
  435. layout->addChild(pluginManager);
  436. }
  437. }
  438. void Toolbar::draw(NVGcontext *vg) {
  439. bndBackground(vg, 0.0, 0.0, box.size.x, box.size.y);
  440. bndBevel(vg, 0.0, 0.0, box.size.x, box.size.y);
  441. Widget::draw(vg);
  442. }
  443. } // namespace rack