Log-scale/relative automation point dragging
This commit is contained in:
parent
1db9ce4c90
commit
fd36355e2c
|
@ -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);
|
||||
if (!get_uses_gain_mapping () && _desc.logarithmic) {
|
||||
return "x " + ARDOUR::value_as_string (_desc, delta);
|
||||
} else {
|
||||
return "\u0394 " + ARDOUR::value_as_string (_desc, delta);
|
||||
}
|
||||
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;
|
||||
}
|
||||
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<ControlPoint*>::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<double, float>
|
||||
pair<float, float>
|
||||
AutomationLine::drag_motion (double const x, float fraction, bool ignore_x, bool with_push, uint32_t& final_index)
|
||||
{
|
||||
if (_drag_points.empty()) {
|
||||
return pair<double,float> (x,fraction);
|
||||
return pair<double,float> (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<ControlPoint*>::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<CCP>::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<double, float> (_drag_x + dx, result_frac);
|
||||
return pair<float, float> (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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<ControlPoint*>, float, XMLNode *);
|
||||
virtual std::pair<double, float> drag_motion (double, float, bool, bool with_push, uint32_t& final_index);
|
||||
virtual std::pair<float, float> 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<ARDOUR::AutomationList> list);
|
||||
boost::shared_ptr<ARDOUR::AutomationList> 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;
|
||||
|
|
|
@ -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<double, float> result;
|
||||
pair<float, float> 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<double, float> result;
|
||||
pair<float, float> 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<Line>::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<double, float> result;
|
||||
pair<float, float> 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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user