diff --git a/include/app/Scene.hpp b/include/app/Scene.hpp index 2a04e480..091d8a17 100644 --- a/include/app/Scene.hpp +++ b/include/app/Scene.hpp @@ -25,6 +25,8 @@ struct Scene : widget::OpaqueWidget { bool checkedVersion = false; std::string latestVersion; + double lastAutoSaveTime = 0.0; + Scene(); ~Scene(); void step() override; diff --git a/include/plugin.hpp b/include/plugin.hpp index f0cca6e4..1c6b19ed 100644 --- a/include/plugin.hpp +++ b/include/plugin.hpp @@ -25,12 +25,12 @@ std::string getAllowedTag(std::string tag); bool isSlugValid(std::string slug); +extern const std::vector allowedTags; extern std::list plugins; extern bool isDownloading; extern float downloadProgress; extern std::string downloadName; extern std::string loginStatus; -extern const std::vector allowedTags; } // namespace plugin diff --git a/src/app/Scene.cpp b/src/app/Scene.cpp index 0e94517c..22eed9cf 100644 --- a/src/app/Scene.cpp +++ b/src/app/Scene.cpp @@ -56,13 +56,15 @@ void Scene::step() { zoomWidget->box.size = rackWidget->box.size.mult(zoomWidget->zoom); // Autosave every 15 seconds - int frame = APP->window->frame; - if (frame > 0 && frame % (60 * 15) == 0) { + double time = glfwGetTime(); + if (time - lastAutoSaveTime >= 15.0) { + lastAutoSaveTime = time; APP->patch->save(asset::user("autosave.vcv")); settings.save(asset::user("settings.json")); } // Set zoom every few frames + int frame = APP->window->frame; if (frame % 10 == 0) zoomWidget->setZoom(std::round(settings.zoom * 100) / 100); diff --git a/src/plugin.cpp b/src/plugin.cpp index 52fc7b7c..597b4990 100644 --- a/src/plugin.cpp +++ b/src/plugin.cpp @@ -14,6 +14,7 @@ #include // for MAXPATHLEN #include #include +#include #include #define ZIP_STATIC @@ -516,41 +517,20 @@ Model *getModel(std::string pluginSlug, std::string modelSlug) { return model; } -std::string getAllowedTag(std::string tag) { - tag = string::lowercase(tag); - for (std::string allowedTag : allowedTags) { - if (tag == string::lowercase(allowedTag)) - return allowedTag; - } - return ""; -} - -bool isSlugValid(std::string slug) { - for (char c : slug) { - if (!(std::isalnum(c) || c == '-' || c == '_')) - return false; - } - return true; -} - - -std::list plugins; -bool isDownloading = false; -float downloadProgress = 0.f; -std::string downloadName; -std::string loginStatus; - +/** List of allowed tags in human display form. +All tags here should be in sentence caps for display consistency. +However, tags are case-insensitive in plugin metadata. +*/ const std::vector allowedTags = { - "VCA", "Arpeggiator", - "Attenuator", - "Blank", + "Attenuator", // With a level knob and not much else. + "Blank", // No parameters or ports. Serves no purpose except visual. "Chorus", - "Clock Modulator", // Clock dividers, multipliers, etc. - "Clock", - "Compressor", - "Controller", // Use only if the artist "performs" with this module. Knobs are not sufficient. Examples: on-screen keyboard, XY pad. + "Clock generator", + "Clock modulator", // Clock dividers, multipliers, etc. + "Compressor", // With threshold, ratio, knee, etc parameters. + "Controller", // Use only if the artist "performs" with this module. Simply having knobs is not enough. Examples: on-screen keyboard, XY pad. "Delay", "Digital", "Distortion", @@ -558,46 +538,98 @@ const std::vector allowedTags = { "Dual", // The core functionality times two. If multiple channels are a requirement for the module to exist (ring modulator, mixer, etc), it is not a Dual module. "Dynamics", "Effect", - "Envelope Follower", - "Envelope Generator", + "Envelope follower", + "Envelope generator", "Equalizer", "External", - "Filter", "Flanger", - "Function Generator", + "Function generator", "Granular", "LFO", "Limiter", "Logic", - "Low Pass Gate", + "Low pass gate", "MIDI", "Mixer", "Multiple", "Noise", - "VCO", "Panning", "Phaser", - "Poly", - "Physical Modeling", + "Physical modeling", + "Polyphonic", "Quad", // The core functionality times four. If multiple channels are a requirement for the module to exist (ring modulator, mixer, etc), it is not a Quad module. "Quantizer", "Random", "Recording", "Reverb", - "Ring Modulator", - "Sample and Hold", + "Ring modulator", + "Sample and hold", "Sampler", "Sequencer", - "Slew Limiter", + "Slew limiter", "Switch", - "Synth Voice", // A synth voice must have an envelope built-in. + "Synth voice", // A synth voice must have, at the minimum, a built-in oscillator and envelope. "Tuner", "Utility", // Serves only extremely basic functions, like inverting, max, min, multiplying by 2, etc. + "VCA", + "VCF", + "VCO", "Visual", "Vocoder", "Waveshaper", }; +/** List of common synonyms for allowed tags. +Aliases and tags must be lowercase. +*/ +const std::map tagAliases = { + {"amplifier", "vca"}, + {"clock", "clock generator"}, + {"drums", "drum"}, + {"eq", "equalizer"}, + {"filter", "vcf"}, + {"low frequency oscillator", "lfo"}, + {"lowpass gate", "low pass gate"}, + {"oscillator", "vco"}, + {"percussion", "drum"}, + {"poly", "polyphonic"}, + {"s&h", "sample and hold"}, + {"voltage controlled amplifier", "vca"}, + {"voltage controlled filter", "vcf"}, + {"voltage controlled oscillator", "vco"}, +}; + + +std::string getAllowedTag(std::string tag) { + tag = string::lowercase(tag); + // Transform aliases + auto it = tagAliases.find(tag); + if (it != tagAliases.end()) + tag = it->second; + // Find allowed tag + for (std::string allowedTag : allowedTags) { + if (tag == string::lowercase(allowedTag)) + return allowedTag; + } + return ""; +} + +bool isSlugValid(std::string slug) { + for (char c : slug) { + if (!(std::isalnum(c) || c == '-' || c == '_')) + return false; + } + return true; +} + + +std::list plugins; +bool isDownloading = false; +float downloadProgress = 0.f; +std::string downloadName; +std::string loginStatus; + + } // namespace plugin } // namespace rack diff --git a/src/string.cpp b/src/string.cpp index 54ea6c08..a9e63227 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -25,12 +25,12 @@ std::string f(const char *format, ...) { } std::string lowercase(std::string s) { - std::transform(s.begin(), s.end(), s.begin(), ::tolower); + std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c){ return std::tolower(c); }); return s; } std::string uppercase(std::string s) { - std::transform(s.begin(), s.end(), s.begin(), ::toupper); + std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c){ return std::toupper(c); }); return s; }