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.

168 lines
3.5KB

  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 "patch.hpp"
  15. #include "ui.hpp"
  16. #include "system.hpp"
  17. #include <osdialog.h>
  18. #include <thread>
  19. #include <unistd.h> // for getopt
  20. #include <signal.h> // for signal
  21. #if defined ARCH_WIN
  22. #include <windows.h> // for CreateMutex
  23. #endif
  24. using namespace rack;
  25. static void fatalSignalHandler(int sig) {
  26. // Only catch one signal
  27. static bool caught = false;
  28. bool localCaught = caught;
  29. caught = true;
  30. if (localCaught)
  31. exit(1);
  32. FATAL("Fatal signal %d. Stack trace:\n%s", sig, system::getStackTrace().c_str());
  33. osdialog_message(OSDIALOG_ERROR, OSDIALOG_OK, "Rack has crashed. See log.txt for details.");
  34. exit(1);
  35. }
  36. int main(int argc, char *argv[]) {
  37. #if defined ARCH_WIN
  38. // Windows global mutex to prevent multiple instances
  39. // Handle will be closed by Windows when the process ends
  40. HANDLE instanceMutex = CreateMutex(NULL, true, app::APP_NAME);
  41. if (GetLastError() == ERROR_ALREADY_EXISTS) {
  42. osdialog_message(OSDIALOG_ERROR, OSDIALOG_OK, "Rack is already running. Multiple Rack instances are not supported.");
  43. exit(1);
  44. }
  45. (void) instanceMutex;
  46. #endif
  47. bool devMode = false;
  48. bool headless = false;
  49. std::string patchPath;
  50. // Parse command line arguments
  51. int c;
  52. opterr = 0;
  53. while ((c = getopt(argc, argv, "ds:u:")) != -1) {
  54. switch (c) {
  55. case 'd': {
  56. devMode = true;
  57. } break;
  58. case 'h': {
  59. headless = true;
  60. } break;
  61. case 's': {
  62. asset::systemDir = optarg;
  63. } break;
  64. case 'u': {
  65. asset::userDir = optarg;
  66. } break;
  67. default: break;
  68. }
  69. }
  70. if (optind < argc) {
  71. patchPath = argv[optind];
  72. }
  73. // Initialize environment
  74. asset::init(devMode);
  75. logger::init(devMode);
  76. // We can now install a signal handler and log the output
  77. // Mac has its own decent crash handler
  78. #if defined ARCH_LIN || defined ARCH_WIN
  79. if (!devMode) {
  80. signal(SIGABRT, fatalSignalHandler);
  81. signal(SIGFPE, fatalSignalHandler);
  82. signal(SIGILL, fatalSignalHandler);
  83. signal(SIGSEGV, fatalSignalHandler);
  84. signal(SIGTERM, fatalSignalHandler);
  85. }
  86. #endif
  87. // Log environment
  88. INFO("%s v%s", app::APP_NAME, app::APP_VERSION);
  89. if (devMode)
  90. INFO("Development mode");
  91. INFO("System directory: %s", asset::systemDir.c_str());
  92. INFO("User directory: %s", asset::userDir.c_str());
  93. INFO("Initializing environment");
  94. random::init();
  95. midi::init();
  96. rtmidiInit();
  97. bridgeInit();
  98. keyboard::init();
  99. gamepad::init();
  100. plugin::init();
  101. if (!headless) {
  102. ui::init();
  103. windowInit();
  104. }
  105. // Initialize app
  106. INFO("Initializing app");
  107. settings.load(asset::user("settings.json"));
  108. appInit(headless);
  109. if (!headless) {
  110. APP->scene->devMode = devMode;
  111. APP->patch->init(patchPath);
  112. }
  113. INFO("Starting engine");
  114. APP->engine->start();
  115. if (!headless) {
  116. INFO("Running window");
  117. APP->window->run();
  118. INFO("Stopped window");
  119. }
  120. else {
  121. // TEMP Prove that the app doesn't crash
  122. std::this_thread::sleep_for(std::chrono::seconds(2));
  123. }
  124. INFO("Stopping engine");
  125. APP->engine->stop();
  126. // Destroy app
  127. if (!headless) {
  128. APP->patch->save(asset::user("autosave.vcv"));
  129. }
  130. INFO("Destroying app");
  131. appDestroy();
  132. settings.save(asset::user("settings.json"));
  133. // Destroy environment
  134. INFO("Destroying environment");
  135. if (!headless) {
  136. windowDestroy();
  137. ui::destroy();
  138. }
  139. plugin::destroy();
  140. bridgeDestroy();
  141. midi::destroy();
  142. INFO("Destroying logger");
  143. logger::destroy();
  144. return 0;
  145. }