basic implementation of Live-style kbd-driven automation editing

This commit is contained in:
Paul Davis
2025-06-17 14:00:54 -06:00
parent fc692f5680
commit c6a49fdd50
7 changed files with 189 additions and 1 deletions

View File

@@ -0,0 +1,9 @@
<Bindings name="Automation">
<Press>
<Binding key="Return" action="Automation/create-point"/>
<Binding key="Right" action="Automation/move-points-later"/>
<Binding key="Left" action="Automation/move-points-earlier"/>
<Binding key="Up" action="Automation/raise-points"/>
<Binding key="Down" action="Automation/lower-points"/>
</Press>
</Bindings>

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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<Gtk::ActionGroup> _midi_actions;
Glib::RefPtr<Gtk::ActionGroup> _common_actions;
Glib::RefPtr<Gtk::ActionGroup> _automation_actions;
Glib::RefPtr<Gtk::ActionGroup> editor_actions;
Glib::RefPtr<Gtk::ActionGroup> snap_actions;
Glib::RefPtr<Gtk::ActionGroup> 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 () {};
};

View File

@@ -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;

View File

@@ -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<AutomationTimeAxisView*> (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<AutomationTimeAxisView*> (entered_track);
if (!atv) {
return;
}
begin_reversible_command (_("automation event lower"));
add_command (new MementoCommand<AutomationList> (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<AutomationList>(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<AutomationTimeAxisView*> (entered_track);
if (!atv) {
return;
}
begin_reversible_command (_("automation event raise"));
add_command (new MementoCommand<AutomationList> (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<AutomationList>(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<AutomationTimeAxisView*> (entered_track);
if (!atv) {
return;
}
begin_reversible_command (_("automation points move later"));
add_command (new MementoCommand<AutomationList> (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<AutomationList>(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<AutomationTimeAxisView*> (entered_track);
if (!atv) {
return;
}
begin_reversible_command (_("automation points move earlier"));
add_command (new MementoCommand<AutomationList> (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<AutomationList>(atv->line()->memento_command_binder (), 0, &atv->line()->the_list()->get_state()));
commit_reversible_command ();
}

View File

@@ -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']