diff --git a/gtk2_ardour/ardour.keys.in b/gtk2_ardour/ardour.keys.in index 4cb4aabf0a..f53032e785 100644 --- a/gtk2_ardour/ardour.keys.in +++ b/gtk2_ardour/ardour.keys.in @@ -175,7 +175,7 @@ This mode provides many different operations on both regions and control points, @edit|Editor/alternate-redo| <@PRIMARY@>y|redo @select|Editor/select-all-between-cursors| <@PRIMARY@>u|select all regions enclosed by Range @select|Editor/select-all-within-cursors| u|select all regions touched by Range -@rop|Region/fork-region| <@TERTIARY@>u|unlink midi from other regions +@rop|Region/fork-regions-from-unselected| <@TERTIARY@>u|unlink midi from unselected regions @eep|Region/insert-region-from-source-list| i|insert from region list @sess|Common/addExistingAudioFiles| <@PRIMARY@>i|import audio files @gselect|Common/invert-selection| <@PRIMARY@><@TERTIARY@>i|invert selection diff --git a/gtk2_ardour/ardour.menus.in b/gtk2_ardour/ardour.menus.in index 7c56127275..11256260ed 100644 --- a/gtk2_ardour/ardour.menus.in +++ b/gtk2_ardour/ardour.menus.in @@ -357,7 +357,8 @@ - + + @@ -857,7 +858,8 @@ - + + diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index 7b85928603..cf37bf50a7 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -1368,7 +1368,8 @@ private: void transpose_region (); void transpose_regions (const RegionSelection& rs); void insert_patch_change (bool from_context); - void fork_region (); + void fork_selected_regions (); + void fork_regions_from_unselected (); void do_insert_time (); void insert_time (Temporal::timepos_t const &, Temporal::timecnt_t const &, Editing::InsertTimeOption, bool, bool, bool, bool, bool, bool); diff --git a/gtk2_ardour/editor_actions.cc b/gtk2_ardour/editor_actions.cc index ab7200e876..4a0bb6f0cd 100644 --- a/gtk2_ardour/editor_actions.cc +++ b/gtk2_ardour/editor_actions.cc @@ -1910,7 +1910,8 @@ Editor::register_region_actions () register_region_action (_region_actions, RegionActionTarget (SelectedRegions|EnteredRegions), "remove-overlap", _("Remove Overlap"), sigc::bind(sigc::mem_fun (*this, &Editor::legatize_region), true)); register_region_action (_region_actions, RegionActionTarget (SelectedRegions|EnteredRegions), "insert-patch-change", _("Insert Patch Change..."), sigc::bind (sigc::mem_fun (*this, &Editor::insert_patch_change), false)); register_region_action (_region_actions, RegionActionTarget (SelectedRegions|EnteredRegions), "insert-patch-change-context", _("Insert Patch Change..."), sigc::bind (sigc::mem_fun (*this, &Editor::insert_patch_change), true)); - register_region_action (_region_actions, RegionActionTarget (SelectedRegions|EnteredRegions), "fork-region", _("Unlink from other copies"), sigc::mem_fun (*this, &Editor::fork_region)); + register_region_action (_region_actions, RegionActionTarget (SelectedRegions|EnteredRegions), "fork-selected-regions", _("Unlink all selected regions"), sigc::mem_fun (*this, &Editor::fork_selected_regions)); + register_region_action (_region_actions, RegionActionTarget (SelectedRegions|EnteredRegions), "fork-regions-from-unselected", _("Unlink from unselected"), sigc::mem_fun (*this, &Editor::fork_regions_from_unselected)); register_region_action (_region_actions, RegionActionTarget (SelectedRegions|EnteredRegions), "strip-region-silence", _("Strip Silence..."), sigc::mem_fun (*this, &Editor::strip_region_silence)); register_region_action (_region_actions, RegionActionTarget (SelectedRegions), "set-selection-from-region", _("Set Range Selection"), sigc::mem_fun (*this, &Editor::set_selection_from_region)); diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index 7f564e3297..4e1ff668f2 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -5871,8 +5871,91 @@ Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs) } } +#include "ardour/midi_source.h" // MidiSource::name() + void -Editor::fork_region () +Editor::fork_regions_from_unselected () +{ + /* keep linkage between regions in the selection, but unlink from unselected regions */ + RegionSelection rs = get_regions_from_selection_and_entered (); + + if (rs.empty()) { + return; + } + + CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait); + bool in_command = false; + + gdk_flush (); + + /* find the set of all MidiSources associated with the selected regions */ + std::set > sources_list; + for (const auto& r : rs) { + const MidiRegionView* const mrv = dynamic_cast(r); + if (!mrv) + continue; // not a MIDI region + + sources_list.insert(mrv->midi_region()->midi_source()); + } + + std::set > affected_playlists; + for (auto r : rs) { + const MidiRegionView* const mrv = dynamic_cast(r); + if (mrv && sources_list.find(mrv->midi_region()->midi_source()) != sources_list.end()) { + affected_playlists.insert(mrv->region()->playlist()); + } + } + for (auto p : affected_playlists) { + p->clear_changes (); + p->freeze (); + } + + /* iterate over sources that need to be duplicated */ + for (const auto& ms : sources_list) { + /* duplicate source */ + boost::shared_ptr new_source = _session->create_midi_source_for_session (ms->name()); + for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) { + RegionSelection::iterator tmp = r; + ++tmp; + + const MidiRegionView* const mrv = dynamic_cast(*r); + + if (!mrv) { + r = tmp; + continue; + } + if (mrv->midi_region()->midi_source() != ms) { + r = tmp; + continue; + } + + try { + if (!in_command) { + begin_reversible_command (_("Unlink from unselected")); + in_command = true; + } + boost::shared_ptr playlist = mrv->region()->playlist(); + boost::shared_ptr new_region = mrv->midi_region()->clone (new_source); + new_region->set_name (mrv->region()->name() + "-unlinked-region"); + playlist->replace_region (mrv->region(), new_region, mrv->region()->position()); + } catch (...) { + error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg; + } + r = tmp; + } + } + if (in_command) { + for (auto p : affected_playlists) { + p->thaw (); + _session->add_command(new StatefulDiffCommand (p)); + } + + commit_reversible_command (); + } +} + +void +Editor::fork_selected_regions () { RegionSelection rs = get_regions_from_selection_and_entered (); diff --git a/gtk2_ardour/editor_selection.cc b/gtk2_ardour/editor_selection.cc index 4718515405..c126cf98e2 100644 --- a/gtk2_ardour/editor_selection.cc +++ b/gtk2_ardour/editor_selection.cc @@ -1539,7 +1539,8 @@ Editor::sensitize_the_right_region_actions (bool because_canvas_crossing) _region_actions->get_action("legatize-region")->set_sensitive (false); _region_actions->get_action("remove-overlap")->set_sensitive (false); _region_actions->get_action("transform-region")->set_sensitive (false); - _region_actions->get_action("fork-region")->set_sensitive (false); + _region_actions->get_action("fork-selected-regions")->set_sensitive (false); + _region_actions->get_action("fork-regions-from-unselected")->set_sensitive (false); _region_actions->get_action("insert-patch-change-context")->set_sensitive (false); _region_actions->get_action("insert-patch-change")->set_sensitive (false); _region_actions->get_action("transpose-region")->set_sensitive (false);