X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fparameter_descriptor.cc;h=4f26af997d843087dca66a5c4d4ea6f5a7620ee6;hb=5fa05b403ca21a6573d07b921dc14f0769dc9fc7;hp=7ed0c785126d6a9808182a37aa3123e1aaaa48ae;hpb=37905d82a611a09342faf52d01378c9b4e86a2ac;p=ardour.git diff --git a/libs/ardour/parameter_descriptor.cc b/libs/ardour/parameter_descriptor.cc index 7ed0c78512..4f26af997d 100644 --- a/libs/ardour/parameter_descriptor.cc +++ b/libs/ardour/parameter_descriptor.cc @@ -17,6 +17,7 @@ 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include #include #include "pbd/control_math.h" @@ -100,20 +101,29 @@ ParameterDescriptor::ParameterDescriptor(const Evoral::Parameter& parameter) lower = 0.0; normal = 0.0; upper = 127.0; + print_fmt = "%.0f"; break; case MidiPitchBenderAutomation: lower = 0.0; normal = 8192.0; upper = 16383.0; + print_fmt = "%.0f"; break; case PhaseAutomation: toggled = true; + scale_points = boost::shared_ptr(new ScalePoints()); + scale_points->insert (std::make_pair (_("Normal"), 0)); + scale_points->insert (std::make_pair (_("Invert"), 1)); break; case MonitoringAutomation: enumeration = true; integer_step = true; lower = MonitorAuto; upper = MonitorDisk; /* XXX bump when we add MonitorCue */ + scale_points = boost::shared_ptr(new ScalePoints()); + scale_points->insert (std::make_pair (_("Auto"), MonitorAuto)); + scale_points->insert (std::make_pair (_("Input"), MonitorInput)); + scale_points->insert (std::make_pair (_("Disk"), MonitorDisk)); break; case SoloIsolateAutomation: case SoloSafeAutomation: @@ -143,6 +153,43 @@ ParameterDescriptor::ParameterDescriptor() void ParameterDescriptor::update_steps() { + /* sanitize flags */ + if (toggled || enumeration) { + logarithmic = false; + } + if (logarithmic && sr_dependent && upper > lower && lower == 0) { + /* work-around for plugins with a log-scale control 0..SR; log (0) is not defined */ + lower = upper / 1000.f; + } + if (logarithmic && (upper <= lower || lower * upper <= 0)) { + /* log-scale params need upper > lower and both values need the same sign */ + logarithmic = false; + } + if (rangesteps < 2) { + rangesteps = 0; + } + if (enumeration) { + /* enums need scale-points. + * The GUI is more restrictive, a dropdown is displayed + * IIF scale_points.size() == (1 + upper - lower) + */ + if (!scale_points || scale_points->empty ()) { + enumeration = false; + } + } + if (integer_step) { + if (lower >= upper) { + integer_step = false; + } + } + + /* upper == lower does not make any sense */ + if (lower == upper) { + upper = lower + 0.01; // add some arbitrary value + } + + /* set steps */ + if (unit == ParameterDescriptor::MIDI_NOTE) { step = smallstep = 1; // semitone largestep = 12; // octave @@ -153,33 +200,39 @@ ParameterDescriptor::update_steps() largestep = position_to_gain (dB_coeff_step(upper)); step = position_to_gain (largestep / 10.0); smallstep = step; - } else { - /* note that LV2Plugin::get_parameter_descriptor () - * overrides this is lv2:rangeStep is set for a port. + } else if (logarithmic) { + /* ignore logscale rangesteps. {small|large}steps are used with the spinbox. + * gtk-spinbox shows the internal (not interface) value and up/down + * arrows linearly increase. + * The AutomationController uses internal_to_interface(): + * ui-step [0..1] -> log (1 + largestep / lower) / log (upper / lower) + * so we use a step that's a multiple of "lower" for the interface step: + * log (1 + x) / log (upper / lower) */ + smallstep = step = lower / 11; + largestep = lower / 3; + /* NOTE: the actual value does use rangesteps via + * logscale_to_position_with_steps(), position_to_logscale_with_steps() + * when it is converted. + */ + } else if (rangesteps > 1) { const float delta = upper - lower; - - /* 30 happens to be the total number of steps for a fader with default - max gain of 2.0 (6 dB), so we use 30 here too for consistency. */ - step = smallstep = (delta / 300.0f); - largestep = (delta / 30.0f); - - if (logarithmic) { - /* Steps are linear, but we map them with pow like values (in - internal_to_interface). Thus, they are applied exponentially, - which means too few steps. So, divide to get roughly the - desired number of steps (30). This is not mathematically - precise but seems to be about right for the controls I tried. - If you're reading this, you've probably found a case where that - isn't true, and somebody needs to sit down with a piece of paper - and actually do the math. */ - smallstep = smallstep / logf(30.0f); - step = step / logf(30.0f); - largestep = largestep / logf(30.0f); - } else if (integer_step) { - smallstep = 1.0; - step = std::max(1.f, rintf (step)); - largestep = std::max(1.f, rintf (largestep)); + if (integer_step) { + smallstep = step = 1.0; + largestep = std::max(1.f, rintf (delta / (rangesteps - 1.f))); + } else { + step = smallstep = delta / (rangesteps - 1.f); + largestep = std::min ((delta / 4.0f), 10.f * smallstep); + } + } else { + const float delta = upper - lower; + /* 30 steps between min/max (300 for fine-grained) */ + if (integer_step) { + smallstep = step = 1.0; + largestep = std::max(1.f, rintf (delta / 30.f)); + } else { + step = smallstep = (delta / 300.0f); + largestep = (delta / 30.0f); } } } @@ -269,7 +322,7 @@ ParameterDescriptor::to_interface (float val) const break; case PanAzimuthAutomation: case PanElevationAutomation: - val = 1.f - val; + val = val; break; case PanWidthAutomation: val = .5f + val * .5f; @@ -320,7 +373,7 @@ ParameterDescriptor::from_interface (float val) const break; case PanAzimuthAutomation: case PanElevationAutomation: - val = 1.f - val; + val = val; break; case PanWidthAutomation: val = 2.f * val - 1.f; @@ -340,10 +393,10 @@ ParameterDescriptor::from_interface (float val) const * e.g. 5 integers 0,1,2,3,4 are mapped to a fader * [0.0 .. 0.2 | 0.2 .. 0.4 | 0.4 .. 0.6 | 0.6 .. 0.8 | 0.8 .. 1.0] */ - val = round (lower + val * (1.f + upper - lower) - .5f); + val = floor (lower + val * (1.f + upper - lower)); } else if (rangesteps > 1) { /* similar to above, but for float controls */ - val = floor (val * (rangesteps - 1.f)) / (rangesteps - 1.f); // XXX + val = round (val * (rangesteps - 1.f)) / (rangesteps - 1.f); // XXX val = val * (upper - lower) + lower; } else { val = val * (upper - lower) + lower; @@ -354,4 +407,80 @@ ParameterDescriptor::from_interface (float val) const return val; } +bool +ParameterDescriptor::is_linear () const +{ + if (logarithmic) { + return false; + } + switch(type) { + case GainAutomation: + case EnvelopeAutomation: + case BusSendLevel: + return false; + default: + break; + } + return true; +} + +float +ParameterDescriptor::compute_delta (float from, float to) const +{ + if (is_linear ()) { + return to - from; + } + if (from == 0) { + return 0; + } + return to / from; +} + +float +ParameterDescriptor::apply_delta (float val, float delta) const +{ + if (is_linear ()) { + return val + delta; + } else { + return val * delta; + } +} + +float +ParameterDescriptor::step_enum (float val, bool prev) const +{ + if (!enumeration) { + return val; + } + assert (scale_points && !scale_points->empty ()); + float rv = scale_points->begin()->second; + float delta = fabsf (val - rv); + std::vector avail; + + for (ScalePoints::const_iterator i = scale_points->begin (); i != scale_points->end (); ++i) { + float s = i->second; + avail.push_back (s); + if (fabsf (val - s) < delta) { + rv = s; + delta = fabsf (val - s); + } + } + /* ScalePoints map is sorted by text string */ + std::sort (avail.begin (), avail.end ()); + std::vector::const_iterator it = std::find (avail.begin (), avail.end (), rv); + assert (it != avail.end()); + + if (prev) { + if (it == avail.begin()) { + return rv; + } + return *(--it); + } else { + if (++it == avail.end()) { + return rv; + } + return *(it); + } +} + } // namespace ARDOUR