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.

172 lines
3.6KB

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