| @@ -16,7 +16,7 @@ | |||||
| namespace rack { | namespace rack { | ||||
| template <class TModule, class TModuleWidget, typename... Tags> | |||||
| template <class TModule, class TModuleWidget> | |||||
| plugin::Model* createModel(const std::string& slug) { | plugin::Model* createModel(const std::string& slug) { | ||||
| struct TModel : plugin::Model { | struct TModel : plugin::Model { | ||||
| engine::Module* createModule() override { | engine::Module* createModule() override { | ||||
| @@ -3,7 +3,6 @@ | |||||
| #include <plugin/Plugin.hpp> | #include <plugin/Plugin.hpp> | ||||
| #include <plugin/Model.hpp> | #include <plugin/Model.hpp> | ||||
| #include <vector> | #include <vector> | ||||
| #include <set> | |||||
| namespace rack { | namespace rack { | ||||
| @@ -35,14 +34,12 @@ void syncUpdates(); | |||||
| bool isSyncing(); | bool isSyncing(); | ||||
| Plugin* getPlugin(const std::string& pluginSlug); | Plugin* getPlugin(const std::string& pluginSlug); | ||||
| Model* getModel(const std::string& pluginSlug, const std::string& modelSlug); | Model* getModel(const std::string& pluginSlug, const std::string& modelSlug); | ||||
| std::string normalizeTag(const std::string& tag); | |||||
| /** Checks that the slug contains only alphanumeric characters, "-", and "_" */ | /** Checks that the slug contains only alphanumeric characters, "-", and "_" */ | ||||
| bool isSlugValid(const std::string& slug); | bool isSlugValid(const std::string& slug); | ||||
| /** Returns a string containing only the valid slug characters. */ | /** Returns a string containing only the valid slug characters. */ | ||||
| std::string normalizeSlug(const std::string& slug); | std::string normalizeSlug(const std::string& slug); | ||||
| extern const std::set<std::string> allowedTags; | |||||
| extern std::vector<Plugin*> plugins; | extern std::vector<Plugin*> plugins; | ||||
| extern std::string loginStatus; | extern std::string loginStatus; | ||||
| @@ -0,0 +1,16 @@ | |||||
| #pragma once | |||||
| #include <common.hpp> | |||||
| #include <set> | |||||
| namespace rack { | |||||
| namespace tag { | |||||
| extern const std::set<std::string> allowedTags; | |||||
| std::string normalize(const std::string& tag); | |||||
| } // namespace tag | |||||
| } // namespace rack | |||||
| @@ -22,6 +22,7 @@ | |||||
| #include <string.hpp> | #include <string.hpp> | ||||
| #include <history.hpp> | #include <history.hpp> | ||||
| #include <settings.hpp> | #include <settings.hpp> | ||||
| #include <tag.hpp> | |||||
| #include <set> | #include <set> | ||||
| #include <algorithm> | #include <algorithm> | ||||
| @@ -377,7 +378,7 @@ struct BrowserSidebar : widget::Widget { | |||||
| tagList = new ui::List; | tagList = new ui::List; | ||||
| tagScroll->container->addChild(tagList); | tagScroll->container->addChild(tagList); | ||||
| for (const std::string& tag : plugin::allowedTags) { | |||||
| for (const std::string& tag : tag::allowedTags) { | |||||
| TagItem* item = new TagItem; | TagItem* item = new TagItem; | ||||
| item->text = tag; | item->text = tag; | ||||
| tagList->addChild(item); | tagList->addChild(item); | ||||
| @@ -536,105 +536,6 @@ Model* getModel(const std::string& pluginSlug, const std::string& modelSlug) { | |||||
| return model; | return model; | ||||
| } | } | ||||
| /** List of allowed tags in human display form, alphabetized. | |||||
| All tags here should be in sentence caps for display consistency. | |||||
| However, tags are case-insensitive in plugin metadata. | |||||
| */ | |||||
| const std::set<std::string> allowedTags = { | |||||
| "Arpeggiator", | |||||
| "Attenuator", // With a level knob and not much else. | |||||
| "Blank", // No parameters or ports. Serves no purpose except visual. | |||||
| "Chorus", | |||||
| "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", | |||||
| "Drum", | |||||
| "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", | |||||
| "Equalizer", | |||||
| "Expander", // Expands the functionality of a "mother" module when placed next to it. Expanders should inherit the tags of its mother module. | |||||
| "External", | |||||
| "Flanger", | |||||
| "Function generator", | |||||
| "Granular", | |||||
| "LFO", | |||||
| "Limiter", | |||||
| "Logic", | |||||
| "Low pass gate", | |||||
| "MIDI", | |||||
| "Mixer", | |||||
| "Multiple", | |||||
| "Noise", | |||||
| "Panning", | |||||
| "Phaser", | |||||
| "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", | |||||
| "Sampler", | |||||
| "Sequencer", | |||||
| "Slew limiter", | |||||
| "Switch", | |||||
| "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<std::string, std::string> 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 normalizeTag(const std::string& tag) { | |||||
| std::string lowercaseTag = string::lowercase(tag); | |||||
| // Transform aliases | |||||
| auto it = tagAliases.find(lowercaseTag); | |||||
| if (it != tagAliases.end()) | |||||
| lowercaseTag = it->second; | |||||
| // Find allowed tag | |||||
| for (const std::string& allowedTag : allowedTags) { | |||||
| if (lowercaseTag == string::lowercase(allowedTag)) | |||||
| return allowedTag; | |||||
| } | |||||
| return ""; | |||||
| } | |||||
| bool isSlugValid(const std::string& slug) { | bool isSlugValid(const std::string& slug) { | ||||
| for (char c : slug) { | for (char c : slug) { | ||||
| if (!(std::isalnum(c) || c == '-' || c == '_')) | if (!(std::isalnum(c) || c == '-' || c == '_')) | ||||
| @@ -3,6 +3,7 @@ | |||||
| #include <asset.hpp> | #include <asset.hpp> | ||||
| #include <system.hpp> | #include <system.hpp> | ||||
| #include <string.hpp> | #include <string.hpp> | ||||
| #include <tag.hpp> | |||||
| namespace rack { | namespace rack { | ||||
| @@ -31,7 +32,7 @@ void Model::fromJson(json_t* rootJ) { | |||||
| json_array_foreach(tagsJ, i, tagJ) { | json_array_foreach(tagsJ, i, tagJ) { | ||||
| std::string tag = json_string_value(tagJ); | std::string tag = json_string_value(tagJ); | ||||
| // Normalize tag | // Normalize tag | ||||
| tag = normalizeTag(tag); | |||||
| tag = tag::normalize(tag); | |||||
| if (tag != "") | if (tag != "") | ||||
| tags.push_back(tag); | tags.push_back(tag); | ||||
| } | } | ||||
| @@ -0,0 +1,115 @@ | |||||
| #include <tag.hpp> | |||||
| #include <string.hpp> | |||||
| #include <map> | |||||
| namespace rack { | |||||
| namespace tag { | |||||
| /** List of allowed tags in human display form, alphabetized. | |||||
| All tags here should be in sentence caps for display consistency. | |||||
| However, tags are case-insensitive in plugin metadata. | |||||
| */ | |||||
| const std::set<std::string> allowedTags = { | |||||
| "Arpeggiator", | |||||
| "Attenuator", // With a level knob and not much else. | |||||
| "Blank", // No parameters or ports. Serves no purpose except visual. | |||||
| "Chorus", | |||||
| "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", | |||||
| "Drum", | |||||
| "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", | |||||
| "Equalizer", | |||||
| "Expander", // Expands the functionality of a "mother" module when placed next to it. Expanders should inherit the tags of its mother module. | |||||
| "External", | |||||
| "Filter", | |||||
| "Flanger", | |||||
| "Function generator", | |||||
| "Granular", | |||||
| "Limiter", | |||||
| "Logic", | |||||
| "Low-frequency oscillator", | |||||
| "Low-pass gate", | |||||
| "MIDI", | |||||
| "Mixer", | |||||
| "Multiple", | |||||
| "Noise", | |||||
| "Oscillator", | |||||
| "Panning", | |||||
| "Phaser", | |||||
| "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", | |||||
| "Sampler", | |||||
| "Sequencer", | |||||
| "Slew limiter", | |||||
| "Switch", | |||||
| "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. | |||||
| "Visual", | |||||
| "Vocoder", | |||||
| "Voltage-controlled amplifier", | |||||
| "Waveshaper", | |||||
| }; | |||||
| /** List of common synonyms for allowed tags. | |||||
| Aliases and tags must be lowercase. | |||||
| */ | |||||
| const std::map<std::string, std::string> tagAliases = { | |||||
| {"amplifier", "voltage-controlled amplifier"}, | |||||
| {"clock", "clock generator"}, | |||||
| {"drums", "drum"}, | |||||
| {"eq", "equalizer"}, | |||||
| {"lfo", "low-frequency oscillator"}, | |||||
| {"low frequency oscillator", "low-frequency oscillator"}, | |||||
| {"low pass gate", "low-pass gate"}, | |||||
| {"lowpass gate", "low-pass gate"}, | |||||
| {"percussion", "drum"}, | |||||
| {"poly", "polyphonic"}, | |||||
| {"s&h", "sample and hold"}, | |||||
| {"sample & hold", "sample and hold"}, | |||||
| {"vca", "voltage-controlled amplifier"}, | |||||
| {"vcf", "filter"}, | |||||
| {"vco", "oscillator"}, | |||||
| {"voltage controlled amplifier", "voltage-controlled amplifier"}, | |||||
| {"voltage controlled filter", "filter"}, | |||||
| {"voltage controlled oscillator", "oscillator"}, | |||||
| }; | |||||
| std::string normalize(const std::string& tag) { | |||||
| std::string lowercaseTag = string::lowercase(tag); | |||||
| // Transform aliases | |||||
| auto it = tagAliases.find(lowercaseTag); | |||||
| if (it != tagAliases.end()) | |||||
| lowercaseTag = it->second; | |||||
| // Find allowed tag | |||||
| for (const std::string& allowedTag : allowedTags) { | |||||
| if (lowercaseTag == string::lowercase(allowedTag)) | |||||
| return allowedTag; | |||||
| } | |||||
| return ""; | |||||
| } | |||||
| } // namespace tag | |||||
| } // namespace rack | |||||