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.

115 lines
2.9KB

  1. #include <unistd.h>
  2. #include "osdialog.h"
  3. #include "rack.hpp"
  4. #include "rtmidi.hpp"
  5. #include "keyboard.hpp"
  6. #include "gamepad.hpp"
  7. #include "bridge.hpp"
  8. #include "settings.hpp"
  9. #ifdef ARCH_WIN
  10. #include <Windows.h>
  11. #endif
  12. using namespace rack;
  13. int main(int argc, char* argv[]) {
  14. bool devMode = false;
  15. std::string patchFile;
  16. // Parse command line arguments
  17. int c;
  18. opterr = 0;
  19. while ((c = getopt(argc, argv, "dg:l:")) != -1) {
  20. switch (c) {
  21. case 'd': {
  22. devMode = true;
  23. } break;
  24. case 'g': {
  25. asset::globalDir = optarg;
  26. } break;
  27. case 'l': {
  28. asset::localDir = optarg;
  29. } break;
  30. default: break;
  31. }
  32. }
  33. if (optind < argc) {
  34. patchFile = argv[optind];
  35. }
  36. #ifdef ARCH_WIN
  37. // Windows global mutex to prevent multiple instances
  38. // Handle will be closed by Windows when the process ends
  39. HANDLE instanceMutex = CreateMutex(NULL, true, gApplicationName.c_str());
  40. if (GetLastError() == ERROR_ALREADY_EXISTS) {
  41. osdialog_message(OSDIALOG_ERROR, OSDIALOG_OK, "Rack is already running. Multiple Rack instances are not supported.");
  42. exit(1);
  43. }
  44. (void) instanceMutex;
  45. #endif
  46. // Initialize environment
  47. random::init();
  48. asset::init(devMode);
  49. logger::init(devMode);
  50. // Log environment
  51. INFO("%s %s", gApplicationName.c_str(), gApplicationVersion.c_str());
  52. if (devMode)
  53. INFO("Development mode");
  54. INFO("Global directory: %s", asset::global("").c_str());
  55. INFO("Local directory: %s", asset::local("").c_str());
  56. // Initialize app
  57. pluginInit(devMode);
  58. engineInit();
  59. rtmidiInit();
  60. bridgeInit();
  61. keyboard::init();
  62. gamepad::init();
  63. appInit(devMode);
  64. windowInit();
  65. settings::load(asset::local("settings.json"));
  66. if (patchFile.empty()) {
  67. // 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.
  68. bool oldSkipAutosaveOnLaunch = settings::gSkipAutosaveOnLaunch;
  69. settings::gSkipAutosaveOnLaunch = true;
  70. settings::save(asset::local("settings.json"));
  71. settings::gSkipAutosaveOnLaunch = false;
  72. if (oldSkipAutosaveOnLaunch && 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?")) {
  73. gRackWidget->lastPath = "";
  74. }
  75. else {
  76. // Load autosave
  77. std::string oldLastPath = gRackWidget->lastPath;
  78. gRackWidget->load(asset::local("autosave.vcv"));
  79. gRackWidget->lastPath = oldLastPath;
  80. }
  81. }
  82. else {
  83. // Load patch
  84. gRackWidget->load(patchFile);
  85. gRackWidget->lastPath = patchFile;
  86. }
  87. engineStart();
  88. windowRun();
  89. engineStop();
  90. // Destroy namespaces
  91. gRackWidget->save(asset::local("autosave.vcv"));
  92. settings::save(asset::local("settings.json"));
  93. appDestroy();
  94. windowDestroy();
  95. bridgeDestroy();
  96. engineDestroy();
  97. midiDestroy();
  98. pluginDestroy();
  99. logger::destroy();
  100. return 0;
  101. }