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.

284 lines
8.2KB

  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 <context.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. KnobMode knobMode = KNOB_MODE_LINEAR;
  23. float knobLinearSensitivity = 0.001f;
  24. float sampleRate = 44100.0;
  25. int threadCount = 1;
  26. bool paramTooltip = true;
  27. bool cpuMeter = false;
  28. bool lockModules = false;
  29. #if defined ARCH_MAC
  30. // Most Mac GPUs can't handle rendering the screen every frame, so use ~30 Hz by default.
  31. int frameSwapInterval = 2;
  32. #else
  33. int frameSwapInterval = 1;
  34. #endif
  35. float autosavePeriod = 15.0;
  36. bool skipLoadOnLaunch = false;
  37. std::string patchPath;
  38. std::list<std::string> recentPatchPaths;
  39. std::vector<NVGcolor> cableColors = {
  40. color::fromHexString("#fc2d5aff"), // red
  41. color::fromHexString("#f9b130ff"), // orange
  42. // color::fromHexString("#f7da31ff"), // yellow
  43. color::fromHexString("#67c12dff"), // green
  44. color::fromHexString("#0f8df4ff"), // blue
  45. color::fromHexString("#8c1889ff"), // purple
  46. };
  47. std::map<std::string, std::vector<std::string>> moduleWhitelist = {};
  48. json_t* toJson() {
  49. json_t* rootJ = json_object();
  50. json_object_set_new(rootJ, "token", json_string(token.c_str()));
  51. json_t* windowSizeJ = json_pack("[f, f]", windowSize.x, windowSize.y);
  52. json_object_set_new(rootJ, "windowSize", windowSizeJ);
  53. json_t* windowPosJ = json_pack("[f, f]", windowPos.x, windowPos.y);
  54. json_object_set_new(rootJ, "windowPos", windowPosJ);
  55. json_object_set_new(rootJ, "zoom", json_real(zoom));
  56. json_object_set_new(rootJ, "invertZoom", json_boolean(invertZoom));
  57. json_object_set_new(rootJ, "cableOpacity", json_real(cableOpacity));
  58. json_object_set_new(rootJ, "cableTension", json_real(cableTension));
  59. json_object_set_new(rootJ, "allowCursorLock", json_boolean(allowCursorLock));
  60. json_object_set_new(rootJ, "knobMode", json_integer((int) knobMode));
  61. json_object_set_new(rootJ, "knobLinearSensitivity", json_real(knobLinearSensitivity));
  62. json_object_set_new(rootJ, "sampleRate", json_real(sampleRate));
  63. json_object_set_new(rootJ, "threadCount", json_integer(threadCount));
  64. json_object_set_new(rootJ, "paramTooltip", json_boolean(paramTooltip));
  65. json_object_set_new(rootJ, "cpuMeter", json_boolean(cpuMeter));
  66. json_object_set_new(rootJ, "lockModules", json_boolean(lockModules));
  67. json_object_set_new(rootJ, "frameSwapInterval", json_integer(frameSwapInterval));
  68. json_object_set_new(rootJ, "autosavePeriod", json_real(autosavePeriod));
  69. if (skipLoadOnLaunch)
  70. json_object_set_new(rootJ, "skipLoadOnLaunch", json_boolean(true));
  71. json_object_set_new(rootJ, "patchPath", json_string(patchPath.c_str()));
  72. json_t* recentPatchPathsJ = json_array();
  73. for (const std::string& path : recentPatchPaths) {
  74. json_array_append_new(recentPatchPathsJ, json_string(path.c_str()));
  75. }
  76. json_object_set_new(rootJ, "recentPatchPaths", recentPatchPathsJ);
  77. json_t* cableColorsJ = json_array();
  78. for (NVGcolor cableColor : cableColors) {
  79. std::string colorStr = color::toHexString(cableColor);
  80. json_array_append_new(cableColorsJ, json_string(colorStr.c_str()));
  81. }
  82. json_object_set_new(rootJ, "cableColors", cableColorsJ);
  83. json_t* moduleWhitelistJ = json_object();
  84. for (const auto& pair : moduleWhitelist) {
  85. json_t* moduleSlugsJ = json_array();
  86. for (const std::string& moduleSlug : pair.second) {
  87. json_array_append_new(moduleSlugsJ, json_string(moduleSlug.c_str()));
  88. }
  89. json_object_set_new(moduleWhitelistJ, pair.first.c_str(), moduleSlugsJ);
  90. }
  91. json_object_set_new(rootJ, "moduleWhitelist", moduleWhitelistJ);
  92. return rootJ;
  93. }
  94. void fromJson(json_t* rootJ) {
  95. json_t* tokenJ = json_object_get(rootJ, "token");
  96. if (tokenJ)
  97. token = json_string_value(tokenJ);
  98. json_t* windowSizeJ = json_object_get(rootJ, "windowSize");
  99. if (windowSizeJ) {
  100. double x, y;
  101. json_unpack(windowSizeJ, "[F, F]", &x, &y);
  102. windowSize = math::Vec(x, y);
  103. }
  104. json_t* windowPosJ = json_object_get(rootJ, "windowPos");
  105. if (windowPosJ) {
  106. double x, y;
  107. json_unpack(windowPosJ, "[F, F]", &x, &y);
  108. windowPos = math::Vec(x, y);
  109. }
  110. json_t* zoomJ = json_object_get(rootJ, "zoom");
  111. if (zoomJ)
  112. zoom = json_number_value(zoomJ);
  113. json_t* invertZoomJ = json_object_get(rootJ, "invertZoom");
  114. if (invertZoomJ)
  115. invertZoom = json_boolean_value(invertZoomJ);
  116. json_t* cableOpacityJ = json_object_get(rootJ, "cableOpacity");
  117. if (cableOpacityJ)
  118. cableOpacity = json_number_value(cableOpacityJ);
  119. json_t* cableTensionJ = json_object_get(rootJ, "cableTension");
  120. if (cableTensionJ)
  121. cableTension = json_number_value(cableTensionJ);
  122. json_t* allowCursorLockJ = json_object_get(rootJ, "allowCursorLock");
  123. if (allowCursorLockJ)
  124. allowCursorLock = json_boolean_value(allowCursorLockJ);
  125. json_t* knobModeJ = json_object_get(rootJ, "knobMode");
  126. if (knobModeJ)
  127. knobMode = (KnobMode) json_integer_value(knobModeJ);
  128. json_t* knobLinearSensitivityJ = json_object_get(rootJ, "knobLinearSensitivity");
  129. if (knobLinearSensitivityJ)
  130. knobLinearSensitivity = json_number_value(knobLinearSensitivityJ);
  131. json_t* sampleRateJ = json_object_get(rootJ, "sampleRate");
  132. if (sampleRateJ)
  133. sampleRate = json_number_value(sampleRateJ);
  134. json_t* threadCountJ = json_object_get(rootJ, "threadCount");
  135. if (threadCountJ)
  136. threadCount = json_integer_value(threadCountJ);
  137. json_t* paramTooltipJ = json_object_get(rootJ, "paramTooltip");
  138. if (paramTooltipJ)
  139. paramTooltip = json_boolean_value(paramTooltipJ);
  140. json_t* cpuMeterJ = json_object_get(rootJ, "cpuMeter");
  141. if (cpuMeterJ)
  142. cpuMeter = json_boolean_value(cpuMeterJ);
  143. json_t* lockModulesJ = json_object_get(rootJ, "lockModules");
  144. if (lockModulesJ)
  145. lockModules = json_boolean_value(lockModulesJ);
  146. json_t* frameSwapIntervalJ = json_object_get(rootJ, "frameSwapInterval");
  147. if (frameSwapIntervalJ)
  148. frameSwapInterval = json_integer_value(frameSwapIntervalJ);
  149. json_t* autosavePeriodJ = json_object_get(rootJ, "autosavePeriod");
  150. if (autosavePeriodJ)
  151. autosavePeriod = json_number_value(autosavePeriodJ);
  152. json_t* skipLoadOnLaunchJ = json_object_get(rootJ, "skipLoadOnLaunch");
  153. if (skipLoadOnLaunchJ)
  154. skipLoadOnLaunch = json_boolean_value(skipLoadOnLaunchJ);
  155. json_t* patchPathJ = json_object_get(rootJ, "patchPath");
  156. if (patchPathJ)
  157. patchPath = json_string_value(patchPathJ);
  158. recentPatchPaths.clear();
  159. json_t* recentPatchPathsJ = json_object_get(rootJ, "recentPatchPaths");
  160. if (recentPatchPathsJ) {
  161. size_t i;
  162. json_t* pathJ;
  163. json_array_foreach(recentPatchPathsJ, i, pathJ) {
  164. std::string path = json_string_value(pathJ);
  165. recentPatchPaths.push_back(path);
  166. }
  167. }
  168. cableColors.clear();
  169. json_t* cableColorsJ = json_object_get(rootJ, "cableColors");
  170. if (cableColorsJ) {
  171. size_t i;
  172. json_t* cableColorJ;
  173. json_array_foreach(cableColorsJ, i, cableColorJ) {
  174. std::string colorStr = json_string_value(cableColorJ);
  175. cableColors.push_back(color::fromHexString(colorStr));
  176. }
  177. }
  178. moduleWhitelist.clear();
  179. json_t* moduleWhitelistJ = json_object_get(rootJ, "moduleWhitelist");
  180. if (moduleWhitelistJ) {
  181. const char* pluginSlug;
  182. json_t* moduleSlugsJ;
  183. json_object_foreach(moduleWhitelistJ, pluginSlug, moduleSlugsJ) {
  184. auto& moduleSlugs = moduleWhitelist[pluginSlug];
  185. size_t i;
  186. json_t* moduleSlugJ;
  187. json_array_foreach(moduleSlugsJ, i, moduleSlugJ) {
  188. std::string moduleSlug = json_string_value(moduleSlugJ);
  189. moduleSlugs.push_back(moduleSlug);
  190. }
  191. }
  192. }
  193. }
  194. void save(const std::string& path) {
  195. INFO("Saving settings %s", path.c_str());
  196. json_t* rootJ = toJson();
  197. if (!rootJ)
  198. return;
  199. FILE* file = fopen(path.c_str(), "w");
  200. if (!file)
  201. return;
  202. DEFER({
  203. fclose(file);
  204. });
  205. json_dumpf(rootJ, file, JSON_INDENT(2) | JSON_REAL_PRECISION(9));
  206. json_decref(rootJ);
  207. }
  208. void load(const std::string& path) {
  209. INFO("Loading settings %s", path.c_str());
  210. FILE* file = fopen(path.c_str(), "r");
  211. if (!file)
  212. return;
  213. DEFER({
  214. fclose(file);
  215. });
  216. json_error_t error;
  217. json_t* rootJ = json_loadf(file, 0, &error);
  218. if (!rootJ)
  219. throw Exception(string::f("Settings file has invalid JSON at %d:%d %s", error.line, error.column, error.text));
  220. fromJson(rootJ);
  221. json_decref(rootJ);
  222. }
  223. } // namespace settings
  224. } // namespace rack