15Param::fetch (
const String &key)
const
17 return kvpairs_fetch (
metadata, key);
23 kvpairs_assign (
metadata, key +
'=' + v);
27ParamExtraVals::ParamExtraVals (
double vmin,
double vmax,
double step)
30 Base::operator= (
MinMaxStep { vmin, vmax, step });
33ParamExtraVals::ParamExtraVals (
const MinMaxStep &range)
36 Base::operator= (range);
40 *
this = ChoiceS (choices);
43ParamExtraVals::ParamExtraVals (
const ChoiceS &choices)
46 Base::operator= (choices);
49ParamExtraVals::ParamExtraVals (
const ChoicesFunc &choicesfunc)
52 Base::operator= (choicesfunc);
57Parameter::construct_hints (
const String &hints,
const String &more,
double pmin,
double pmax)
79Parameter::nick ()
const
81 String nick = fetch (
"nick");
88Parameter::has (
const String &key)
const
90 return key ==
"ident" || kvpairs_search (metadata_, key) >= 0;
94Parameter::fetch (
const String &key)
const
97 return kvpairs_fetch (metadata_, key);
101Parameter::store (
const String &key,
const String &value)
108 kvpairs_assign (metadata_, kv);
117 const ChoiceS cs = choices();
119 return { 0, cs.size() -1, 1 };
120 return { NAN, NAN, NAN };
124Parameter::choices ()
const
129 return (*cf) (cident);
134Parameter::is_numeric ()
const
138 auto [i, a, s] =
range();
143Parameter::initialsync (
const Value &v)
149Parameter::has_hint (
const String &hint)
const
151 const String hints_ = hints();
153 while ((pos = hints_.find (hint, pos)) != std::string::npos) {
154 if ((pos == 0 || hints_[pos-1] ==
':') && (pos + hint.size() == hints_.size() || hints_[pos + hint.size()] ==
':'))
162Parameter::normalize (
double val)
const
165 if (std::abs (fmax - fmin) < F32EPS)
167 const double normalized = (val -
fmin) / (fmax - fmin);
168 assert_return (normalized >= 0.0 && normalized <= 1.0, normalized);
173Parameter::rescale (
double t)
const
182Parameter::match_choice (
const ChoiceS &choices,
const String &text)
184 for (
size_t i = 0; i < choices.size(); i++)
185 if (text == choices[i].ident)
190 for (
size_t i = 0; i < choices.size(); i++) {
191 const size_t maxdist =
std::max (choices[i].ident.size(), ltext.size());
202Parameter::constrain (
const Value &value)
const
206 const ChoiceS choices = this->choices();
207 if (value.is_numeric()) {
209 if (i >= 0 && i < choices.size())
210 return choices[i].ident;
212 const size_t selected = value.is_string() ? match_choice (choices, value.as_string()) : 0;
213 return choices.size() ? choices[selected].ident : initial_;
219 return dconstrain (value);
223Parameter::dconstrain (
const Value &value)
const
227 const ChoiceS choices = this->choices();
228 if (value.is_numeric()) {
230 if (i >= 0 && i < choices.size())
233 const size_t selected = value.is_string() ? match_choice (choices, value.as_string()) : 0;
238 return value.as_double();
240 double val = value.as_double();
242 if (std::abs (fmax - fmin) < F32EPS)
246 if (step > F32EPS && has_hint (
"stepped")) {
251 const double t =
std::floor ((val - fmin) / step + nearintoffset);
252 val =
fmin + t * step;
259minmaxstep_from_initialval (
const Param::InitialVal &iv,
bool *isbool)
268 range = { -128, 127, 1 };
270 range = { 0, 255, 1 };
272 range = { -32768, 32767, 1 };
274 range = { 0, 65536, 1 };
276 range = { -2147483648, 2147483647, 1 };
278 range = { 0, 4294967295, 1 };
280 range = { -9223372036854775807-1, 9223372036854775807, 1 };
282 range = { 0, 18446744073709551615ull, 1 };
284 range = { -F32MAX, F32MAX, 0 };
286 range = { -D64MAX, D64MAX, 0 };
289 range = { 0, I31MAX, 1 };
291 static_assert (
sizeof (T) < 0,
"unimplemented InitialVal type");
299value_from_initialval (
const Param::InitialVal &iv)
312 value = int32_t (arg);
317 value = int64_t (arg);
326 static_assert (
sizeof (T) < 0,
"unimplemented InitialVal type");
331Parameter::Parameter (
const Param &initparam)
333 const Param &p = initparam;
334 cident = kvpairs_fetch (p.metadata,
"ident");
335 if (!p.ident.empty()) {
337 kvpairs_assign (metadata_,
"ident=" + cident);
338 }
else if (cident.empty()) {
340 kvpairs_assign (metadata_,
"ident=" + cident);
342 metadata_ = p.metadata;
348 if (!p.label.empty())
349 store (
"label", p.label);
351 store (
"nick", p.nick);
353 store (
"unit", p.unit);
357 extras_ = *choicesfuncp;
360 else if (fmin != fmax)
363 extras_ = minmaxstep_from_initialval (p.initial, &isbool);
364 initial_ = value_from_initialval (p.initial);
366 String choice = choicesp || choicesfuncp ?
"choice" :
"";
367 String text = choicesfuncp || initial_.is_string() ?
"text" :
"";
368 String dynamic = choicesfuncp ?
"dynamic" :
"";
369 String stepped = isbool ?
"stepped" :
"";
370 store (
"hints", construct_hints (p.hints, fetch (
"hints") +
":" + text +
":" + choice +
":" + dynamic +
":" + stepped, fmin, fmax));
375Parameter::value_to_text (
const Value &value)
const
379 const Value::Type type = value.index();
380 if (type != Value::BOOL && type != Value::INT64 && type != Value::DOUBLE)
381 return value.as_string();
382 double val = value.as_double();
383 String unit = this->unit();
384 if (unit ==
"Hz" && fabs (val) >= 1000)
392 else if (fabs (val) < 100)
394 else if (fabs (val) < 1000)
399 const bool need_sign =
fmin < 0;
401 if (fdigits == 0 && fabs (val) == 100 && unit ==
"%")
409Parameter::value_from_text (
const String &text)
const
412 const ChoiceS choices = this->choices();
413 return int64_t (match_choice (choices, text));
424 return { *
this,
id };
428ParameterMap::Entry::operator= (
const Param ¶m)
430 const char *
const FUNC =
"ParameterMap::Entry::operator=";
434 warning (
"%s: reassign parameter '%s' with: %s\n", FUNC, old->ident(), param.
ident);
436 auto it = pmap.find (
id - 1);
437 if (it != pmap.end() && it->second) {
439 if (it->second->ident() == param.
ident)
440 warning (
"%s: duplicate %s: '%s' (param_id=%u)", FUNC,
"ident", param.
ident,
id);
441 else if (it->second->label() == param.
label)
442 warning (
"%s: duplicate %s: '%s' (param_id=%u)", FUNC,
"label", param.
label,
id);
446 Param mparam = param;
447 mparam.store (
"group", map.
group);
457 return kvpairs_fetch (metadata,
"hints");
463 return kvpairs_fetch (metadata,
"blurb");
469 return kvpairs_fetch (metadata,
"descr");
475 return kvpairs_fetch (metadata,
"group");
483search_first_digit (
const String &s)
485 for (
size_t i = 0; i < s.
size(); ++i)
493search_last_digits (
const String &s)
495 for (
size_t i = 0; i < s.size(); ++i)
496 if (isdigit (s[i])) {
497 if (isdigit (s[i+1]) && !isalnum (s[i+2]))
499 else if (!isalnum (s[i+1]))
507make_nick3 (
const String &label)
513 if (words.size() == 1) {
514 const ssize_t d = search_first_digit (words[0]);
515 if (d > 0 && isdigit (words[0][d + 1]))
516 return { words[0].substr (0, 1), words[0].substr (d, 2),
"" };
518 return { words[0].substr (0, 2), words[0].substr (d, 1),
"" };
520 return { words[0].substr (0, 3),
"",
"" };
524 if (words.size() == 2) {
525 const ssize_t e = search_last_digits (words[1]);
526 if (e >= 0 && isdigit (words[1][e+1]))
527 return { words[0].substr (0, 1), words[1].substr (e, 2),
"" };
529 return { words[0].substr (0, 1), words[1].substr (0, 1), words[1].substr (e, 1) };
531 return { words[0].substr (0, 2), words[1].substr (e, 1),
"" };
532 const ssize_t d = search_first_digit (words[0]);
534 return { words[0].substr (0, 1), words[0].substr (d, 1), words[1].substr (0, 1) };
535 if (words[1].
size() > 1)
536 return { words[0].substr (0, 1), words[1].substr (0, 2),
"" };
538 return { words[0].substr (0, 2), words[1].substr (0, 1),
"" };
542 if (words.size() >= 3) {
544 for (i = words.size() - 1; i > 1; i--) {
545 e = search_last_digits (words[i]);
549 if (e >= 0 && isdigit (words[i][e + 1]))
550 return { words[0].substr (0, 1), words[i].substr (e, 2),
"" };
551 if (e >= 0 && i + 1 < words.size())
552 return { words[0].substr (0, 1), words[i].substr (e, 1), words[i+1].substr (0, 1) };
554 return { words[0].substr (0, 1), words[i].substr (0, 1), words[i].substr (e, 1) };
555 if (e == 0 && i >= 3)
556 return { words[0].substr (0, 1), words[i-1].substr (0, 1), words[i].substr (e, 1) };
557 if (e == 0 && i >= 2)
558 return { words[0].substr (0, 1), words[1].substr (0, 1), words[i].substr (e, 1) };
560 return { words[0].substr (0, 2), words[i].substr (e, 1),
"" };
561 if (words.back().size() >= 2)
562 return { words[0].substr (0, 1), words.back().substr (0, 2),
"" };
564 return { words[0].substr (0, 1), words[words.size()-1].substr (0, 1), words.back().substr (0, 1) };
568 return { words[0].substr (0, 3),
"",
"" };
575 for (ssize_t i = s.size() - 1; i > 0; i--)
577 s.
insert (s.begin() + i,
' ');
586 String string = spaced_nums (parameter_label);
589 const auto& [a, b, c] = make_nick3 (
string);
594 nick = a.
substr (0, 1) + b.substr (0, 1) + c.substr (0, 1);
595 else if (b.size() > 0)
596 nick = a.
substr (0, 1) + b.substr (0, 2);
String descr() const
Elaborate description, e.g. for help dialogs (metadata).
String blurb() const
Short description for user interface tooltips (metadata).
String hints() const
Hints for parameter handling (metadata).
String group() const
Group name for parameters of similar function (metadata).
static StringS findall(const String ®ex, const String &input, Flags=DEFAULT)
Find regex in input and return non-overlapping matches.
#define assert_return(expr,...)
Return from the current function if expr is unmet and issue an assertion warning.
#define return_unless(cond,...)
Return silently if cond does not evaluate to true with return value ...
The Anklang C++ API namespace.
std::string string_format(const char *format, const Args &...args) __attribute__((__format__(__printf__
Format a string similar to sprintf(3) with support for std::string and std::ostringstream convertible...
StringS string_split(const String &string, const String &splitter, size_t maxn)
String parameter_guess_nick(const String ¶meter_label)
Create a few letter nick name from a multi word parameter label.
String string_tolower(const String &str)
Convert all string characters into Unicode lower case characters.
std::tuple< double, double, double > MinMaxStep
Min, max, stepping for double ranges.
std::vector< String > StringS
Convenience alias for a std::vector<std::string>.
std::function< ChoiceS(const CString &)> ChoicesFunc
Handler to generate all possible parameter choices dynamically.
String string_option_find(const String &optionlist, const String &feature, const String &fallback)
Retrieve the option value from an options list separated by ':' or ';' or fallback.
double string_to_double(const String &string)
Parse a double from a string, trying locale specific characters and POSIX/C formatting.
std::string String
Convenience alias for std::string.
constexpr const char STANDARD[]
STORAGE GUI READABLE WRITABLE.
float damerau_levenshtein_restricted(const std::string &source, const std::string &target, const float ci, const float cd, const float cs, const float ct)
String string_to_ncname(const String &input, uint32_t substitute)
constexpr const double DOUBLE_EPSILON
Double round-off error at 1.0, equals 2^-53.
Structured initializer for Parameter.
StringS metadata
Array of "key=value" pairs.
String label
Preferred user interface name.
String ident
Identifier used for serialization (can be derived from untranslated label).
Entry operator[](uint32_t id)
Slot subscription for new Parameter creation.
String group
Group to be applied to all newly inserted Parameter objects.
MinMaxStep range() const
Min, max, stepping for double ranges.
double as_double() const
Convert Value to double or return 0.
bool is_numeric(bool boolisnumeric=true) const
Checks if Value is a DOUBLE, INT64, or BOOL.
String as_string() const
Convert Value to a string, not very useful for RECORD or ARRAY.