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.

134 lines
3.3KB

  1. #include "common.hpp"
  2. #include "random.hpp"
  3. #include "asset.hpp"
  4. #include "midi.hpp"
  5. #include "rtmidi.hpp"
  6. #include "keyboard.hpp"
  7. #include "gamepad.hpp"
  8. #include "bridge.hpp"
  9. #include "settings.hpp"
  10. #include "engine/Engine.hpp"
  11. #include "app/Scene.hpp"
  12. #include "plugin.hpp"
  13. #include "app.hpp"
  14. #include "ui.hpp"
  15. #include <unistd.h>
  16. #include <osdialog.h>
  17. #ifdef ARCH_WIN
  18. #include <Windows.h>
  19. #endif
  20. using namespace rack;
  21. int main(int argc, char *argv[]) {
  22. #ifdef ARCH_WIN
  23. // Windows global mutex to prevent multiple instances
  24. // Handle will be closed by Windows when the process ends
  25. HANDLE instanceMutex = CreateMutex(NULL, true, APP_NAME.c_str());
  26. if (GetLastError() == ERROR_ALREADY_EXISTS) {
  27. osdialog_message(OSDIALOG_ERROR, OSDIALOG_OK, "Rack is already running. Multiple Rack instances are not supported.");
  28. exit(1);
  29. }
  30. (void) instanceMutex;
  31. #endif
  32. bool devMode = false;
  33. std::string patchFile;
  34. // Parse command line arguments
  35. int c;
  36. opterr = 0;
  37. while ((c = getopt(argc, argv, "ds:u:")) != -1) {
  38. switch (c) {
  39. case 'd': {
  40. devMode = true;
  41. } break;
  42. case 's': {
  43. asset::systemDir = optarg;
  44. } break;
  45. case 'u': {
  46. asset::userDir = optarg;
  47. } break;
  48. default: break;
  49. }
  50. }
  51. if (optind < argc) {
  52. patchFile = argv[optind];
  53. }
  54. // Initialize environment
  55. asset::init(devMode);
  56. logger::init(devMode);
  57. // Log environment
  58. INFO("%s %s", APP_NAME.c_str(), APP_VERSION.c_str());
  59. if (devMode)
  60. INFO("Development mode");
  61. INFO("System directory: %s", asset::systemDir.c_str());
  62. INFO("User directory: %s", asset::userDir.c_str());
  63. random::init();
  64. midi::init();
  65. rtmidiInit();
  66. bridgeInit();
  67. keyboard::init();
  68. gamepad::init();
  69. ui::init();
  70. plugin::init(devMode);
  71. windowInit();
  72. INFO("Initialized environment");
  73. // Initialize app
  74. appInit();
  75. app()->scene->devMode = devMode;
  76. settings::load(asset::user("settings.json"));
  77. if (patchFile.empty()) {
  78. // To prevent launch crashes, if Rack crashes between now and 15 seconds from now, the "skipAutosaveOnLaunch" property will remain in settings.json, so that in the next launch, the broken autosave will not be loaded.
  79. bool oldSkipLoadOnLaunch = settings::skipLoadOnLaunch;
  80. settings::skipLoadOnLaunch = true;
  81. settings::save(asset::user("settings.json"));
  82. settings::skipLoadOnLaunch = false;
  83. if (oldSkipLoadOnLaunch && osdialog_message(OSDIALOG_INFO, OSDIALOG_YES_NO, "Rack has recovered from a crash, possibly caused by a faulty module in your patch. Clear your patch and start over?")) {
  84. app()->scene->rackWidget->lastPath = "";
  85. }
  86. else {
  87. // Load autosave
  88. std::string oldLastPath = app()->scene->rackWidget->lastPath;
  89. app()->scene->rackWidget->load(asset::user("autosave.vcv"));
  90. app()->scene->rackWidget->lastPath = oldLastPath;
  91. }
  92. }
  93. else {
  94. // Load patch
  95. app()->scene->rackWidget->load(patchFile);
  96. app()->scene->rackWidget->lastPath = patchFile;
  97. }
  98. INFO("Initialized app");
  99. app()->engine->start();
  100. app()->window->run();
  101. INFO("Window closed");
  102. app()->engine->stop();
  103. // Destroy app
  104. app()->scene->rackWidget->save(asset::user("autosave.vcv"));
  105. settings::save(asset::user("settings.json"));
  106. appDestroy();
  107. INFO("Cleaned up app");
  108. // Destroy environment
  109. windowDestroy();
  110. plugin::destroy();
  111. ui::destroy();
  112. bridgeDestroy();
  113. midi::destroy();
  114. INFO("Cleaned up environment");
  115. logger::destroy();
  116. return 0;
  117. }