diff --git a/.gitignore b/.gitignore index d1c2e310..887392fb 100644 --- a/.gitignore +++ b/.gitignore @@ -2,13 +2,11 @@ /Rack.exe /Rack.res /libRack.a -/autosave.json -/settings.json +/dep /plugins /build -/dep -*.vcv +/dist /patches -/design .DS_Store -/dist +/autosave.vcv +/settings.json diff --git a/include/patch.hpp b/include/patch.hpp index 71c10110..bfa1c93d 100644 --- a/include/patch.hpp +++ b/include/patch.hpp @@ -13,13 +13,14 @@ struct PatchManager { int legacy; std::string warningLog; + void init(std::string path); void reset(); void resetDialog(); void save(std::string path); void saveDialog(); void saveAsDialog(); void saveTemplateDialog(); - void load(std::string path); + bool load(std::string path); void loadDialog(); /** If `lastPath` is defined, ask the user to reload it */ void revertDialog(); diff --git a/src/main.cpp b/src/main.cpp index 1251171a..59dc6ea9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -37,7 +37,7 @@ int main(int argc, char *argv[]) { #endif bool devMode = false; - std::string patchFile; + std::string patchPath; // Parse command line arguments int c; @@ -57,7 +57,7 @@ int main(int argc, char *argv[]) { } } if (optind < argc) { - patchFile = argv[optind]; + patchPath = argv[optind]; } // Initialize environment @@ -86,28 +86,8 @@ int main(int argc, char *argv[]) { appInit(); app()->scene->devMode = devMode; settings::load(asset::user("settings.json")); + app()->patch->init(patchPath); - if (patchFile.empty()) { - // To prevent launch crashes, if Rack crashes between now and 15 seconds from now, the "skipAutosaveOnLaunch" property will remain in settings.json, so that in the next launch, the broken autosave will not be loaded. - bool oldSkipLoadOnLaunch = settings::skipLoadOnLaunch; - settings::skipLoadOnLaunch = true; - settings::save(asset::user("settings.json")); - settings::skipLoadOnLaunch = false; - if (oldSkipLoadOnLaunch && osdialog_message(OSDIALOG_INFO, OSDIALOG_YES_NO, "Rack has recovered from a crash, possibly caused by a faulty module in your patch. Clear your patch and start over?")) { - app()->patch->path = ""; - } - else { - // Load autosave - std::string oldLastPath = app()->patch->path; - app()->patch->load(asset::user("autosave.vcv")); - app()->patch->path = oldLastPath; - } - } - else { - // Load patch - app()->patch->load(patchFile); - app()->patch->path = patchFile; - } INFO("Initialized app"); app()->engine->start(); diff --git a/src/patch.cpp b/src/patch.cpp index 9d813940..8969f05d 100644 --- a/src/patch.cpp +++ b/src/patch.cpp @@ -5,6 +5,8 @@ #include "app/Scene.hpp" #include "app/RackWidget.hpp" #include "history.hpp" +#include "settings.hpp" + #include "osdialog.h" @@ -14,6 +16,39 @@ namespace rack { static const char PATCH_FILTERS[] = "VCV Rack patch (.vcv):vcv"; +void PatchManager::init(std::string path) { + if (!path.empty()) { + // Load patch + load(path); + this->path = path; + return; + } + + // To prevent launch crashes, if Rack crashes between now and 15 seconds from now, the "skipAutosaveOnLaunch" property will remain in settings.json, so that in the next launch, the broken autosave will not be loaded. + bool oldSkipLoadOnLaunch = settings::skipLoadOnLaunch; + settings::skipLoadOnLaunch = true; + settings::save(asset::user("settings.json")); + settings::skipLoadOnLaunch = false; + if (oldSkipLoadOnLaunch && osdialog_message(OSDIALOG_INFO, OSDIALOG_YES_NO, "Rack has recovered from a crash, possibly caused by a faulty module in your patch. Clear your patch and start over?")) { + this->path = ""; + return; + } + + // Load autosave + if (load(asset::user("autosave.vcv"))) { + return; + } + + this->path = ""; + if (load(asset::user("template.vcv"))) { + return; + } + + if (load(asset::system("template.vcv"))) { + return; + } +} + void PatchManager::reset() { app()->history->clear(); app()->scene->rackWidget->clear(); @@ -102,12 +137,12 @@ void PatchManager::saveTemplateDialog() { } } -void PatchManager::load(std::string path) { +bool PatchManager::load(std::string path) { INFO("Loading patch %s", path.c_str()); FILE *file = std::fopen(path.c_str(), "r"); if (!file) { // Exit silently - return; + return false; } DEFER({ std::fclose(file); @@ -118,7 +153,7 @@ void PatchManager::load(std::string path) { if (!rootJ) { std::string message = string::f("JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text); osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, message.c_str()); - return; + return false; } DEFER({ json_decref(rootJ); @@ -128,6 +163,7 @@ void PatchManager::load(std::string path) { app()->scene->rackWidget->clear(); app()->scene->scrollWidget->offset = math::Vec(0, 0); fromJson(rootJ); + return true; } void PatchManager::loadDialog() { diff --git a/template.vcv b/template.vcv new file mode 100644 index 00000000..a980157a --- /dev/null +++ b/template.vcv @@ -0,0 +1,238 @@ +{ + "version": "1.dev", + "modules": [ + { + "plugin": "Core", + "version": "1.dev", + "model": "AudioInterface", + "params": [], + "data": { + }, + "id": 1, + "pos": [ + 47, + 0 + ] + }, + { + "plugin": "Fundamental", + "version": "1.0.0", + "model": "VCMixer", + "params": [ + { + "value": 1.0 + }, + { + "value": 1.0 + }, + { + "value": 1.0 + }, + { + "value": 1.0 + }, + { + "value": 1.0 + } + ], + "id": 2, + "pos": [ + 37, + 0 + ] + }, + { + "plugin": "Fundamental", + "version": "1.0.0", + "model": "VCO", + "params": [ + { + "value": 1.0 + }, + { + "value": 1.0 + }, + { + "value": 0.0 + }, + { + "value": 0.0 + }, + { + "value": 0.0 + }, + { + "value": 0.5 + }, + { + "value": 0.0 + } + ], + "id": 3, + "pos": [ + 8, + 0 + ] + }, + { + "plugin": "Fundamental", + "version": "1.0.0", + "model": "VCF", + "params": [ + { + "value": 0.262999862 + }, + { + "value": 0.5 + }, + { + "value": 0.236999944 + }, + { + "value": 0.869999945 + }, + { + "value": 0.0 + } + ], + "id": 4, + "pos": [ + 18, + 0 + ] + }, + { + "plugin": "Core", + "version": "1.dev", + "model": "MIDIToCVInterface", + "params": [], + "data": { + "divisions": [ + 24, + 6 + ] + }, + "id": 5, + "pos": [ + 0, + 0 + ] + }, + { + "plugin": "Fundamental", + "version": "1.0.0", + "model": "VCA-1", + "params": [ + { + "value": 1.0 + }, + { + "value": 1.0 + } + ], + "id": 6, + "pos": [ + 26, + 0 + ] + }, + { + "plugin": "Fundamental", + "version": "1.0.0", + "model": "ADSR", + "params": [ + { + "value": 0.356000006 + }, + { + "value": 0.671000004 + }, + { + "value": 0.358999938 + }, + { + "value": 0.5 + } + ], + "id": 7, + "pos": [ + 29, + 0 + ] + } + ], + "cables": [ + { + "id": 1, + "outputModuleId": 5, + "outputId": 0, + "inputModuleId": 3, + "inputId": 0, + "color": "#c91847" + }, + { + "id": 2, + "outputModuleId": 3, + "outputId": 2, + "inputModuleId": 4, + "inputId": 3, + "color": "#0c8e15" + }, + { + "id": 3, + "outputModuleId": 4, + "outputId": 0, + "inputModuleId": 6, + "inputId": 1, + "color": "#0986ad" + }, + { + "id": 4, + "outputModuleId": 6, + "outputId": 0, + "inputModuleId": 2, + "inputId": 1, + "color": "#c9b70e" + }, + { + "id": 5, + "outputModuleId": 2, + "outputId": 0, + "inputModuleId": 1, + "inputId": 0, + "color": "#0986ad" + }, + { + "id": 6, + "outputModuleId": 2, + "outputId": 0, + "inputModuleId": 1, + "inputId": 1, + "color": "#c9b70e" + }, + { + "id": 7, + "outputModuleId": 7, + "outputId": 0, + "inputModuleId": 4, + "inputId": 0, + "color": "#c91847" + }, + { + "id": 8, + "outputModuleId": 7, + "outputId": 0, + "inputModuleId": 6, + "inputId": 0, + "color": "#0c8e15" + }, + { + "id": 9, + "outputModuleId": 5, + "outputId": 1, + "inputModuleId": 7, + "inputId": 4, + "color": "#c9b70e" + } + ] +} \ No newline at end of file