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.

145 lines
3.1KB

  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 <unistd.h> // for getopt
  19. #include <signal.h> // for signal
  20. #if defined ARCH_WIN
  21. #include <windows.h> // for CreateMutex
  22. #endif
  23. using namespace rack;
  24. static void fatalSignalHandler(int sig) {
  25. // Only catch one signal
  26. static bool caught = false;
  27. bool localCaught = caught;
  28. caught = true;
  29. if (localCaught)
  30. exit(1);
  31. FATAL("Fatal signal %d. Stack trace:\n%s", sig, system::getStackTrace().c_str());
  32. osdialog_message(OSDIALOG_ERROR, OSDIALOG_OK, "Rack has crashed. See log.txt for details.");
  33. exit(1);
  34. }
  35. int main(int argc, char *argv[]) {
  36. #if defined 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, app::APP_NAME);
  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. bool devMode = false;
  47. std::string patchPath;
  48. // Parse command line arguments
  49. int c;
  50. opterr = 0;
  51. while ((c = getopt(argc, argv, "ds:u:")) != -1) {
  52. switch (c) {
  53. case 'd': {
  54. devMode = true;
  55. } break;
  56. case 's': {
  57. asset::systemDir = optarg;
  58. } break;
  59. case 'u': {
  60. asset::userDir = optarg;
  61. } break;
  62. default: break;
  63. }
  64. }
  65. if (optind < argc) {
  66. patchPath = argv[optind];
  67. }
  68. // Initialize environment
  69. asset::init(devMode);
  70. logger::init(devMode);
  71. // We can now install a signal handler and log the output
  72. // Mac has its own decent crash handler
  73. #if defined ARCH_LIN || defined ARCH_WIN
  74. if (!devMode) {
  75. signal(SIGABRT, fatalSignalHandler);
  76. signal(SIGFPE, fatalSignalHandler);
  77. signal(SIGILL, fatalSignalHandler);
  78. signal(SIGSEGV, fatalSignalHandler);
  79. signal(SIGTERM, fatalSignalHandler);
  80. }
  81. #endif
  82. // Log environment
  83. INFO("%s v%s", app::APP_NAME, app::APP_VERSION);
  84. if (devMode)
  85. INFO("Development mode");
  86. INFO("System directory: %s", asset::systemDir.c_str());
  87. INFO("User directory: %s", asset::userDir.c_str());
  88. random::init();
  89. midi::init();
  90. rtmidiInit();
  91. bridgeInit();
  92. keyboard::init();
  93. gamepad::init();
  94. ui::init();
  95. plugin::init(devMode);
  96. windowInit();
  97. INFO("Initialized environment");
  98. // Initialize app
  99. settings.load(asset::user("settings.json"));
  100. app::init();
  101. APP->scene->devMode = devMode;
  102. APP->patch->init(patchPath);
  103. INFO("Initialized app");
  104. APP->engine->start();
  105. APP->window->run();
  106. INFO("Window closed");
  107. APP->engine->stop();
  108. // Destroy app
  109. APP->patch->save(asset::user("autosave.vcv"));
  110. app::destroy();
  111. settings.save(asset::user("settings.json"));
  112. INFO("Cleaned up app");
  113. // Destroy environment
  114. windowDestroy();
  115. plugin::destroy();
  116. ui::destroy();
  117. bridgeDestroy();
  118. midi::destroy();
  119. INFO("Cleaned up environment");
  120. logger::destroy();
  121. return 0;
  122. }