@@ -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 |