commit ffa7efb89b8cc8315fac8c54e1b699cc2f2fcb50
parent 172d2f157e1138ea00107d6bfc38d14ea32b7c2e
Author: dsp56300 <dsp56300@users.noreply.github.com>
Date: Thu, 9 May 2024 16:35:22 +0200
support value list definition by value/string pairs
Diffstat:
5 files changed, 132 insertions(+), 60 deletions(-)
diff --git a/source/jucePluginLib/parameterbinding.cpp b/source/jucePluginLib/parameterbinding.cpp
@@ -103,48 +103,34 @@ namespace pluginLib
std::vector<Entry> sortedValues;
- const auto& allValues = v->getAllValueStrings();
- uint8_t i = 0;
- for (const auto& vs : allValues)
+ const auto& desc = v->getDescription();
+ const auto& valueList = desc.valueList;
+
+ if(valueList.order.empty())
{
- if(vs.isNotEmpty())
- sortedValues.emplace_back(i, vs.toStdString());
- ++i;
+ uint8_t i = 0;
+ const auto& allValues = v->getAllValueStrings();
+ for (const auto& vs : allValues)
+ {
+ if(vs.isNotEmpty())
+ sortedValues.emplace_back(i, vs.toStdString());
+ ++i;
+ }
}
- /*
- std::sort(sortedValues.begin(), sortedValues.end(), [](const Entry& _a, const Entry& _b)
+ else
{
- const auto aOff =_a.second == "Off" || _a.second == "-";
- const auto bOff =_b.second == "Off" || _b.second == "-";
-
- if(aOff && !bOff)
- return true;
-
- if(!aOff && bOff)
- return false;
-
- auto noDigitsString = [](const std::string& _s)
+ for(uint32_t i=0; i<valueList.order.size(); ++i)
{
- std::string s;
- s.reserve(_s.size());
- for (const char c : _s)
- {
- if(isdigit(c))
- break;
- s += c;
- }
- return s;
- };
-
- const auto a = noDigitsString(_a.second);
- const auto b = noDigitsString(_b.second);
-
- if(a == b)
- return _a.first < _b.first;
-
- return a < b;
- });
- */
+ const auto value = valueList.orderToValue(i);
+ if(value == ValueList::InvalidIndex)
+ continue;
+ const auto text = valueList.valueToText(value);
+ if(text.empty())
+ continue;
+ sortedValues.emplace_back(value, text);
+ }
+ }
+
uint32_t count = 0;
for (const auto& vs : sortedValues)
diff --git a/source/jucePluginLib/parameterdescriptions.cpp b/source/jucePluginLib/parameterdescriptions.cpp
@@ -100,6 +100,8 @@ namespace pluginLib
if (descsArray == nullptr)
return "Parameter descriptions are empty";
+ std::stringstream errors;
+
{
const auto& valueLists = json["valuelists"];
@@ -113,33 +115,15 @@ namespace pluginLib
for(int i=0; i<entryProps.size(); ++i)
{
const auto key = std::string(entryProps.getName(i).toString().toUTF8());
- const auto values = entryProps.getValueAt(i).getArray();
-
- if(m_valueLists.find(key) != m_valueLists.end())
- return "value list " + key + " is defined twice";
-
- if(!values || values->isEmpty())
- return std::string("value list ") + key + " is not a valid array of strings";
-
- ValueList vl;
- vl.texts.reserve(values->size());
-
- for (auto&& value : *values)
- {
- const auto text = static_cast<std::string>(value.toString().toUTF8());
-
- if (vl.textToValueMap.find(text) == vl.textToValueMap.end())
- vl.textToValueMap.insert(std::make_pair(text, static_cast<uint32_t>(vl.texts.size())));
+ const auto& values = entryProps.getValueAt(i);
- vl.texts.push_back(text);
- }
+ const auto result = parseValueList(key, values);
- m_valueLists.insert(std::make_pair(key, vl));
+ if(!result.empty())
+ errors << "Failed to parse value list " << key << ": " << result << '\n';
}
}
- std::stringstream errors;
-
const auto& descs = *descsArray;
for (int i = 0; i < descs.size(); ++i)
@@ -426,6 +410,80 @@ namespace pluginLib
return res;
}
+
+ std::string ParameterDescriptions::parseValueList(const std::string& _key, const juce::var& _values)
+ {
+ auto valuesArray = _values.getArray();
+
+ if(m_valueLists.find(_key) != m_valueLists.end())
+ return "value list " + _key + " is defined twice";
+
+ ValueList vl;
+
+ if(valuesArray)
+ {
+ if(valuesArray->isEmpty())
+ return std::string("value list ") + _key + " is not a valid array of strings";
+
+ vl.texts.reserve(valuesArray->size());
+
+ for (auto&& value : *valuesArray)
+ {
+ const auto text = static_cast<std::string>(value.toString().toUTF8());
+ vl.texts.push_back(text);
+ }
+
+ for(uint32_t i=0; i<vl.texts.size(); ++i)
+ vl.order.push_back(i);
+ }
+ else
+ {
+ const auto valueMap = _values.getDynamicObject();
+ if(!valueMap)
+ {
+ return std::string("value list ") + _key + " neither contains an array of strings nor a map of values => strings";
+ }
+
+ std::set<uint32_t> knownValues;
+
+ for (const auto& it : valueMap->getProperties())
+ {
+ const auto keyName = it.name.toString().toStdString();
+ const auto& value = it.value;
+
+ const auto key = std::strtol(keyName.c_str(), nullptr, 10);
+
+ if(key < 0)
+ {
+ return std::string("Invalid parameter index '") + keyName + " in value list '" + _key + "', values must be >= 0";
+ }
+ if(knownValues.find(key) != knownValues.end())
+ {
+ return std::string("Parameter index '") + keyName + " in value list '" + _key + " has been specified twice";
+ }
+ knownValues.insert(key);
+
+ const auto requiredLength = key+1;
+
+ if(vl.texts.size() < requiredLength)
+ vl.texts.resize(requiredLength);
+
+ vl.texts[key] = value.toString().toStdString();
+ vl.order.push_back(key);
+ }
+ }
+
+ for (const auto& text : vl.texts)
+ {
+ if (vl.textToValueMap.find(text) == vl.textToValueMap.end())
+ vl.textToValueMap.insert(std::make_pair(text, static_cast<uint32_t>(vl.texts.size())));
+ }
+
+ m_valueLists.insert(std::make_pair(_key, vl));
+
+ return {};
+ }
+
void ParameterDescriptions::parseMidiPackets(std::stringstream& _errors, juce::DynamicObject* _packets)
{
if(!_packets)
diff --git a/source/jucePluginLib/parameterdescriptions.h b/source/jucePluginLib/parameterdescriptions.h
@@ -51,6 +51,9 @@ namespace pluginLib
private:
std::string loadJson(const std::string& _jsonString);
+
+ std::string parseValueList(const std::string& _key, const juce::var& _values);
+
void parseMidiPackets(std::stringstream& _errors, juce::DynamicObject* _packets);
void parseMidiPacket(std::stringstream& _errors, const std::string& _key, const juce::var& _value);
diff --git a/source/jucePluginLib/parametervaluelist.cpp b/source/jucePluginLib/parametervaluelist.cpp
@@ -2,6 +2,11 @@
namespace pluginLib
{
+ namespace
+ {
+ std::string g_empty;
+ }
+
uint32_t ValueList::textToValue(const std::string& _string) const
{
const auto it = textToValueMap.find(_string);
@@ -16,4 +21,19 @@ namespace pluginLib
return texts.back();
return texts[_value];
}
+
+ uint32_t ValueList::orderToValue(const uint32_t _orderIndex) const
+ {
+ if(_orderIndex >= order.size())
+ return InvalidIndex;
+ return order[_orderIndex];
+ }
+
+ const std::string& ValueList::orderToText(const uint32_t _orderIndex) const
+ {
+ const auto value = orderToValue(_orderIndex);
+ if(value == InvalidIndex)
+ return g_empty;
+ return valueToText(value);
+ }
}
diff --git a/source/jucePluginLib/parametervaluelist.h b/source/jucePluginLib/parametervaluelist.h
@@ -9,10 +9,15 @@ namespace pluginLib
{
struct ValueList
{
+ static constexpr uint32_t InvalidIndex = 0xffffffff;
+
uint32_t textToValue(const std::string& _string) const;
const std::string& valueToText(const uint32_t _value) const;
+ uint32_t orderToValue(uint32_t _orderIndex) const;
+ const std::string& orderToText(uint32_t _orderIndex) const;
std::vector<std::string> texts;
std::map<std::string, uint32_t> textToValueMap;
+ std::vector<uint32_t> order;
};
}