|
- #include <common.hpp>
- #include <random.hpp>
- #include <asset.hpp>
- #include <midi.hpp>
- #include <rtmidi.hpp>
- #include <keyboard.hpp>
- #include <gamepad.hpp>
- #include <bridge.hpp>
- #include <settings.hpp>
- #include <engine/Engine.hpp>
- #include <app/common.hpp>
- #include <app/Scene.hpp>
- #include <plugin.hpp>
- #include <app.hpp>
- #include <patch.hpp>
- #include <ui.hpp>
- #include <system.hpp>
- #include <string.hpp>
-
- #include <osdialog.h>
- #include <thread>
- #include <unistd.h> // for getopt
- #include <signal.h> // for signal
-
- #if defined ARCH_WIN
- #include <windows.h> // for CreateMutex
- #endif
-
- using namespace rack;
-
-
- static void fatalSignalHandler(int sig) {
- // Only catch one signal
- static bool caught = false;
- bool localCaught = caught;
- caught = true;
- if (localCaught)
- exit(1);
-
- FATAL("Fatal signal %d. Stack trace:\n%s", sig, system::getStackTrace().c_str());
-
- // osdialog_message(OSDIALOG_ERROR, OSDIALOG_OK, "Rack has crashed. See log.txt for details.");
-
- exit(1);
- }
-
-
- int main(int argc, char *argv[]) {
- #if defined ARCH_WIN
- // Windows global mutex to prevent multiple instances
- // Handle will be closed by Windows when the process ends
- HANDLE instanceMutex = CreateMutexA(NULL, true, app::APP_NAME.c_str());
- if (GetLastError() == ERROR_ALREADY_EXISTS) {
- osdialog_message(OSDIALOG_ERROR, OSDIALOG_OK, "Rack is already running. Multiple Rack instances are not supported.");
- exit(1);
- }
- (void) instanceMutex;
- #endif
-
- std::string patchPath;
- bool screenshot = false;
- float screenshotZoom = 1.f;
-
- // Parse command line arguments
- int c;
- opterr = 0;
- while ((c = getopt(argc, argv, "dhp:s:u:")) != -1) {
- switch (c) {
- case 'd': {
- settings::devMode = true;
- } break;
- case 'h': {
- settings::headless = true;
- } break;
- case 'p': {
- screenshot = true;
- sscanf(optarg, "%f", &screenshotZoom);
- } break;
- case 's': {
- asset::systemDir = optarg;
- } break;
- case 'u': {
- asset::userDir = optarg;
- } break;
- default: break;
- }
- }
- if (optind < argc) {
- patchPath = argv[optind];
- }
-
- asset::init();
- logger::init();
-
- // We can now install a signal handler and log the output
- // Mac has its own decent crash handler
- #if 0
- if (!settings::devMode) {
- signal(SIGABRT, fatalSignalHandler);
- signal(SIGFPE, fatalSignalHandler);
- signal(SIGILL, fatalSignalHandler);
- signal(SIGSEGV, fatalSignalHandler);
- signal(SIGTERM, fatalSignalHandler);
- }
- #endif
-
- // Log environment
- INFO("%s v%s", app::APP_NAME.c_str(), app::APP_VERSION.c_str());
- INFO("%s", system::getOperatingSystemInfo().c_str());
- if (settings::devMode)
- INFO("Development mode");
- INFO("System directory: %s", asset::systemDir.c_str());
- INFO("User directory: %s", asset::userDir.c_str());
-
- // Load settings
- try {
- settings::load(asset::settingsPath);
- }
- catch (UserException &e) {
- std::string msg = e.what();
- msg += "\n\nReset settings to default?";
- if (!osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK_CANCEL, msg.c_str())) {
- exit(1);
- }
- }
-
- // Check existence of the system res/ directory
- std::string resDir = asset::system("res");
- if (!system::isDirectory(resDir)) {
- std::string message = string::f("Rack's resource directory \"%s\" does not exist. Make sure Rack is correctly installed and launched.", resDir.c_str());
- osdialog_message(OSDIALOG_ERROR, OSDIALOG_OK, message.c_str());
- exit(1);
- }
-
- INFO("Initializing environment");
- random::init();
- midi::init();
- rtmidiInit();
- bridgeInit();
- keyboard::init();
- gamepad::init();
- plugin::init();
- app::init();
- if (!settings::headless) {
- ui::init();
- windowInit();
- }
-
- // Initialize app
- INFO("Initializing app");
- appInit();
-
- const char *openedFilename = glfwGetOpenedFilename();
- if (openedFilename) {
- patchPath = openedFilename;
- }
-
- if (!settings::headless) {
- APP->patch->init(patchPath);
- }
-
- INFO("Starting engine");
- APP->engine->start();
-
- if (settings::headless) {
- // TEMP Prove that the app doesn't crash
- std::this_thread::sleep_for(std::chrono::seconds(2));
- }
- else if (screenshot) {
- INFO("Taking screenshots of all modules at %gx zoom", screenshotZoom);
- APP->window->screenshot(screenshotZoom);
- }
- else {
- INFO("Running window");
- APP->window->run();
- INFO("Stopped window");
- }
- INFO("Stopping engine");
- APP->engine->stop();
-
- // Destroy app
- if (!settings::headless) {
- APP->patch->save(asset::autosavePath);
- }
- INFO("Destroying app");
- appDestroy();
- settings::save(asset::settingsPath);
-
- // Destroy environment
- INFO("Destroying environment");
- if (!settings::headless) {
- windowDestroy();
- ui::destroy();
- }
- plugin::destroy();
- bridgeDestroy();
- midi::destroy();
- INFO("Destroying logger");
- logger::destroy();
-
- return 0;
- }
|