diff --git a/include/Lv2Ports.h b/include/Lv2Ports.h index e61f9bbd1cf..a0d68f24fd8 100644 --- a/include/Lv2Ports.h +++ b/include/Lv2Ports.h @@ -108,11 +108,17 @@ struct Meta Flow m_flow = Flow::Unknown; Vis m_vis = Vis::None; - float m_def = .0f, m_min = .0f, m_max = .0f; bool m_optional = false; bool m_used = true; std::vector get(const LilvPlugin* plugin, std::size_t portNum); + + float def() const { return m_def; } + float min(sample_rate_t sr) const { return m_sampleRate ? sr * m_min : m_min; } + float max(sample_rate_t sr) const { return m_sampleRate ? sr * m_max : m_max; } +private: + float m_def = .0f, m_min = .0f, m_max = .0f; + bool m_sampleRate = false; }; struct PortBase : public Meta diff --git a/include/PluginIssue.h b/include/PluginIssue.h index 00c90b756f1..0cf713f355b 100644 --- a/include/PluginIssue.h +++ b/include/PluginIssue.h @@ -42,6 +42,7 @@ enum PluginIssueType portHasNoDef, portHasNoMin, portHasNoMax, + defaultValueNotInRange, featureNotSupported, //!< plugin requires functionality LMMS can't offer badPortType, //!< port type not supported noIssue diff --git a/src/core/PluginIssue.cpp b/src/core/PluginIssue.cpp index 8e1938e5685..069e718cb40 100644 --- a/src/core/PluginIssue.cpp +++ b/src/core/PluginIssue.cpp @@ -50,6 +50,8 @@ const char *PluginIssue::msgFor(const PluginIssueType &it) return "port is missing min value"; case portHasNoMax: return "port is missing max value"; + case defaultValueNotInRange: + return "default value is not in range [min, max]"; case featureNotSupported: return "required feature not supported"; case badPortType: diff --git a/src/core/lv2/Lv2Ports.cpp b/src/core/lv2/Lv2Ports.cpp index cc8ecf6ca43..3bca0c89f1e 100644 --- a/src/core/lv2/Lv2Ports.cpp +++ b/src/core/lv2/Lv2Ports.cpp @@ -151,10 +151,34 @@ std::vector Meta::get(const LilvPlugin *plugin, }; takeRangeValue(def.get(), m_def, portHasNoDef); - if (!isToggle) + if (isToggle) + { + m_min = .0f; + m_max = 1.f; + if(def.get() && m_def != m_min && m_def != m_max) + { + issue(defaultValueNotInRange, portName); + } + } + else { takeRangeValue(min.get(), m_min, portHasNoMin); takeRangeValue(max.get(), m_max, portHasNoMax); + if (hasProperty(LV2_CORE__sampleRate)) { m_sampleRate = true; } + + if (def.get()) + { + if (m_def < m_min) { issue(defaultValueNotInRange, portName); } + else if (m_def > m_max) + { + if(m_sampleRate) + { + // multiplying with sample rate will hopefully lead us + // to a good default value + } + else { issue(defaultValueNotInRange, portName); } + } + } if (m_max - m_min > 15.0f) { diff --git a/src/core/lv2/Lv2Proc.cpp b/src/core/lv2/Lv2Proc.cpp index 925dca5bd0c..23212c2e0a2 100644 --- a/src/core/lv2/Lv2Proc.cpp +++ b/src/core/lv2/Lv2Proc.cpp @@ -455,12 +455,23 @@ void Lv2Proc::createPort(std::size_t portNum) { AutoLilvNode node(lilv_port_get_name(m_plugin, lilvPort)); QString dispName = lilv_node_as_string(node.get()); + sample_rate_t sr = Engine::mixer()->processingSampleRate(); + if(meta.def() < meta.min(sr) || meta.def() > meta.max(sr)) + { + qWarning() << "Warning: Plugin" + << qStringFromPluginNode(m_plugin, lilv_plugin_get_name) + << "(URI:" + << lilv_node_as_uri(lilv_plugin_get_uri(m_plugin)) + << ") has a default value for port" + << dispName + << "which is not in range [min, max]."; + } switch (meta.m_vis) { case Lv2Ports::Vis::None: { // allow ~1000 steps - float stepSize = (meta.m_max - meta.m_min) / 1000.0f; + float stepSize = (meta.max(sr) - meta.min(sr)) / 1000.0f; // make multiples of 0.01 (or 0.1 for larger values) float minStep = (stepSize >= 1.0f) ? 0.1f : 0.01f; @@ -468,15 +479,15 @@ void Lv2Proc::createPort(std::size_t portNum) stepSize = std::max(stepSize, minStep); ctrl->m_connectedModel.reset( - new FloatModel(meta.m_def, meta.m_min, meta.m_max, + new FloatModel(meta.def(), meta.min(sr), meta.max(sr), stepSize, nullptr, dispName)); break; } case Lv2Ports::Vis::Integer: ctrl->m_connectedModel.reset( - new IntModel(static_cast(meta.m_def), - static_cast(meta.m_min), - static_cast(meta.m_max), + new IntModel(static_cast(meta.def()), + static_cast(meta.min(sr)), + static_cast(meta.max(sr)), nullptr, dispName)); break; case Lv2Ports::Vis::Enumeration: @@ -497,11 +508,12 @@ void Lv2Proc::createPort(std::size_t portNum) } lilv_scale_points_free(sps); ctrl->m_connectedModel.reset(comboModel); + // TODO: use default value on comboModel, too? break; } case Lv2Ports::Vis::Toggled: ctrl->m_connectedModel.reset( - new BoolModel(static_cast(meta.m_def), + new BoolModel(static_cast(meta.def()), nullptr, dispName)); break; } @@ -735,9 +747,10 @@ void Lv2Proc::dumpPort(std::size_t num) qDebug() << " visualization: " << Lv2Ports::toStr(port.m_vis); if (port.m_type == Lv2Ports::Type::Control || port.m_type == Lv2Ports::Type::Cv) { - qDebug() << " default:" << port.m_def; - qDebug() << " min:" << port.m_min; - qDebug() << " max:" << port.m_max; + sample_rate_t sr = Engine::mixer()->processingSampleRate(); + qDebug() << " default:" << port.def(); + qDebug() << " min:" << port.min(sr); + qDebug() << " max:" << port.max(sr); } qDebug() << " optional: " << port.m_optional; qDebug() << " => USED: " << port.m_used; diff --git a/src/gui/Lv2ViewBase.cpp b/src/gui/Lv2ViewBase.cpp index 488705bcb66..a3ef260581d 100644 --- a/src/gui/Lv2ViewBase.cpp +++ b/src/gui/Lv2ViewBase.cpp @@ -44,6 +44,7 @@ #include "Lv2Proc.h" #include "Lv2Ports.h" #include "MainWindow.h" +#include "Mixer.h" #include "SubWindow.h" @@ -70,9 +71,12 @@ Lv2ViewProc::Lv2ViewProc(QWidget* parent, Lv2Proc* ctrlBase, int colNum) : m_control = new KnobControl(m_par); break; case PortVis::Integer: - m_control = new LcdControl((port.m_max <= 9.0f) ? 1 : 2, + { + sample_rate_t sr = Engine::mixer()->processingSampleRate(); + m_control = new LcdControl((port.max(sr) <= 9.0f) ? 1 : 2, m_par); break; + } case PortVis::Enumeration: m_control = new ComboControl(m_par); break;