diff options
Diffstat (limited to 'libs')
-rw-r--r-- | libs/ardour/ardour/parameter_descriptor.h | 45 | ||||
-rw-r--r-- | libs/ardour/ardour/value_as_string.h | 81 | ||||
-rw-r--r-- | libs/ardour/automatable.cc | 17 | ||||
-rw-r--r-- | libs/ardour/lv2_plugin.cc | 45 |
4 files changed, 146 insertions, 42 deletions
diff --git a/libs/ardour/ardour/parameter_descriptor.h b/libs/ardour/ardour/parameter_descriptor.h index 8916f081a3..1576230b8f 100644 --- a/libs/ardour/ardour/parameter_descriptor.h +++ b/libs/ardour/ardour/parameter_descriptor.h @@ -33,24 +33,34 @@ typedef std::map<const std::string, const float> ScalePoints; */ struct ParameterDescriptor { + enum Unit { + NONE, ///< No unit + DB, ///< Decibels + MIDI_NOTE, ///< MIDI note number + }; + ParameterDescriptor(const Evoral::Parameter& parameter) : key((uint32_t)-1) , datatype(Variant::VOID) , normal(parameter.normal()) , lower(parameter.min()) , upper(parameter.max()) - , step(0) - , smallstep((upper - lower) / 100.0) - , largestep((upper - lower) / 10.0) - , integer_step(false) + , step((upper - lower) / 100.0f) + , smallstep((upper - lower) / 1000.0f) + , largestep((upper - lower) / 10.0f) + , integer_step(parameter.type() >= MidiCCAutomation && + parameter.type() <= MidiChannelPressureAutomation) , toggled(parameter.toggled()) , logarithmic(false) , sr_dependent(false) , min_unbound(0) , max_unbound(0) , enumeration(false) - , midinote(false) - {} + { + if (parameter.type() == GainAutomation) { + unit = DB; + } + } ParameterDescriptor() : key((uint32_t)-1) @@ -68,13 +78,33 @@ struct ParameterDescriptor , min_unbound(0) , max_unbound(0) , enumeration(false) - , midinote(false) {} + /// Set step, smallstep, and largestep, based on current description + void update_steps() { + if (unit == ParameterDescriptor::MIDI_NOTE) { + step = smallstep = 1; // semitone + largestep = 12; // octave + } else { + const float delta = upper - lower; + + step = delta / 1000.0f; + smallstep = delta / 10000.0f; + largestep = delta / 10.0f; + + if (integer_step) { + step = rint(step); + largestep = rint(largestep); + // leave smallstep alone for fine tuning + } + } + } + std::string label; boost::shared_ptr<ScalePoints> scale_points; uint32_t key; ///< for properties Variant::Type datatype; ///< for properties + Unit unit; float normal; float lower; ///< for frequencies, this is in Hz (not a fraction of the sample rate) float upper; ///< for frequencies, this is in Hz (not a fraction of the sample rate) @@ -88,7 +118,6 @@ struct ParameterDescriptor bool min_unbound; bool max_unbound; bool enumeration; - bool midinote; ///< only used if integer_step is also true }; } // namespace ARDOUR diff --git a/libs/ardour/ardour/value_as_string.h b/libs/ardour/ardour/value_as_string.h new file mode 100644 index 0000000000..6c17ace5d3 --- /dev/null +++ b/libs/ardour/ardour/value_as_string.h @@ -0,0 +1,81 @@ +/* + Copyright (C) 2014 Paul Davis + Author: David Robillard + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __ardour_value_as_string_h__ +#define __ardour_value_as_string_h__ + +#include <stddef.h> + +#include "ardour/parameter_descriptor.h" + +namespace ARDOUR { + +inline std::string +value_as_string(const ARDOUR::ParameterDescriptor& desc, + double v) +{ + char buf[32]; + + if (desc.scale_points) { + // Check if value is on a scale point + for (ARDOUR::ScalePoints::const_iterator i = desc.scale_points->begin(); + i != desc.scale_points->end(); + ++i) { + if (i->second == v) { + return i->first; // Found it, return scale point label + } + } + } + + // Value is not a scale point, print it normally + if (desc.unit == ARDOUR::ParameterDescriptor::MIDI_NOTE) { + if (v >= 0 && v <= 127) { + const int num = rint(v); + static const char names[12][3] = { + "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" + }; + snprintf(buf, sizeof(buf), "%s %d", names[num % 12], (num / 12) - 2); + } else { + // Odd, invalid range, just print the number + snprintf(buf, sizeof(buf), "%.0f", v); + } + } else if (desc.integer_step) { + snprintf(buf, sizeof(buf), "%d", (int)v); + } else { + snprintf(buf, sizeof(buf), "%.2f", v); + } + if (desc.unit == ARDOUR::ParameterDescriptor::DB) { + // TODO: Move proper dB printing from AutomationLine here + return std::string(buf) + " dB"; + } + return buf; +} + +inline std::string +value_as_string(const ARDOUR::ParameterDescriptor& desc, + const ARDOUR::Variant& val) +{ + // Only numeric support, for now + return value_as_string(desc, val.to_double()); +} + +} // namespace ARDOUR + +#endif /* __ardour_value_as_string_h__ */ diff --git a/libs/ardour/automatable.cc b/libs/ardour/automatable.cc index 466899ce48..b4d957c8b6 100644 --- a/libs/ardour/automatable.cc +++ b/libs/ardour/automatable.cc @@ -35,6 +35,7 @@ #include "ardour/plugin_insert.h" #include "ardour/session.h" #include "ardour/uri_map.h" +#include "ardour/value_as_string.h" #include "i18n.h" @@ -474,19 +475,5 @@ Automatable::clear_controls () string Automatable::value_as_string (boost::shared_ptr<AutomationControl> ac) const { - std::stringstream s; - - /* this is a the default fallback for this virtual method. Derived Automatables - are free to override this to display the values of their parameters/controls - in different ways. - */ - - // Hack to display CC as integer value, rather than double - if (ac->parameter().type() == MidiCCAutomation) { - s << lrint (ac->get_value()); - } else { - s << std::fixed << std::setprecision(3) << ac->get_value(); - } - - return s.str (); + return ARDOUR::value_as_string(ac->desc(), ac->get_value()); } diff --git a/libs/ardour/lv2_plugin.cc b/libs/ardour/lv2_plugin.cc index cf33c22424..dca91fd646 100644 --- a/libs/ardour/lv2_plugin.cc +++ b/libs/ardour/lv2_plugin.cc @@ -66,6 +66,7 @@ #include "lv2/lv2plug.in/ns/ext/worker/worker.h" #include "lv2/lv2plug.in/ns/ext/resize-port/resize-port.h" #include "lv2/lv2plug.in/ns/extensions/ui/ui.h" +#include "lv2/lv2plug.in/ns/extensions/units/units.h" #include "lv2/lv2plug.in/ns/ext/patch/patch.h" #ifdef HAVE_LV2_1_2_0 #include "lv2/lv2plug.in/ns/ext/buf-size/buf-size.h" @@ -138,6 +139,7 @@ public: LilvNode* ui_GtkUI; LilvNode* ui_external; LilvNode* ui_externalkx; + LilvNode* units_db; LilvNode* units_unit; LilvNode* units_midiNote; LilvNode* patch_writable; @@ -1312,10 +1314,10 @@ LV2Plugin::get_property_descriptor(uint32_t id) const } static void -set_parameter_descriptor(LV2World& world, - ParameterDescriptor& desc, - Variant::Type datatype, - const LilvNode* subject) +load_parameter_descriptor(LV2World& world, + ParameterDescriptor& desc, + Variant::Type datatype, + const LilvNode* subject) { LilvWorld* lworld = _world.world; LilvNode* label = lilv_world_get(lworld, subject, _world.rdfs_label, NULL); @@ -1337,6 +1339,12 @@ set_parameter_descriptor(LV2World& world, desc.datatype = datatype; desc.toggled |= datatype == Variant::BOOL; desc.integer_step |= datatype == Variant::INT || datatype == Variant::LONG; + if (lilv_world_ask(lworld, subject, _world.units_unit, _world.units_midiNote)) { + desc.unit = ParameterDescriptor::MIDI_NOTE; + } else if (lilv_world_ask(lworld, subject, _world.units_unit, _world.units_db)) { + desc.unit = ParameterDescriptor::DB; + } + desc.update_steps(); } void @@ -1368,7 +1376,7 @@ LV2Plugin::load_supported_properties(PropertyDescriptors& descs) ParameterDescriptor desc; desc.key = _uri_map.uri_to_id(lilv_node_as_uri(prop)); desc.datatype = datatype; - set_parameter_descriptor(_world, desc, datatype, prop); + load_parameter_descriptor(_world, desc, datatype, prop); descs.insert(std::make_pair(desc.key, desc)); lilv_node_free(range); @@ -1560,6 +1568,8 @@ LV2Plugin::get_parameter_descriptor(uint32_t which, ParameterDescriptor& desc) c lilv_port_get_range(_impl->plugin, port, &def, &min, &max); portunits = lilv_port_get_value(_impl->plugin, port, _world.units_unit); + // TODO: Once we can rely on lilv 0.18.0 being present, + // load_parameter_descriptor() can be used for ports as well desc.integer_step = lilv_port_has_property(_impl->plugin, port, _world.lv2_integer); desc.toggled = lilv_port_has_property(_impl->plugin, port, _world.lv2_toggled); desc.logarithmic = lilv_port_has_property(_impl->plugin, port, _world.ext_logarithmic); @@ -1567,7 +1577,11 @@ LV2Plugin::get_parameter_descriptor(uint32_t which, ParameterDescriptor& desc) c desc.label = lilv_node_as_string(lilv_port_get_name(_impl->plugin, port)); desc.lower = min ? lilv_node_as_float(min) : 0.0f; desc.upper = max ? lilv_node_as_float(max) : 1.0f; - desc.midinote = lilv_nodes_contains(portunits, _world.units_midiNote); + if (lilv_nodes_contains(portunits, _world.units_midiNote)) { + desc.unit = ParameterDescriptor::MIDI_NOTE; + } else if (lilv_nodes_contains(portunits, _world.units_db)) { + desc.unit = ParameterDescriptor::DB; + } if (desc.sr_dependent) { desc.lower *= _session.frame_rate (); @@ -1577,20 +1591,11 @@ LV2Plugin::get_parameter_descriptor(uint32_t which, ParameterDescriptor& desc) c desc.min_unbound = false; // TODO: LV2 extension required desc.max_unbound = false; // TODO: LV2 extension required - if (desc.integer_step) { - desc.step = 1.0; - desc.smallstep = 0.1; - desc.largestep = 10.0; - } else { - const float delta = desc.upper - desc.lower; - desc.step = delta / 1000.0f; - desc.smallstep = delta / 10000.0f; - desc.largestep = delta / 10.0f; - } - desc.enumeration = lilv_port_has_property(_impl->plugin, port, _world.lv2_enumeration); desc.scale_points = get_scale_points(which); + desc.update_steps(); + lilv_node_free(def); lilv_node_free(min); lilv_node_free(max); @@ -2274,8 +2279,9 @@ LV2World::LV2World() ui_GtkUI = lilv_new_uri(world, LV2_UI__GtkUI); ui_external = lilv_new_uri(world, "http://lv2plug.in/ns/extensions/ui#external"); ui_externalkx = lilv_new_uri(world, "http://kxstudio.sf.net/ns/lv2ext/external-ui#Widget"); - units_unit = lilv_new_uri(world, "http://lv2plug.in/ns/extensions/units#unit"); - units_midiNote = lilv_new_uri(world, "http://lv2plug.in/ns/extensions/units#midiNote"); + units_unit = lilv_new_uri(world, LV2_UNITS__unit); + units_midiNote = lilv_new_uri(world, LV2_UNITS__midiNote); + units_db = lilv_new_uri(world, LV2_UNITS__db); patch_writable = lilv_new_uri(world, LV2_PATCH__writable); patch_Message = lilv_new_uri(world, LV2_PATCH__Message); } @@ -2285,6 +2291,7 @@ LV2World::~LV2World() lilv_node_free(patch_Message); lilv_node_free(patch_writable); lilv_node_free(units_midiNote); + lilv_node_free(units_db); lilv_node_free(units_unit); lilv_node_free(ui_externalkx); lilv_node_free(ui_external); |