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.

203 lines
4.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/common.hpp>
  12. #include <app/Scene.hpp>
  13. #include <plugin.hpp>
  14. #include <app.hpp>
  15. #include <patch.hpp>
  16. #include <ui.hpp>
  17. #include <system.hpp>
  18. #include <string.hpp>
  19. #include <osdialog.h>
  20. #include <thread>
  21. #include <unistd.h> // for getopt
  22. #include <signal.h> // for signal
  23. #if defined ARCH_WIN
  24. #include <windows.h> // for CreateMutex
  25. #endif
  26. using namespace rack;
  27. static void fatalSignalHandler(int sig) {
  28. // Only catch one signal
  29. static bool caught = false;
  30. bool localCaught = caught;
  31. caught = true;
  32. if (localCaught)
  33. exit(1);
  34. FATAL("Fatal signal %d. Stack trace:\n%s", sig, system::getStackTrace().c_str());
  35. // osdialog_message(OSDIALOG_ERROR, OSDIALOG_OK, "Rack has crashed. See log.txt for details.");
  36. exit(1);
  37. }
  38. int main(int argc, char *argv[]) {
  39. #if defined ARCH_WIN
  40. // Windows global mutex to prevent multiple instances
  41. // Handle will be closed by Windows when the process ends
  42. HANDLE instanceMutex = CreateMutexA(NULL, true, app::APP_NAME.c_str());
  43. if (GetLastError() == ERROR_ALREADY_EXISTS) {
  44. osdialog_message(OSDIALOG_ERROR, OSDIALOG_OK, "Rack is already running. Multiple Rack instances are not supported.");
  45. exit(1);
  46. }
  47. (void) instanceMutex;
  48. #endif
  49. std::string patchPath;
  50. bool screenshot = false;
  51. float screenshotZoom = 1.f;
  52. // Parse command line arguments
  53. int c;
  54. opterr = 0;
  55. while ((c = getopt(argc, argv, "dhp:s:u:")) != -1) {
  56. switch (c) {
  57. case 'd': {
  58. settings::devMode = true;
  59. } break;
  60. case 'h': {
  61. settings::headless = true;
  62. } break;
  63. case 'p': {
  64. screenshot = true;
  65. sscanf(optarg, "%f", &screenshotZoom);
  66. } break;
  67. case 's': {
  68. asset::systemDir = optarg;
  69. } break;
  70. case 'u': {
  71. asset::userDir = optarg;
  72. } break;
  73. default: break;
  74. }
  75. }
  76. if (optind < argc) {
  77. patchPath = argv[optind];
  78. }
  79. asset::init();
  80. logger::init();
  81. // We can now install a signal handler and log the output
  82. // Mac has its own decent crash handler
  83. #if 0
  84. if (!settings::devMode) {
  85. signal(SIGABRT, fatalSignalHandler);
  86. signal(SIGFPE, fatalSignalHandler);
  87. signal(SIGILL, fatalSignalHandler);
  88. signal(SIGSEGV, fatalSignalHandler);
  89. signal(SIGTERM, fatalSignalHandler);
  90. }
  91. #endif
  92. // Log environment
  93. INFO("%s v%s", app::APP_NAME.c_str(), app::APP_VERSION.c_str());
  94. INFO("%s", system::getOperatingSystemInfo().c_str());
  95. if (settings::devMode)
  96. INFO("Development mode");
  97. INFO("System directory: %s", asset::systemDir.c_str());
  98. INFO("User directory: %s", asset::userDir.c_str());
  99. // Load settings
  100. try {
  101. settings::load(asset::settingsPath);
  102. }
  103. catch (UserException &e) {
  104. std::string msg = e.what();
  105. msg += "\n\nReset settings to default?";
  106. if (!osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK_CANCEL, msg.c_str())) {
  107. exit(1);
  108. }
  109. }
  110. // Check existence of the system res/ directory
  111. std::string resDir = asset::system("res");
  112. if (!system::isDirectory(resDir)) {
  113. std::string message = string::f("Rack's resource directory \"%s\" does not exist. Make sure Rack is correctly installed and launched.", resDir.c_str());
  114. osdialog_message(OSDIALOG_ERROR, OSDIALOG_OK, message.c_str());
  115. exit(1);
  116. }
  117. INFO("Initializing environment");
  118. random::init();
  119. midi::init();
  120. rtmidiInit();
  121. bridgeInit();
  122. keyboard::init();
  123. gamepad::init();
  124. plugin::init();
  125. app::init();
  126. if (!settings::headless) {
  127. ui::init();
  128. windowInit();
  129. }
  130. // Initialize app
  131. INFO("Initializing app");
  132. appInit();
  133. const char *openedFilename = glfwGetOpenedFilename();
  134. if (openedFilename) {
  135. patchPath = openedFilename;
  136. }
  137. if (!settings::headless) {
  138. APP->patch->init(patchPath);
  139. }
  140. INFO("Starting engine");
  141. APP->engine->start();
  142. if (settings::headless) {
  143. // TEMP Prove that the app doesn't crash
  144. std::this_thread::sleep_for(std::chrono::seconds(2));
  145. }
  146. else if (screenshot) {
  147. INFO("Taking screenshots of all modules at %gx zoom", screenshotZoom);
  148. APP->window->screenshot(screenshotZoom);
  149. }
  150. else {
  151. INFO("Running window");
  152. APP->window->run();
  153. INFO("Stopped window");
  154. }
  155. INFO("Stopping engine");
  156. APP->engine->stop();
  157. // Destroy app
  158. if (!settings::headless) {
  159. APP->patch->save(asset::autosavePath);
  160. }
  161. INFO("Destroying app");
  162. appDestroy();
  163. settings::save(asset::settingsPath);
  164. // Destroy environment
  165. INFO("Destroying environment");
  166. if (!settings::headless) {
  167. windowDestroy();
  168. ui::destroy();
  169. }
  170. plugin::destroy();
  171. bridgeDestroy();
  172. midi::destroy();
  173. INFO("Destroying logger");
  174. logger::destroy();
  175. return 0;
  176. }