Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: Automation control point operations #744

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
64 changes: 52 additions & 12 deletions gtk2_ardour/automation_line.cc
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ double
AutomationLine::control_point_box_size ()
{
float uiscale = UIConfiguration::instance().get_ui_scale();
uiscale = std::max<float> (1.f, powf (uiscale, 1.71));
uiscale = std::max<float> (1.f, powf (uiscale, 1.71)) * 2;

if (_height > TimeAxisView::preset_height (HeightLarger)) {
return rint (8.0 * uiscale);
Expand Down Expand Up @@ -394,26 +394,58 @@ AutomationLine::delta_to_string (double delta) const
* @return Corresponding y fraction.
*/
double
AutomationLine::string_to_fraction (string const & s) const
AutomationLine::string_to_fraction (string const & s, double const old_fraction) const
{
double v;
sscanf (s.c_str(), "%lf", &v);

bool is_db = false;
switch (_desc.type) {
case GainAutomation:
case BusSendLevel:
case EnvelopeAutomation:
case TrimAutomation:
case InsertReturnLevel:
if (s == "-inf") { /* translation */
v = 0;
} else {
v = dB_to_coefficient (v);
}
is_db = true;
break;
default:
break;
}
double v;
if ((s.length() > 2) && index("+-*/", s[0]) && (s[1] == '=')) {
v = old_fraction;
view_to_model_coord_y (v);
if (is_db) {
v = accurate_coefficient_to_dB(v);
}
double op_v;
sscanf (s.c_str() + 2, "%lf", &op_v);
if (op_v != 0.f) {
switch (s[0]) {
case '+':
v += op_v;
break;
case '-':
v -= op_v;
break;
case '*':
v *= op_v;
break;
case '/':
if (op_v > 1.0) {
v /= op_v;
}
break;
}
}
} else {
sscanf (s.c_str(), "%lf", &v);
}

if (is_db) {
if (s == "-inf") { /* translation */
v = 0;
} else {
v = dB_to_coefficient (v);
}
}
return model_to_view_coord_y (v);
}

Expand Down Expand Up @@ -926,13 +958,21 @@ AutomationLine::is_first_point (ControlPoint& cp)

// This is copied into AudioRegionGainLine
void
AutomationLine::remove_point (ControlPoint& cp)
AutomationLine::remove_points (std::vector<ControlPoint*> const& cps)
{
trackview.editor().begin_reversible_command (_("remove control point"));
XMLNode &before = alist->get_state();

trackview.editor ().get_selection ().clear_points ();
alist->erase (cp.model());

// Extract models before the ControlPoints iterator mutates on ControlPoint deletion
std::list<Evoral::ControlList::iterator> models;
for (auto const & cp : cps) {
models.push_back(cp->model());
}
for (auto const & model : models) {
alist->erase (model);
}

trackview.editor().session()->add_command(
new MementoCommand<AutomationList> (memento_command_binder (), &before, &alist->get_state()));
Expand Down
4 changes: 2 additions & 2 deletions gtk2_ardour/automation_line.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulDestructible
void get_selectables (Temporal::timepos_t const &, Temporal::timepos_t const &, double, double, std::list<Selectable*>&);
void get_inverted_selectables (Selection&, std::list<Selectable*>& results);

virtual void remove_point (ControlPoint&);
bool control_points_adjacent (double xval, uint32_t& before, uint32_t& after);

/* dragging API */
Expand Down Expand Up @@ -126,7 +125,7 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulDestructible
std::string get_verbose_cursor_relative_string (double, double) const;
std::string fraction_to_string (double) const;
std::string delta_to_string (double) const;
double string_to_fraction (std::string const &) const;
double string_to_fraction (std::string const &, double old_fraction) const;

void view_to_model_coord_y (double &) const;

Expand All @@ -150,6 +149,7 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulDestructible
void set_colors();

void modify_points_y (std::vector<ControlPoint*> const&, double);
virtual void remove_points (std::vector<ControlPoint*> const& cps);

virtual MementoCommandBinder<ARDOUR::AutomationList>* memento_command_binder ();

Expand Down
5 changes: 1 addition & 4 deletions gtk2_ardour/control_point.cc
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ ControlPoint::ControlPoint (AutomationLine& al)
_size = 4.0;

_item = new ArdourCanvas::Rectangle (&_line.canvas_group());
_item->set_fill (true);
_item->set_fill_color (UIConfiguration::instance().color ("control point fill"));
_item->set_fill (false);
_item->set_outline_color (UIConfiguration::instance().color ("control point outline"));
_item->set_data ("control_point", this);
_item->Event.connect (sigc::mem_fun (this, &ControlPoint::event_handler));
Expand Down Expand Up @@ -122,10 +121,8 @@ ControlPoint::set_color ()
{
if (_selected) {
_item->set_outline_color(UIConfiguration::instance().color ("control point selected outline"));;
_item->set_fill_color(UIConfiguration::instance().color ("control point selected fill"));
} else {
_item->set_outline_color(UIConfiguration::instance().color ("control point outline"));
_item->set_fill_color(UIConfiguration::instance().color ("control point fill"));
}
}

Expand Down
6 changes: 4 additions & 2 deletions gtk2_ardour/control_point_dialog.cc
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,11 @@ ControlPointDialog::ControlPointDialog (ControlPoint* p, bool multi)
}

double
ControlPointDialog::get_y_fraction () const
ControlPointDialog::get_y_fraction (ControlPoint* p) const
{
return point_->line().string_to_fraction (value_.get_text ());
double const old_fraction = 1.0 - (p->get_y () / p->line().height ());

return point_->line().string_to_fraction (value_.get_text (), old_fraction);
}

bool
Expand Down
2 changes: 1 addition & 1 deletion gtk2_ardour/control_point_dialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class ControlPointDialog : public ArdourDialog
public:
ControlPointDialog (ControlPoint *, bool multi);

double get_y_fraction () const;
double get_y_fraction (ControlPoint *) const;

bool all_selected_points () const;

Expand Down
5 changes: 2 additions & 3 deletions gtk2_ardour/editor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6812,9 +6812,8 @@ Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* ev

items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
if (!can_remove_control_point (item)) {
items.back().set_sensitive (false);
}
ControlPoint * control_point = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"));
items.back().set_sensitive ((control_point != 0) && can_remove_control_point (*control_point));

_control_point_context_menu.popup (event->button.button, event->button.time);
}
Expand Down
2 changes: 1 addition & 1 deletion gtk2_ardour/editor.h
Original file line number Diff line number Diff line change
Expand Up @@ -1718,7 +1718,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList

void region_view_item_click (AudioRegionView&, GdkEventButton*);

bool can_remove_control_point (ArdourCanvas::Item*);
bool can_remove_control_point (ControlPoint& control_point);
void remove_control_point (ArdourCanvas::Item*);

/* Canvas event handlers */
Expand Down
24 changes: 12 additions & 12 deletions gtk2_ardour/editor_drag.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4813,6 +4813,12 @@ ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
void
ControlPointDrag::motion (GdkEvent* event, bool first_motion)
{
if (first_motion) {
float const initial_fraction = 1.0 - (_fixed_grab_y / _point->line ().height ());
_editor->begin_reversible_command (_("automation event move"));
_point->line ().start_drag_single (_point, _fixed_grab_x, initial_fraction);
}

/* First y */

double dy = current_pointer_y () - last_pointer_y ();
Expand All @@ -4830,31 +4836,25 @@ ControlPointDrag::motion (GdkEvent* event, bool first_motion)

_cumulative_y_drag = cy - _fixed_grab_y;

cy = max (0.0, cy);
cy = min ((double)_point->line ().height (), cy);

// make sure we hit zero when passing through

if ((cy < zero_gain_y && (cy - dy) > zero_gain_y) || (cy > zero_gain_y && (cy - dy) < zero_gain_y)) {
cy = zero_gain_y;
}

float const fraction = 1.0 - (cy / _point->line ().height ());

/* Now x axis */

timecnt_t dt;

if (_point->can_slide ()) {
// alternatively, drag horizontally but use initial vertical position
if (_point->can_slide () && (abs(_drags->current_pointer_x() - grab_x()) > abs(cy - _fixed_grab_y))) {
dt = total_dt (event);
cy = _fixed_grab_y;
}

if (first_motion) {
float const initial_fraction = 1.0 - (_fixed_grab_y / _point->line ().height ());
_editor->begin_reversible_command (_("automation event move"));
_point->line ().start_drag_single (_point, _fixed_grab_x, initial_fraction);
}
cy = max (0.0, cy);
cy = min ((double)_point->line ().height (), cy);

float const fraction = 1.0 - (cy / _point->line ().height ());
pair<float, float> result;
result = _point->line ().drag_motion (dt, fraction, false, _pushing, _final_index);
show_verbose_cursor_text (_point->line ().get_verbose_cursor_relative_string (result.first, result.second));
Expand Down
35 changes: 16 additions & 19 deletions gtk2_ardour/editor_mouse.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2453,19 +2453,12 @@ Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, bool from_aut
}

bool
Editor::can_remove_control_point (ArdourCanvas::Item* item)
Editor::can_remove_control_point (ControlPoint& control_point)
{
ControlPoint* control_point;

if ((control_point = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"))) == 0) {
fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg;
abort(); /*NOTREACHED*/
}

AutomationLine& line = control_point->line ();
AutomationLine& line = control_point.line ();
if (dynamic_cast<AudioRegionGainLine*> (&line)) {
/* we shouldn't remove the first or last gain point in region gain lines */
if (line.is_last_point(*control_point) || line.is_first_point(*control_point)) {
if (line.is_last_point(control_point) || line.is_first_point(control_point)) {
return false;
}
}
Expand All @@ -2476,18 +2469,22 @@ Editor::can_remove_control_point (ArdourCanvas::Item* item)
void
Editor::remove_control_point (ArdourCanvas::Item* item)
{
if (!can_remove_control_point (item)) {
return;
}

ControlPoint* control_point;
ControlPoint* control_point = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"));

if ((control_point = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"))) == 0) {
if (control_point == 0) {
fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg;
abort(); /*NOTREACHED*/
}

control_point->line().remove_point (*control_point);
std::vector<ControlPoint*> cps;

for (auto const& cp : selection->points) {
if ((&cp->line() == &control_point->line ()) && can_remove_control_point (*cp)) {
cps.push_back (cp);
}
}

control_point->line().remove_points (cps);
}

void
Expand Down Expand Up @@ -2517,11 +2514,11 @@ Editor::edit_control_point (ArdourCanvas::Item* item)
}

if (d.all_selected_points ()) {
p->line().modify_points_y (cps, d.get_y_fraction ());
p->line().modify_points_y (cps, d.get_y_fraction (p)); // FIXME: multi edit somehow?
} else {
cps.clear ();
cps.push_back (p);
p->line().modify_points_y (cps, d.get_y_fraction ());
p->line().modify_points_y (cps, d.get_y_fraction (p));
}
}

Expand Down
12 changes: 10 additions & 2 deletions gtk2_ardour/region_gain_line.cc
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ AudioRegionGainLine::start_drag_single (ControlPoint* cp, double x, float fracti

// This is an extended copy from AutomationList
void
AudioRegionGainLine::remove_point (ControlPoint& cp)
AudioRegionGainLine::remove_points (std::vector<ControlPoint*> const& cps)
{
trackview.editor().begin_reversible_command (_("remove control point"));
XMLNode &before = alist->get_state();
Expand All @@ -91,7 +91,15 @@ AudioRegionGainLine::remove_point (ControlPoint& cp)
}

trackview.editor ().get_selection ().clear_points ();
alist->erase (cp.model());

// Extract models before the ControlPoints iterator mutates on ControlPoint deletion
std::list<Evoral::ControlList::iterator> models;
for (auto const & cp : cps) {
models.push_back(cp->model());
}
for (auto const & model : models) {
alist->erase (model);
}

trackview.editor().session()->add_command (new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
trackview.editor().commit_reversible_command ();
Expand Down
2 changes: 1 addition & 1 deletion gtk2_ardour/region_gain_line.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class AudioRegionGainLine : public AutomationLine
void start_drag_single (ControlPoint*, double, float);
void end_drag (bool with_push, uint32_t final_index);

void remove_point (ControlPoint&);
void remove_points (std::vector<ControlPoint*> const& cps);
AudioRegionView& region_view () { return rv; }

private:
Expand Down