From fd36355e2cd95550a0f7d9b7a6f5e3bc2fcc7fa2 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Wed, 21 Jun 2017 13:03:00 +0200 Subject: Log-scale/relative automation point dragging --- gtk2_ardour/automation_line.cc | 151 +++++++++++++++++++++++++++-------------- gtk2_ardour/automation_line.h | 9 ++- gtk2_ardour/editor_drag.cc | 13 ++-- 3 files changed, 112 insertions(+), 61 deletions(-) diff --git a/gtk2_ardour/automation_line.cc b/gtk2_ardour/automation_line.cc index 8624d43947..9523df2c57 100644 --- a/gtk2_ardour/automation_line.cc +++ b/gtk2_ardour/automation_line.cc @@ -342,14 +342,11 @@ AutomationLine::get_verbose_cursor_string (double fraction) const } string -AutomationLine::get_verbose_cursor_relative_string (double original, double fraction) const +AutomationLine::get_verbose_cursor_relative_string (double fraction, double delta) const { std::string s = fraction_to_string (fraction); - std::string d = fraction_to_relative_string (original, fraction); - if (!d.empty()) { - s += " (\u0394" + d + ")"; - } - return s; + std::string d = delta_to_string (delta); + return s + " (" + d + ")"; } /** @@ -359,37 +356,18 @@ AutomationLine::get_verbose_cursor_relative_string (double original, double frac string AutomationLine::fraction_to_string (double fraction) const { - return ARDOUR::value_as_string (_desc, _desc.from_interface (fraction)); + view_to_model_coord_y (fraction); + return ARDOUR::value_as_string (_desc, fraction); } -/** - * @param original an old y-axis fraction - * @param fraction the new y fraction - * @return string representation of the difference between original and fraction, using dB if appropriate. - */ string -AutomationLine::fraction_to_relative_string (double original, double fraction) const +AutomationLine::delta_to_string (double delta) const { - if (original == fraction) { - return ARDOUR::value_as_string (_desc, 0); - } - switch (_desc.type) { - case GainAutomation: - case EnvelopeAutomation: - case TrimAutomation: - if (original == 0.0) { - /* there is no sensible representation of a relative - * change from -inf dB, so return an empty string. - */ - return ""; - } else if (fraction == 0.0) { - return "-inf dB"; - } - return ARDOUR::value_as_string (_desc, _desc.from_interface (fraction) / _desc.from_interface(original)); - default: - break; + if (!get_uses_gain_mapping () && _desc.logarithmic) { + return "x " + ARDOUR::value_as_string (_desc, delta); + } else { + return "\u0394 " + ARDOUR::value_as_string (_desc, delta); } - return ARDOUR::value_as_string (_desc, _desc.from_interface (fraction) - _desc.from_interface(original)); } /** @@ -415,7 +393,8 @@ AutomationLine::string_to_fraction (string const & s) const default: break; } - return _desc.to_interface (v); + model_to_view_coord_y (v); + return v; } /** Start dragging a single point, possibly adding others if the supplied point is selected and there @@ -564,10 +543,17 @@ AutomationLine::ContiguousControlPoints::clamp_dx (double dx) } void -AutomationLine::ContiguousControlPoints::move (double dx, double dy) +AutomationLine::ContiguousControlPoints::move (double dx, double dvalue) { for (std::list::iterator i = begin(); i != end(); ++i) { - (*i)->move_to ((*i)->get_x() + dx, (*i)->get_y() - line.height() * dy, ControlPoint::Full); + // compute y-axis delta + double view_y = 1.0 - (*i)->get_y() / line.height(); + line.view_to_model_coord_y (view_y); + line.apply_delta (view_y, dvalue); + line.model_to_view_coord_y (view_y); + view_y = (1.0 - view_y) * line.height(); + + (*i)->move_to ((*i)->get_x() + dx, view_y, ControlPoint::Full); line.reset_line_coords (**i); } } @@ -596,11 +582,11 @@ AutomationLine::start_drag_common (double x, float fraction) * @param fraction New y fraction. * @return x position and y fraction that were actually used (once clamped). */ -pair +pair AutomationLine::drag_motion (double const x, float fraction, bool ignore_x, bool with_push, uint32_t& final_index) { if (_drag_points.empty()) { - return pair (x,fraction); + return pair (fraction, _desc.is_linear () ? 0 : 1); } double dx = ignore_x ? 0 : (x - _drag_x); @@ -657,24 +643,42 @@ AutomationLine::drag_motion (double const x, float fraction, bool ignore_x, bool } } + /* compute deflection */ + double delta_value; + { + double value0 = _last_drag_fraction; + double value1 = _last_drag_fraction + dy; + view_to_model_coord_y (value0); + view_to_model_coord_y (value1); + delta_value = compute_delta (value0, value1); + } + + /* special case -inf */ + if (delta_value == 0 && dy > 0 && !_desc.is_linear ()) { + assert (_desc.lower == 0); + delta_value = 1.0; + } + /* clamp y */ for (list::iterator i = _drag_points.begin(); i != _drag_points.end(); ++i) { - double const y = ((_height - (*i)->get_y()) / _height) + dy; - if (y < 0) { - dy -= y; + double vy = 1.0 - (*i)->get_y() / _height; + view_to_model_coord_y (vy); + const double orig = vy; + apply_delta (vy, delta_value); + if (vy < _desc.lower) { + delta_value = compute_delta (orig, _desc.lower); } - if (y > 1) { - dy -= (y - 1); + if (vy > _desc.upper) { + delta_value = compute_delta (orig, _desc.upper); } } if (dx || dy) { - /* and now move each section */ - for (vector::iterator ccp = contiguous_points.begin(); ccp != contiguous_points.end(); ++ccp) { - (*ccp)->move (dx, dy); + (*ccp)->move (dx, delta_value); } + if (with_push) { final_index = contiguous_points.back()->back()->view_index () + 1; ControlPoint* p; @@ -686,20 +690,32 @@ AutomationLine::drag_motion (double const x, float fraction, bool ignore_x, bool } } - /* update actual line coordinates (will queue a redraw) - */ + /* update actual line coordinates (will queue a redraw) */ if (line_points.size() > 1) { line->set_steps (line_points, is_stepped()); } } + + /* calculate effective delta */ + ControlPoint* cp = _drag_points.front(); + double vy = 1.0 - cp->get_y() / (double)_height; + view_to_model_coord_y (vy); + float val = (*(cp->model ()))->value; + float effective_delta = _desc.compute_delta (val, vy); + /* special case recovery from -inf */ + if (val == 0 && effective_delta == 0 && vy > 0) { + assert (!_desc.is_linear ()); + effective_delta = HUGE_VAL; // +Infinity + } + double const result_frac = _last_drag_fraction + dy; _drag_distance += dx; _drag_x += dx; _last_drag_fraction = result_frac; did_push = with_push; - return pair (_drag_x + dx, result_frac); + return pair (result_frac, effective_delta); } /** Should be called to indicate the end of a drag */ @@ -750,7 +766,7 @@ AutomationLine::sync_model_with_view_point (ControlPoint& cp) */ double view_x = cp.get_x(); - double view_y = 1.0 - (cp.get_y() / _height); + double view_y = 1.0 - cp.get_y() / (double)_height; /* if xval has not changed, set it directly from the model to avoid rounding errors */ @@ -1153,16 +1169,48 @@ void AutomationLine::view_to_model_coord_y (double& y) const { if (alist->default_interpolation () != alist->interpolation()) { - //TODO use non-standard scaling. + switch (alist->interpolation()) { + case AutomationList::Linear: + y = y * (_desc.upper - _desc.lower) + _desc.lower; + return; + default: + assert (0); + break; + } } y = _desc.from_interface (y); } +double +AutomationLine::compute_delta (double from, double to) const +{ + return _desc.compute_delta (from, to); +} + +void +AutomationLine::apply_delta (double& val, double delta) const +{ + if (val == 0 && !_desc.is_linear () && delta >= 1.0) { + /* recover from -inf */ + val = 1.0 / _height; + view_to_model_coord_y (val); + return; + } + val = _desc.apply_delta (val, delta); +} + void AutomationLine::model_to_view_coord_y (double& y) const { if (alist->default_interpolation () != alist->interpolation()) { - //TODO use non-standard scaling. + switch (alist->interpolation()) { + case AutomationList::Linear: + y = (y - _desc.lower) / (_desc.upper - _desc.lower); + return; + default: + assert (0); + break; + } } y = _desc.to_interface (y); } @@ -1179,6 +1227,7 @@ void AutomationLine::interpolation_changed (AutomationList::InterpolationStyle style) { if (line_points.size() > 1) { + reset (); line->set_steps(line_points, is_stepped()); } } diff --git a/gtk2_ardour/automation_line.h b/gtk2_ardour/automation_line.h index b004dc6a56..07b8df5148 100644 --- a/gtk2_ardour/automation_line.h +++ b/gtk2_ardour/automation_line.h @@ -86,7 +86,7 @@ public: virtual void start_drag_single (ControlPoint*, double, float); virtual void start_drag_line (uint32_t, uint32_t, float); virtual void start_drag_multiple (std::list, float, XMLNode *); - virtual std::pair drag_motion (double, float, bool, bool with_push, uint32_t& final_index); + virtual std::pair drag_motion (double, float, bool, bool with_push, uint32_t& final_index); virtual void end_drag (bool with_push, uint32_t final_index); ControlPoint* nth (uint32_t); @@ -118,13 +118,16 @@ public: virtual std::string get_verbose_cursor_string (double) const; std::string get_verbose_cursor_relative_string (double, double) const; std::string fraction_to_string (double) const; - std::string fraction_to_relative_string (double, double) const; + std::string delta_to_string (double) const; double string_to_fraction (std::string const &) const; void view_to_model_coord (double& x, double& y) const; void view_to_model_coord_y (double &) const; void model_to_view_coord (double& x, double& y) const; void model_to_view_coord_y (double &) const; + double compute_delta (double from, double to) const; + void apply_delta (double& val, double delta) const; + void set_list(boost::shared_ptr list); boost::shared_ptr the_list() const { return alist; } @@ -190,7 +193,7 @@ protected: public: ContiguousControlPoints (AutomationLine& al); double clamp_dx (double dx); - void move (double dx, double dy); + void move (double dx, double dvalue); void compute_x_bounds (PublicEditor& e); private: AutomationLine& line; diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index c9604b13df..4fed4f072d 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -4785,10 +4785,9 @@ ControlPointDrag::motion (GdkEvent* event, bool first_motion) _editor->begin_reversible_command (_("automation event move")); _point->line().start_drag_single (_point, _fixed_grab_x, initial_fraction); } - pair result; + pair result; result = _point->line().drag_motion (_editor->sample_to_pixel_unrounded (cx_mf.frame), fraction, false, _pushing, _final_index); - - show_verbose_cursor_text (_point->line().get_verbose_cursor_string (result.second)); + show_verbose_cursor_text (_point->line().get_verbose_cursor_relative_string (result.first, result.second)); } void @@ -4905,10 +4904,10 @@ LineDrag::motion (GdkEvent* event, bool first_move) } /* we are ignoring x position for this drag, so we can just pass in anything */ - pair result; + pair result; result = _line->drag_motion (0, fraction, true, false, ignored); - show_verbose_cursor_text (_line->get_verbose_cursor_string (result.second)); + show_verbose_cursor_text (_line->get_verbose_cursor_relative_string (result.first, result.second)); } void @@ -6396,10 +6395,10 @@ AutomationRangeDrag::motion (GdkEvent*, bool first_move) for (list::iterator l = _lines.begin(); l != _lines.end(); ++l) { float const f = y_fraction (l->line, current_pointer_y()); /* we are ignoring x position for this drag, so we can just pass in anything */ - pair result; + pair result; uint32_t ignored; result = l->line->drag_motion (0, f, true, false, ignored); - show_verbose_cursor_text (l->line->get_verbose_cursor_relative_string (l->original_fraction, result.second)); + show_verbose_cursor_text (l->line->get_verbose_cursor_relative_string (result.first, result.second)); } } -- cgit v1.2.3