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.

495 lines
14KB

  1. #include "global_pre.hpp"
  2. #include "settings.hpp"
  3. #include "app.hpp"
  4. #include "window.hpp"
  5. #include "engine.hpp"
  6. #include "plugin.hpp"
  7. #include <jansson.h>
  8. #include "global.hpp"
  9. #include "global_ui.hpp"
  10. #ifdef RACK_HOST
  11. extern void vst2_window_size_set (int _width, int _height);
  12. extern void vst2_refresh_rate_set (float _hz);
  13. extern float vst2_refresh_rate_get (void);
  14. extern void vst2_oversample_realtime_set (float _factor, int _quality);
  15. extern void vst2_oversample_realtime_get (float *_factor, int *_quality);
  16. extern void vst2_oversample_offline_set (float _factor, int _quality);
  17. extern void vst2_oversample_offline_get (float *_factor, int *_quality);
  18. extern void vst2_oversample_offline_check_set (int _bEnable);
  19. extern int32_t vst2_oversample_offline_check_get (void);
  20. extern void vst2_oversample_channels_set (int _numIn, int _numOut);
  21. extern void vst2_oversample_channels_get (int *_numIn, int *_numOut);
  22. extern void vst2_idle_detect_mode_fx_set (int _mode);
  23. extern int vst2_idle_detect_mode_fx_get (void);
  24. extern void vst2_idle_detect_mode_instr_set (int _mode);
  25. extern int vst2_idle_detect_mode_instr_get (void);
  26. extern int vst2_fix_denorm_get (void);
  27. extern void vst2_fix_denorm_set (int _bEnable);
  28. #endif // RACK_HOST
  29. namespace rack {
  30. bool b_touchkeyboard_enable = false; // true=support effEditKey*
  31. static json_t *settingsToJson() {
  32. // root
  33. json_t *rootJ = json_object();
  34. #ifdef RACK_HOST
  35. // token
  36. json_t *tokenJ = json_string(global->plugin.gToken.c_str());
  37. json_object_set_new(rootJ, "token", tokenJ);
  38. #if 0
  39. if (!windowIsMaximized())
  40. #endif
  41. {
  42. // windowSize
  43. Vec windowSize = windowGetWindowSize();
  44. json_t *windowSizeJ = json_pack("[f, f]", windowSize.x, windowSize.y);
  45. json_object_set_new(rootJ, "windowSize", windowSizeJ);
  46. // windowPos
  47. Vec windowPos = windowGetWindowPos();
  48. json_t *windowPosJ = json_pack("[f, f]", windowPos.x, windowPos.y);
  49. json_object_set_new(rootJ, "windowPos", windowPosJ);
  50. }
  51. // opacity
  52. float opacity = global_ui->app.gToolbar->wireOpacitySlider->value;
  53. json_t *opacityJ = json_real(opacity);
  54. json_object_set_new(rootJ, "wireOpacity", opacityJ);
  55. // tension
  56. float tension = global_ui->app.gToolbar->wireTensionSlider->value;
  57. json_t *tensionJ = json_real(tension);
  58. json_object_set_new(rootJ, "wireTension", tensionJ);
  59. // zoom
  60. float zoom = global_ui->app.gRackScene->zoomWidget->zoom;
  61. json_t *zoomJ = json_real(zoom);
  62. json_object_set_new(rootJ, "zoom", zoomJ);
  63. // refresh rate (Hz)
  64. float refreshRate = vst2_refresh_rate_get();
  65. json_t *refreshRateJ = json_integer(int(refreshRate));
  66. json_object_set_new(rootJ, "refreshRate", refreshRateJ);
  67. // vsync
  68. int vsync = lglw_swap_interval_get(global_ui->window.lglw);
  69. json_t *vsyncJ = json_boolean(vsync);
  70. json_object_set_new(rootJ, "vsync", vsyncJ);
  71. // fbo
  72. json_t *fboJ = json_boolean(global_ui->b_fbo);
  73. json_object_set_new(rootJ, "fbo", fboJ);
  74. // fbo_shared (dynamically loaded modules)
  75. json_t *fbo_sharedJ = json_boolean(global_ui->b_fbo_shared);
  76. json_object_set_new(rootJ, "fbo_shared", fbo_sharedJ);
  77. // touchInput
  78. int touchInput = lglw_touchinput_get(global_ui->window.lglw);
  79. json_t *touchInputJ = json_boolean(touchInput);
  80. json_object_set_new(rootJ, "touchInput", touchInputJ);
  81. // touchKbd
  82. int touchKbd = b_touchkeyboard_enable;
  83. json_t *touchKbdJ = json_boolean(touchKbd);
  84. json_object_set_new(rootJ, "touchKbd", touchKbdJ);
  85. // (realtime) oversampleFactor, oversampleQuality
  86. {
  87. float factor;
  88. int quality;
  89. vst2_oversample_realtime_get(&factor, &quality);
  90. json_t *factorJ = json_real(factor);
  91. json_object_set_new(rootJ, "oversampleFactor", factorJ);
  92. json_t *qualityJ = json_integer(quality);
  93. json_object_set_new(rootJ, "oversampleQuality", qualityJ);
  94. }
  95. // oversampleOfflineFactor, oversampleOfflineQuality
  96. {
  97. float factor;
  98. int quality;
  99. vst2_oversample_offline_get(&factor, &quality);
  100. json_t *factorJ = json_real(factor);
  101. json_object_set_new(rootJ, "oversampleOfflineFactor", factorJ);
  102. json_t *qualityJ = json_integer(quality);
  103. json_object_set_new(rootJ, "oversampleOfflineQuality", qualityJ);
  104. }
  105. // oversample offline check (oversampleOffline)
  106. json_t *offlineJ = json_boolean(vst2_oversample_offline_check_get());
  107. json_object_set_new(rootJ, "oversampleOffline", offlineJ);
  108. // oversample input channel limit (oversampleNumIn)
  109. // oversample output channel limit (oversampleNumOut)
  110. {
  111. int numIn;
  112. int numOut;
  113. vst2_oversample_channels_get(&numIn, &numOut);
  114. json_t *numInJ = json_real(numIn);
  115. json_object_set_new(rootJ, "oversampleNumIn", numInJ);
  116. json_t *numOutJ = json_real(numOut);
  117. json_object_set_new(rootJ, "oversampleNumOut", numOutJ);
  118. }
  119. // idleDetectInstr
  120. {
  121. int idleMode = vst2_idle_detect_mode_instr_get();
  122. json_t *idleJ = json_integer(idleMode);
  123. json_object_set_new(rootJ, "idleDetectInstr", idleJ);
  124. }
  125. // idleDetectFx
  126. {
  127. int idleMode = vst2_idle_detect_mode_fx_get();
  128. json_t *idleJ = json_integer(idleMode);
  129. json_object_set_new(rootJ, "idleDetectFx", idleJ);
  130. }
  131. // allowCursorLock
  132. json_t *allowCursorLockJ = json_boolean(global_ui->window.gAllowCursorLock);
  133. json_object_set_new(rootJ, "allowCursorLock", allowCursorLockJ);
  134. // sampleRate
  135. json_t *sampleRateJ = json_real(engineGetSampleRate());
  136. json_object_set_new(rootJ, "sampleRate", sampleRateJ);
  137. // fixDenorm
  138. json_t *fixDenormJ = json_boolean(vst2_fix_denorm_get());
  139. json_object_set_new(rootJ, "fixDenorm", fixDenormJ);
  140. // lastPath
  141. json_t *lastPathJ = json_string(global_ui->app.gRackWidget->lastPath.c_str());
  142. json_object_set_new(rootJ, "lastPath", lastPathJ);
  143. // skipAutosaveOnLaunch
  144. if (global->settings.gSkipAutosaveOnLaunch) {
  145. json_object_set_new(rootJ, "skipAutosaveOnLaunch", json_true());
  146. }
  147. // moduleBrowser
  148. json_object_set_new(rootJ, "moduleBrowser", appModuleBrowserToJson());
  149. // powerMeter
  150. json_object_set_new(rootJ, "powerMeter", json_boolean(global->gPowerMeter));
  151. // checkVersion
  152. json_object_set_new(rootJ, "checkVersion", json_boolean(global_ui->app.gCheckVersion));
  153. #endif // RACK_HOST
  154. return rootJ;
  155. }
  156. static void settingsFromJson(json_t *rootJ, bool bWindowSizeOnly) {
  157. // token
  158. json_t *tokenJ = json_object_get(rootJ, "token");
  159. if (tokenJ)
  160. global->plugin.gToken = json_string_value(tokenJ);
  161. // windowSize
  162. json_t *windowSizeJ = json_object_get(rootJ, "windowSize");
  163. if (windowSizeJ) {
  164. double width, height;
  165. json_unpack(windowSizeJ, "[F, F]", &width, &height);
  166. #ifdef USE_VST2
  167. // (note) calling windowSetWindowSize() causes the window to be not resizable initially, and when it is moved, it reverts to a default size (TBI)
  168. if(bWindowSizeOnly)
  169. {
  170. global_ui->window.windowWidth = int(width);
  171. global_ui->window.windowHeight = int(height);
  172. #ifdef RACK_HOST
  173. vst2_window_size_set((int)width, (int)height);
  174. #endif // RACK_HOST
  175. return;
  176. }
  177. #else
  178. windowSetWindowSize(Vec(width, height));
  179. #endif // USE_VST2
  180. }
  181. // windowPos
  182. json_t *windowPosJ = json_object_get(rootJ, "windowPos");
  183. if (windowPosJ) {
  184. double x, y;
  185. json_unpack(windowPosJ, "[F, F]", &x, &y);
  186. #ifndef USE_VST2
  187. windowSetWindowPos(Vec(x, y));
  188. #endif // USE_VST2
  189. }
  190. // opacity
  191. json_t *opacityJ = json_object_get(rootJ, "wireOpacity");
  192. if (opacityJ)
  193. global_ui->app.gToolbar->wireOpacitySlider->value = json_number_value(opacityJ);
  194. // tension
  195. json_t *tensionJ = json_object_get(rootJ, "wireTension");
  196. if (tensionJ)
  197. global_ui->app.gToolbar->wireTensionSlider->value = json_number_value(tensionJ);
  198. // zoom
  199. json_t *zoomJ = json_object_get(rootJ, "zoom");
  200. if (zoomJ) {
  201. global_ui->app.gRackScene->zoomWidget->setZoom(clamp((float) json_number_value(zoomJ), 0.25f, 4.0f));
  202. global_ui->app.gToolbar->zoomSlider->setValue(json_number_value(zoomJ) * 100.0);
  203. }
  204. // refresh rate (Hz)
  205. // (note) <15: use DAW timer (effEditIdle)
  206. json_t *refreshJ = json_object_get(rootJ, "refreshRate");
  207. if (refreshJ) {
  208. #ifdef RACK_HOST
  209. vst2_refresh_rate_set(clamp((float) json_number_value(refreshJ), 0.0f, 200.0f));
  210. #endif // RACK_HOST
  211. }
  212. // vsync
  213. if(!bWindowSizeOnly)
  214. {
  215. json_t *vsyncJ = json_object_get(rootJ, "vsync");
  216. if (vsyncJ)
  217. {
  218. // lglw_glcontext_push(global_ui->window.lglw);
  219. // lglw_swap_interval_set(global_ui->window.lglw, json_is_true(vsyncJ);
  220. // lglw_glcontext_pop(global_ui->window.lglw);
  221. // postpone until first vst2_editor_redraw() call (see window.cpp)
  222. // (note) on Linux we need a drawable to set the swap interval
  223. global_ui->pending_swap_interval = json_is_true(vsyncJ);
  224. }
  225. }
  226. // fbo support (not working with VirtualBox GL driver!)
  227. json_t *fboJ = json_object_get(rootJ, "fbo");
  228. if (fboJ)
  229. {
  230. global_ui->b_fbo = json_is_true(fboJ);
  231. }
  232. // fbo support in dynamically loaded modules (not working with VirtualBox GL driver or Windows NVidia driver)
  233. json_t *fbo_sharedJ = json_object_get(rootJ, "fbo_shared");
  234. if (fbo_sharedJ)
  235. {
  236. global_ui->b_fbo_shared = json_is_true(fbo_sharedJ);
  237. }
  238. // allowCursorLock
  239. json_t *allowCursorLockJ = json_object_get(rootJ, "allowCursorLock");
  240. if (allowCursorLockJ)
  241. {
  242. global_ui->window.gAllowCursorLock = json_is_true(allowCursorLockJ);
  243. }
  244. // touchInput
  245. if(!bWindowSizeOnly)
  246. {
  247. json_t *touchJ = json_object_get(rootJ, "touchInput");
  248. if (touchJ)
  249. {
  250. if(json_is_true(touchJ))
  251. {
  252. lglw_touchinput_set(global_ui->window.lglw, LGLW_TRUE);
  253. }
  254. }
  255. }
  256. // touchKbd
  257. if(!bWindowSizeOnly)
  258. {
  259. json_t *touchJ = json_object_get(rootJ, "touchKbd");
  260. if (touchJ)
  261. {
  262. b_touchkeyboard_enable = json_is_true(touchJ);
  263. }
  264. }
  265. #ifndef USE_VST2
  266. // sampleRate
  267. json_t *sampleRateJ = json_object_get(rootJ, "sampleRate");
  268. if (sampleRateJ) {
  269. float sampleRate = json_number_value(sampleRateJ);
  270. engineSetSampleRate(sampleRate);
  271. }
  272. #endif // USE_VST2
  273. #ifdef RACK_HOST
  274. // Realtime Oversample factor and quality
  275. {
  276. float oversampleFactor = -1.0f;
  277. int oversampleQuality = -1;
  278. // Realtime Oversample factor
  279. {
  280. json_t *oversampleJ = json_object_get(rootJ, "oversampleFactor");
  281. if (oversampleJ) {
  282. oversampleFactor = float(json_number_value(oversampleJ));
  283. }
  284. }
  285. // Realtime Oversample quality (0..10)
  286. {
  287. json_t *oversampleJ = json_object_get(rootJ, "oversampleQuality");
  288. if (oversampleJ) {
  289. oversampleQuality = int(json_number_value(oversampleJ));
  290. }
  291. }
  292. vst2_oversample_realtime_set(oversampleFactor, oversampleQuality);
  293. }
  294. // Offline Oversample factor and quality
  295. {
  296. float oversampleFactor = -1.0f;
  297. int oversampleQuality = -1;
  298. // Offline Oversample factor
  299. {
  300. json_t *oversampleJ = json_object_get(rootJ, "oversampleOfflineFactor");
  301. if (oversampleJ) {
  302. oversampleFactor = float(json_number_value(oversampleJ));
  303. }
  304. }
  305. // Offline Oversample quality (0..10)
  306. {
  307. json_t *oversampleJ = json_object_get(rootJ, "oversampleOfflineQuality");
  308. if (oversampleJ) {
  309. oversampleQuality = int(json_number_value(oversampleJ));
  310. }
  311. }
  312. vst2_oversample_offline_set(oversampleFactor, oversampleQuality);
  313. }
  314. json_t *checkOfflineJ = json_object_get(rootJ, "oversampleOffline");
  315. if (checkOfflineJ)
  316. {
  317. vst2_oversample_offline_check_set(json_is_true(checkOfflineJ));
  318. }
  319. // Oversample channel limit
  320. int oversampleNumIn = -1;
  321. int oversampleNumOut = -1;
  322. // Oversample input channel limit
  323. {
  324. json_t *oversampleJ = json_object_get(rootJ, "oversampleNumIn");
  325. if (oversampleJ) {
  326. oversampleNumIn = int(json_number_value(oversampleJ));
  327. }
  328. }
  329. // Oversample output channel limit
  330. {
  331. json_t *oversampleJ = json_object_get(rootJ, "oversampleNumOut");
  332. if (oversampleJ) {
  333. oversampleNumOut = int(json_number_value(oversampleJ));
  334. }
  335. }
  336. vst2_oversample_channels_set(oversampleNumIn, oversampleNumOut);
  337. // Idle detection mode (instrument build)
  338. {
  339. json_t *idleJ = json_object_get(rootJ, "idleDetectInstr");
  340. if (idleJ) {
  341. vst2_idle_detect_mode_instr_set(int(json_number_value(idleJ)));
  342. }
  343. }
  344. // Idle detection mode (FX build)
  345. {
  346. json_t *idleJ = json_object_get(rootJ, "idleDetectFx");
  347. if (idleJ) {
  348. vst2_idle_detect_mode_fx_set(int(json_number_value(idleJ)));
  349. }
  350. }
  351. // fixDenorm
  352. json_t *fixDenormJ = json_object_get(rootJ, "fixDenorm");
  353. if (fixDenormJ)
  354. {
  355. vst2_fix_denorm_set(json_is_true(fixDenormJ));
  356. }
  357. #endif // RACK_HOST
  358. // lastPath
  359. json_t *lastPathJ = json_object_get(rootJ, "lastPath");
  360. if (lastPathJ)
  361. global_ui->app.gRackWidget->lastPath = json_string_value(lastPathJ);
  362. // skipAutosaveOnLaunch
  363. json_t *skipAutosaveOnLaunchJ = json_object_get(rootJ, "skipAutosaveOnLaunch");
  364. if (skipAutosaveOnLaunchJ)
  365. global->settings.gSkipAutosaveOnLaunch = json_boolean_value(skipAutosaveOnLaunchJ);
  366. // moduleBrowser
  367. json_t *moduleBrowserJ = json_object_get(rootJ, "moduleBrowser");
  368. if (moduleBrowserJ)
  369. appModuleBrowserFromJson(moduleBrowserJ);
  370. // powerMeter
  371. json_t *powerMeterJ = json_object_get(rootJ, "powerMeter");
  372. if (powerMeterJ)
  373. global->gPowerMeter = json_boolean_value(powerMeterJ);
  374. // checkVersion
  375. json_t *checkVersionJ = json_object_get(rootJ, "checkVersion");
  376. if (checkVersionJ)
  377. global_ui->app.gCheckVersion = json_boolean_value(checkVersionJ);
  378. }
  379. void settingsSave(std::string filename) {
  380. info("Saving settings %s", filename.c_str());
  381. json_t *rootJ = settingsToJson();
  382. if (rootJ) {
  383. FILE *file = fopen(filename.c_str(), "w");
  384. if (!file)
  385. return;
  386. json_dumpf(rootJ, file, JSON_INDENT(2) | JSON_REAL_PRECISION(9));
  387. json_decref(rootJ);
  388. fclose(file);
  389. }
  390. }
  391. void settingsLoad(std::string filename, bool bWindowSizeOnly) {
  392. info("Loading settings %s", filename.c_str());
  393. FILE *file = fopen(filename.c_str(), "r");
  394. if (!file)
  395. return;
  396. json_error_t error;
  397. json_t *rootJ = json_loadf(file, 0, &error);
  398. if (rootJ) {
  399. settingsFromJson(rootJ, bWindowSizeOnly);
  400. json_decref(rootJ);
  401. }
  402. else {
  403. warn("JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text);
  404. }
  405. fclose(file);
  406. }
  407. } // namespace rack