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.

settings.cpp 6.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. #include <settings.hpp>
  2. #include <window.hpp>
  3. #include <plugin.hpp>
  4. #include <app/Scene.hpp>
  5. #include <app/ModuleBrowser.hpp>
  6. #include <engine/Engine.hpp>
  7. #include <app.hpp>
  8. #include <patch.hpp>
  9. #include <jansson.h>
  10. namespace rack {
  11. namespace settings {
  12. bool devMode = false;
  13. bool headless = false;
  14. std::string token;
  15. math::Vec windowSize;
  16. math::Vec windowPos;
  17. float zoom = 0.0;
  18. bool invertZoom = false;
  19. float cableOpacity = 0.5;
  20. float cableTension = 0.5;
  21. bool allowCursorLock = true;
  22. bool realTime = false;
  23. float sampleRate = 44100.0;
  24. int threadCount = 1;
  25. bool paramTooltip = false;
  26. bool cpuMeter = false;
  27. bool lockModules = false;
  28. #if defined ARCH_MAC
  29. // Most Mac GPUs can't handle rendering the screen every frame, so use ~30 Hz by default.
  30. int frameSwapInterval = 2;
  31. #else
  32. int frameSwapInterval = 1;
  33. #endif
  34. float autosavePeriod = 15.0;
  35. bool skipLoadOnLaunch = false;
  36. std::string patchPath;
  37. std::vector<NVGcolor> cableColors = {
  38. nvgRGB(0xc9, 0xb7, 0x0e), // yellow
  39. nvgRGB(0x0c, 0x8e, 0x15), // green
  40. nvgRGB(0xc9, 0x18, 0x47), // red
  41. nvgRGB(0x09, 0x86, 0xad), // blue
  42. };
  43. json_t* toJson() {
  44. json_t* rootJ = json_object();
  45. json_object_set_new(rootJ, "token", json_string(token.c_str()));
  46. json_t* windowSizeJ = json_pack("[f, f]", windowSize.x, windowSize.y);
  47. json_object_set_new(rootJ, "windowSize", windowSizeJ);
  48. json_t* windowPosJ = json_pack("[f, f]", windowPos.x, windowPos.y);
  49. json_object_set_new(rootJ, "windowPos", windowPosJ);
  50. json_object_set_new(rootJ, "zoom", json_real(zoom));
  51. json_object_set_new(rootJ, "invertZoom", json_boolean(invertZoom));
  52. json_object_set_new(rootJ, "cableOpacity", json_real(cableOpacity));
  53. json_object_set_new(rootJ, "cableTension", json_real(cableTension));
  54. json_object_set_new(rootJ, "allowCursorLock", json_boolean(allowCursorLock));
  55. json_object_set_new(rootJ, "realTime", json_boolean(realTime));
  56. json_object_set_new(rootJ, "sampleRate", json_real(sampleRate));
  57. json_object_set_new(rootJ, "threadCount", json_integer(threadCount));
  58. json_object_set_new(rootJ, "paramTooltip", json_boolean(paramTooltip));
  59. json_object_set_new(rootJ, "cpuMeter", json_boolean(cpuMeter));
  60. json_object_set_new(rootJ, "lockModules", json_boolean(lockModules));
  61. json_object_set_new(rootJ, "frameSwapInterval", json_integer(frameSwapInterval));
  62. json_object_set_new(rootJ, "autosavePeriod", json_real(autosavePeriod));
  63. if (skipLoadOnLaunch) {
  64. json_object_set_new(rootJ, "skipLoadOnLaunch", json_true());
  65. }
  66. json_object_set_new(rootJ, "patchPath", json_string(patchPath.c_str()));
  67. json_t* cableColorsJ = json_array();
  68. for (NVGcolor cableColor : cableColors) {
  69. std::string colorStr = color::toHexString(cableColor);
  70. json_array_append_new(cableColorsJ, json_string(colorStr.c_str()));
  71. }
  72. json_object_set_new(rootJ, "cableColors", cableColorsJ);
  73. return rootJ;
  74. }
  75. void fromJson(json_t* rootJ) {
  76. json_t* tokenJ = json_object_get(rootJ, "token");
  77. if (tokenJ)
  78. token = json_string_value(tokenJ);
  79. json_t* windowSizeJ = json_object_get(rootJ, "windowSize");
  80. if (windowSizeJ) {
  81. double x, y;
  82. json_unpack(windowSizeJ, "[F, F]", &x, &y);
  83. windowSize = math::Vec(x, y);
  84. }
  85. json_t* windowPosJ = json_object_get(rootJ, "windowPos");
  86. if (windowPosJ) {
  87. double x, y;
  88. json_unpack(windowPosJ, "[F, F]", &x, &y);
  89. windowPos = math::Vec(x, y);
  90. }
  91. json_t* zoomJ = json_object_get(rootJ, "zoom");
  92. if (zoomJ)
  93. zoom = json_number_value(zoomJ);
  94. json_t* invertZoomJ = json_object_get(rootJ, "invertZoom");
  95. if (invertZoomJ)
  96. invertZoom = json_boolean_value(invertZoomJ);
  97. json_t* cableOpacityJ = json_object_get(rootJ, "cableOpacity");
  98. if (cableOpacityJ)
  99. cableOpacity = json_number_value(cableOpacityJ);
  100. json_t* tensionJ = json_object_get(rootJ, "cableTension");
  101. if (tensionJ)
  102. cableTension = json_number_value(tensionJ);
  103. json_t* allowCursorLockJ = json_object_get(rootJ, "allowCursorLock");
  104. if (allowCursorLockJ)
  105. allowCursorLock = json_is_true(allowCursorLockJ);
  106. json_t* realTimeJ = json_object_get(rootJ, "realTime");
  107. if (realTimeJ)
  108. realTime = json_boolean_value(realTimeJ);
  109. json_t* sampleRateJ = json_object_get(rootJ, "sampleRate");
  110. if (sampleRateJ)
  111. sampleRate = json_number_value(sampleRateJ);
  112. json_t* threadCountJ = json_object_get(rootJ, "threadCount");
  113. if (threadCountJ)
  114. threadCount = json_integer_value(threadCountJ);
  115. json_t* paramTooltipJ = json_object_get(rootJ, "paramTooltip");
  116. if (paramTooltipJ)
  117. paramTooltip = json_boolean_value(paramTooltipJ);
  118. json_t* cpuMeterJ = json_object_get(rootJ, "cpuMeter");
  119. if (cpuMeterJ)
  120. cpuMeter = json_boolean_value(cpuMeterJ);
  121. json_t* lockModulesJ = json_object_get(rootJ, "lockModules");
  122. if (lockModulesJ)
  123. lockModules = json_boolean_value(lockModulesJ);
  124. json_t* frameSwapIntervalJ = json_object_get(rootJ, "frameSwapInterval");
  125. if (frameSwapIntervalJ)
  126. frameSwapInterval = json_integer_value(frameSwapIntervalJ);
  127. json_t* autosavePeriodJ = json_object_get(rootJ, "autosavePeriod");
  128. if (autosavePeriodJ)
  129. autosavePeriod = json_number_value(autosavePeriodJ);
  130. json_t* skipLoadOnLaunchJ = json_object_get(rootJ, "skipLoadOnLaunch");
  131. if (skipLoadOnLaunchJ)
  132. skipLoadOnLaunch = json_boolean_value(skipLoadOnLaunchJ);
  133. json_t* patchPathJ = json_object_get(rootJ, "patchPath");
  134. if (patchPathJ)
  135. patchPath = json_string_value(patchPathJ);
  136. json_t* cableColorsJ = json_object_get(rootJ, "cableColors");
  137. if (cableColorsJ) {
  138. cableColors.clear();
  139. size_t i;
  140. json_t* cableColorJ;
  141. json_array_foreach(cableColorsJ, i, cableColorJ) {
  142. std::string colorStr = json_string_value(cableColorJ);
  143. cableColors.push_back(color::fromHexString(colorStr));
  144. }
  145. }
  146. }
  147. void save(const std::string& path) {
  148. INFO("Saving settings %s", path.c_str());
  149. json_t* rootJ = toJson();
  150. if (!rootJ)
  151. return;
  152. FILE* file = fopen(path.c_str(), "w");
  153. if (!file)
  154. return;
  155. DEFER({
  156. fclose(file);
  157. });
  158. json_dumpf(rootJ, file, JSON_INDENT(2) | JSON_REAL_PRECISION(9));
  159. json_decref(rootJ);
  160. }
  161. void load(const std::string& path) {
  162. INFO("Loading settings %s", path.c_str());
  163. FILE* file = fopen(path.c_str(), "r");
  164. if (!file)
  165. return;
  166. DEFER({
  167. fclose(file);
  168. });
  169. json_error_t error;
  170. json_t* rootJ = json_loadf(file, 0, &error);
  171. if (!rootJ)
  172. throw UserException(string::f("Settings file has invalid JSON at %d:%d %s", error.line, error.column, error.text));
  173. fromJson(rootJ);
  174. json_decref(rootJ);
  175. }
  176. } // namespace settings
  177. } // namespace rack