You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

166 lines
3.5KB

  1. #include <tinyexpr.h>
  2. #include <Quantity.hpp>
  3. #include <string.hpp>
  4. // for C4 and A4 frequencies
  5. #include <dsp/common.hpp>
  6. namespace rack {
  7. float Quantity::getDisplayValue() {
  8. return getValue();
  9. }
  10. void Quantity::setDisplayValue(float displayValue) {
  11. setValue(displayValue);
  12. }
  13. int Quantity::getDisplayPrecision() {
  14. return 5;
  15. }
  16. std::string Quantity::getDisplayValueString() {
  17. float v = getDisplayValue();
  18. if (std::isnan(v))
  19. return "NaN";
  20. return string::f("%.*g", getDisplayPrecision(), math::normalizeZero(v));
  21. }
  22. /** Build-in variables for tinyexpr */
  23. struct TeVariable {
  24. std::string name;
  25. double value;
  26. };
  27. static std::vector<TeVariable> teVariables;
  28. static std::vector<te_variable> teVars;
  29. static void teVarsInit() {
  30. if (!teVars.empty())
  31. return;
  32. // Add variables
  33. teVariables.push_back({"inf", INFINITY});
  34. teVariables.push_back({"c", dsp::FREQ_C4});
  35. teVariables.push_back({"a", dsp::FREQ_A4});
  36. for (int i = 0; i <= 8; i++)
  37. teVariables.push_back({string::f("c%d", i), dsp::FREQ_C4 * std::pow(2.0, i - 4)});
  38. for (int i = 0; i <= 8; i++)
  39. teVariables.push_back({string::f("a%d", i), dsp::FREQ_A4 * std::pow(2.0, i - 4)});
  40. // Build teVars
  41. teVars.resize(teVariables.size());
  42. for (size_t i = 0; i < teVariables.size(); i++) {
  43. teVars[i].name = teVariables[i].name.c_str();
  44. teVars[i].address = &teVariables[i].value;
  45. teVars[i].type = TE_VARIABLE;
  46. teVars[i].context = NULL;
  47. }
  48. }
  49. void Quantity::setDisplayValueString(std::string s) {
  50. teVarsInit();
  51. // Uppercase letters aren't needed in formulas, so convert to lowercase in case user types INF or C4.
  52. s = string::lowercase(s);
  53. // Compile string with tinyexpr
  54. te_expr* expr = te_compile(s.c_str(), teVars.data(), teVars.size(), NULL);
  55. if (!expr)
  56. return;
  57. double result = te_eval(expr);
  58. te_free(expr);
  59. if (std::isnan(result))
  60. return;
  61. setDisplayValue(result);
  62. }
  63. std::string Quantity::getString() {
  64. std::string s;
  65. std::string label = getLabel();
  66. std::string valueString = getDisplayValueString() + getUnit();
  67. s += label;
  68. if (label != "" && valueString != "")
  69. s += ": ";
  70. s += valueString;
  71. return s;
  72. }
  73. void Quantity::reset() {
  74. setValue(getDefaultValue());
  75. }
  76. void Quantity::randomize() {
  77. if (isBounded())
  78. setScaledValue(random::uniform());
  79. }
  80. bool Quantity::isMin() {
  81. return getValue() <= getMinValue();
  82. }
  83. bool Quantity::isMax() {
  84. return getValue() >= getMaxValue();
  85. }
  86. void Quantity::setMin() {
  87. setValue(getMinValue());
  88. }
  89. void Quantity::setMax() {
  90. setValue(getMaxValue());
  91. }
  92. void Quantity::toggle() {
  93. setValue(isMin() ? getMaxValue() : getMinValue());
  94. }
  95. void Quantity::moveValue(float deltaValue) {
  96. setValue(getValue() + deltaValue);
  97. }
  98. float Quantity::getRange() {
  99. return getMaxValue() - getMinValue();
  100. }
  101. bool Quantity::isBounded() {
  102. return std::isfinite(getMinValue()) && std::isfinite(getMaxValue());
  103. }
  104. float Quantity::toScaled(float value) {
  105. if (!isBounded())
  106. return value;
  107. else if (getMinValue() == getMaxValue())
  108. return 0.f;
  109. else
  110. return math::rescale(value, getMinValue(), getMaxValue(), 0.f, 1.f);
  111. }
  112. float Quantity::fromScaled(float scaledValue) {
  113. if (!isBounded())
  114. return scaledValue;
  115. else
  116. return math::rescale(scaledValue, 0.f, 1.f, getMinValue(), getMaxValue());
  117. }
  118. void Quantity::setScaledValue(float scaledValue) {
  119. setValue(fromScaled(scaledValue));
  120. }
  121. float Quantity::getScaledValue() {
  122. return toScaled(getValue());
  123. }
  124. void Quantity::moveScaledValue(float deltaScaledValue) {
  125. if (!isBounded())
  126. moveValue(deltaScaledValue);
  127. else
  128. moveValue(deltaScaledValue * getRange());
  129. }
  130. } // namespace rack