diff --git a/gtk2_ardour/automation.bindings b/gtk2_ardour/automation.bindings
new file mode 100644
index 0000000000..dd3139a40c
--- /dev/null
+++ b/gtk2_ardour/automation.bindings
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/gtk2_ardour/automation_time_axis.cc b/gtk2_ardour/automation_time_axis.cc
index 3cdbea638b..d8d74d367d 100644
--- a/gtk2_ardour/automation_time_axis.cc
+++ b/gtk2_ardour/automation_time_axis.cc
@@ -971,6 +971,7 @@ AutomationTimeAxisView::entered()
if (_line) {
_line->track_entered();
}
+ _editor.enable_automation_bindings ();
}
void
@@ -979,6 +980,8 @@ AutomationTimeAxisView::exited ()
if (_line) {
_line->track_exited();
}
+
+ _editor.enable_automation_bindings ();
}
void
diff --git a/gtk2_ardour/editing_context.cc b/gtk2_ardour/editing_context.cc
index 839f39f758..f7cd000d08 100644
--- a/gtk2_ardour/editing_context.cc
+++ b/gtk2_ardour/editing_context.cc
@@ -303,6 +303,32 @@ EditingContext::set_selected_midi_region_view (MidiRegionView& mrv)
get_selection().set (&mrv);
}
+void
+EditingContext::register_automation_actions (Bindings* automation_bindings, std::string const & prefix)
+{
+ _automation_actions = ActionManager::create_action_group (automation_bindings, prefix + X_("Automation"));
+
+ reg_sens (_automation_actions, "create-point", _("Create Automation Point"), sigc::mem_fun (*this, &EditingContext::automation_create_point_at_edit_point));
+ reg_sens (_automation_actions, "move-points-later", _("Create Automation P (at Playhead)"), sigc::mem_fun (*this, &EditingContext::automation_move_points_later));
+ reg_sens (_automation_actions, "move-points-earlier", _("Create Automation Point (at Playhead)"), sigc::mem_fun (*this, &EditingContext::automation_move_points_earlier));
+ reg_sens (_automation_actions, "raise-points", _("Create Automation Point (at Playhead)"), sigc::mem_fun (*this, &EditingContext::automation_raise_points));
+ reg_sens (_automation_actions, "lower-points", _("Create Automation Point (at Playhead)"), sigc::mem_fun (*this, &EditingContext::automation_lower_points));
+
+ ActionManager::set_sensitive (_automation_actions, false);
+}
+
+void
+EditingContext::enable_automation_bindings ()
+{
+ ActionManager::set_sensitive (_automation_actions, true);
+}
+
+void
+EditingContext::disable_automation_bindings ()
+{
+ ActionManager::set_sensitive (_automation_actions, false);
+}
+
void
EditingContext::register_common_actions (Bindings* common_bindings, std::string const & prefix)
{
@@ -3254,10 +3280,12 @@ EditingContext::load_shared_bindings ()
{
Bindings* m = Bindings::get_bindings (X_("MIDI"));
Bindings* b = Bindings::get_bindings (X_("Editing"));
+ Bindings* a = Bindings::get_bindings (X_("Automation"));
if (need_shared_actions) {
register_midi_actions (m, string());
register_common_actions (b, string());
+ register_automation_actions (a, string());
need_shared_actions = false;
}
@@ -3279,8 +3307,13 @@ EditingContext::load_shared_bindings ()
register_common_actions (shared_bindings, _name);
shared_bindings->associate ();
+ Bindings* automation_bindings = new Bindings (_name, *a);
+ register_automation_actions (automation_bindings, _name);
+ automation_bindings->associate ();
+
/* Attach bindings to the canvas for this editing context */
+ bindings.push_back (automation_bindings);
bindings.push_back (midi_bindings);
bindings.push_back (shared_bindings);
}
diff --git a/gtk2_ardour/editing_context.h b/gtk2_ardour/editing_context.h
index f9d16a7df0..6a112e1463 100644
--- a/gtk2_ardour/editing_context.h
+++ b/gtk2_ardour/editing_context.h
@@ -421,6 +421,7 @@ class EditingContext : public ARDOUR::SessionHandlePtr, public AxisViewProvider,
static bool need_shared_actions;
void register_midi_actions (Gtkmm2ext::Bindings*, std::string const &);
void register_common_actions (Gtkmm2ext::Bindings*, std::string const &);
+ void register_automation_actions (Gtkmm2ext::Bindings*, std::string const &);
ArdourCanvas::Rectangle* rubberband_rect;
@@ -497,12 +498,16 @@ class EditingContext : public ARDOUR::SessionHandlePtr, public AxisViewProvider,
void center_screen (samplepos_t);
void reset_x_origin_to_follow_playhead ();
+ void enable_automation_bindings ();
+ void disable_automation_bindings ();
+
protected:
std::string _name;
bool within_track_canvas;
Glib::RefPtr _midi_actions;
Glib::RefPtr _common_actions;
+ Glib::RefPtr _automation_actions;
Glib::RefPtr editor_actions;
Glib::RefPtr snap_actions;
Glib::RefPtr length_actions;
@@ -818,4 +823,9 @@ class EditingContext : public ARDOUR::SessionHandlePtr, public AxisViewProvider,
void center_screen_internal (samplepos_t, float);
+ virtual void automation_create_point_at_edit_point() {}
+ virtual void automation_raise_points () {}
+ virtual void automation_lower_points () {};
+ virtual void automation_move_points_later () {};
+ virtual void automation_move_points_earlier () {};
};
diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h
index 639a5b4ace..80c3a205ef 100644
--- a/gtk2_ardour/editor.h
+++ b/gtk2_ardour/editor.h
@@ -1603,6 +1603,11 @@ private:
protected:
void _commit_tempo_map_edit (Temporal::TempoMap::WritableSharedPtr&, bool with_update = false);
+ void automation_create_point_at_edit_point();
+ void automation_raise_points ();
+ void automation_lower_points ();
+ void automation_move_points_later ();
+ void automation_move_points_earlier ();
private:
friend class DragManager;
diff --git a/gtk2_ardour/editor_actions.cc b/gtk2_ardour/editor_actions.cc
index 3b2c68b3d6..98a40bfac2 100644
--- a/gtk2_ardour/editor_actions.cc
+++ b/gtk2_ardour/editor_actions.cc
@@ -39,6 +39,8 @@
#include "ardour/session.h"
#include "ardour/types.h"
+#include "temporal/bbt_time.h"
+
#include "canvas/canvas.h"
#include "canvas/pixbuf.h"
@@ -46,6 +48,7 @@
#include "actions.h"
#include "ardour_ui.h"
+#include "control_point.h"
#include "editing.h"
#include "editor.h"
#include "gui_thread.h"
@@ -1333,3 +1336,128 @@ Editor::register_region_actions ()
sensitize_all_region_actions (false);
}
+void
+Editor::automation_create_point_at_edit_point ()
+{
+ AutomationTimeAxisView* atv = dynamic_cast (entered_track);
+ if (!atv) {
+ return;
+ }
+
+ timepos_t where (get_preferred_edit_position());;
+ GdkEvent event;
+
+ event.type = GDK_KEY_PRESS;
+ event.button.button = 1;
+ event.button.state = 0;
+
+ atv->line()->add (atv->control(), &event, where, atv->line()->the_list()->eval (where), false);
+}
+
+void
+Editor::automation_lower_points ()
+{
+ PointSelection& points (selection->points);
+
+ if (points.empty()) {
+ return;
+ }
+
+ AutomationTimeAxisView* atv = dynamic_cast (entered_track);
+
+ if (!atv) {
+ return;
+ }
+
+ begin_reversible_command (_("automation event lower"));
+ add_command (new MementoCommand (atv->line()->memento_command_binder(), &atv->line()->the_list()->get_state(), 0));
+ atv->line()->the_list()->freeze ();
+ for (auto & p : points) {
+ atv->line()->the_list()->modify (p->model(), (*p->model())->when, max (0.0, (*p->model())->value - 0.1));
+ }
+ atv->line()->the_list()->thaw ();
+ add_command (new MementoCommand(atv->line()->memento_command_binder (), 0, &atv->line()->the_list()->get_state()));
+ commit_reversible_command ();
+}
+
+void
+Editor::automation_raise_points ()
+{
+ PointSelection& points (selection->points);
+
+ if (points.empty()) {
+ return;
+ }
+
+ AutomationTimeAxisView* atv = dynamic_cast (entered_track);
+
+ if (!atv) {
+ return;
+ }
+
+ begin_reversible_command (_("automation event raise"));
+ add_command (new MementoCommand (atv->line()->memento_command_binder(), &atv->line()->the_list()->get_state(), 0));
+ atv->line()->the_list()->freeze ();
+ for (auto & p : points) {
+ atv->line()->the_list()->modify (p->model(), (*p->model())->when, min (1.0, (*p->model())->value + 0.1));
+ }
+ atv->line()->the_list()->thaw ();
+ add_command (new MementoCommand(atv->line()->memento_command_binder (), 0, &atv->line()->the_list()->get_state()));
+ commit_reversible_command ();
+}
+
+void
+Editor::automation_move_points_later ()
+{
+ PointSelection& points (selection->points);
+
+ if (points.empty()) {
+ return;
+ }
+
+ AutomationTimeAxisView* atv = dynamic_cast (entered_track);
+
+ if (!atv) {
+ return;
+ }
+
+ begin_reversible_command (_("automation points move later"));
+ add_command (new MementoCommand (atv->line()->memento_command_binder(), &atv->line()->the_list()->get_state(), 0));
+ atv->line()->the_list()->freeze ();
+ for (auto & p : points) {
+ timepos_t model_time ((*p->model())->when);
+ model_time += Temporal::BBT_Offset (0, 1, 0);
+ atv->line()->the_list()->modify (p->model(), model_time, (*p->model())->value);
+ }
+ atv->line()->the_list()->thaw ();
+ add_command (new MementoCommand(atv->line()->memento_command_binder (), 0, &atv->line()->the_list()->get_state()));
+ commit_reversible_command ();
+}
+
+void
+Editor::automation_move_points_earlier ()
+{
+ PointSelection& points (selection->points);
+
+ if (points.empty()) {
+ return;
+ }
+
+ AutomationTimeAxisView* atv = dynamic_cast (entered_track);
+
+ if (!atv) {
+ return;
+ }
+
+ begin_reversible_command (_("automation points move earlier"));
+ add_command (new MementoCommand (atv->line()->memento_command_binder(), &atv->line()->the_list()->get_state(), 0));
+ atv->line()->the_list()->freeze ();
+ for (auto & p : points) {
+ timepos_t model_time ((*p->model())->when);
+ model_time = model_time.earlier (Temporal::BBT_Offset (0, 1, 0));
+ atv->line()->the_list()->modify (p->model(), model_time, (*p->model())->value);
+ }
+ atv->line()->the_list()->thaw ();
+ add_command (new MementoCommand(atv->line()->memento_command_binder (), 0, &atv->line()->the_list()->get_state()));
+ commit_reversible_command ();
+}
diff --git a/gtk2_ardour/wscript b/gtk2_ardour/wscript
index 6e5d319c11..cc71e41da4 100644
--- a/gtk2_ardour/wscript
+++ b/gtk2_ardour/wscript
@@ -945,7 +945,7 @@ def build(bld):
for b in [ 'ardour' ] :
obj = bld(
target = b + '.keys',
- source = [ b + '.keys.in', 'mixer.bindings', 'processor_box.bindings', 'step_editing.bindings', 'monitor.bindings', 'trigger.bindings', 'regionfx_box.bindings' ],
+ source = [ b + '.keys.in', 'mixer.bindings', 'processor_box.bindings', 'step_editing.bindings', 'monitor.bindings', 'trigger.bindings', 'regionfx_box.bindings', 'automation.bindings' ],
rule = a_rule
)
obj.install_path = bld.env['CONFDIR']