View Issue Details

IDProjectCategoryView StatusLast Update
0005517ardourfeaturespublic2020-04-19 20:16
Reportercolinf Assigned Topaul  
PrioritynormalSeverityminorReproducibilityN/A
Status closedResolutionfixed 
Summary0005517: New intermediate 'Regions in active edit groups are edited together' setting
DescriptionI think that a setting for 'Regions in active edit groups are edited together' that considers regions equivalent when the bounds of one are either equal to or lie within the bounds of another would be useful.

This would fit my workflow editing multi-track live recordings very well, where in general, all tracks are edited together, but the timing of the edits in one or two tracks occasionally has to be adjusted. Nether of the two existing region equivalency modes does exactly what I want here: 'only when identical' of course stops working as soon as any regions are edited slightly differently within the group, and 'whenever they overlap' selects regions on both sides of the edit.
Additional InformationASCII-art examples to clarify how I think this new mode should work:

|---a---|
|--b--|

|---a---|
 |--b--|

|---a---|
  |--b--|
 - are equivalent.

|---a---|
   |--b--|

 |---a---|
|--b--|
 - are not.
TagsNo tags attached.

Activities

paul

2013-06-10 16:10

administrator   ~0014963

I like it.

colinf

2013-06-10 17:29

updater   ~0014973

I started to hack this together, and it seemed like a doddle, but I got totally stumped thinking up a name for the function. The standard 'identical' equivalence mode function is Region::equivalent() and the 'overlap' mode is Region::overlap_equivalent(), but what to call this one?

Also, I'm not sure whether it's a good idea to change the use_overlap_equivalency config setting from a bool to an int/enum for this third type, or to introduce a new config variable, or just change the overlap equivalency to work like this. Who uses overlap equivalency, anyway?

colinf

2014-09-19 18:36

updater   ~0015889

I've implemented this now (I have it in a local branch), since I wanted it (especially in the face of 0004834).

I made a new enumerated "region-equivalence" config setting, and got rid of the old "use-overlap-equivalency" boolean one, so anyone who had enabled the old one would lose their setting if the patch were to be merged as-is. I hope that's OK - I'd think that anyone who wants this setting knows they want it.

There's also a discussion to be had about what the default should be - obviously I'd like it to be my new mode, but I guess there's a consistency argument in favour of making it be the 'exact' equivalence mode as at present.

colinf

2018-09-13 13:25

updater  

enclosed-equivalent-regions.patch (8,874 bytes)   
commit ff2cfb306a0d46e267d5102a456fa01b086a3f4d
Author: Colin Fletcher <colin.m.fletcher@googlemail.com>
Date:   Sun Dec 28 16:03:56 2014 +0000

    Implement new 'Enclosed' region equivalence mode.

diff --git a/gtk2_ardour/rc_option_editor.cc b/gtk2_ardour/rc_option_editor.cc
index 421e4c56c..2f5f12d3a 100644
--- a/gtk2_ardour/rc_option_editor.cc
+++ b/gtk2_ardour/rc_option_editor.cc
@@ -1728,7 +1728,6 @@ RCOptionEditor::RCOptionEditor ()
 
         uint32_t hwcpus = hardware_concurrency ();
 	BoolOption* bo;
-	BoolComboOption* bco;
 
         if (hwcpus > 1) {
                 add_option (_("Misc"), new OptionEditorHeading (_("DSP CPU Utilization")));
@@ -2173,16 +2172,18 @@ if (!Profile->get_mixbus()) {
 	add_option (_("Editor"), fadeshape);
 
 
-	bco = new BoolComboOption (
-		     "use-overlap-equivalency",
+	ComboOption<RegionEquivalence> *eqv = new ComboOption<RegionEquivalence> (
+		     "region-equivalence",
 		     _("Regions in active edit groups are edited together"),
-		     _("whenever they overlap in time"),
-		     _("only if they have identical length, position and origin"),
-		     sigc::mem_fun (*_rc_config, &RCConfiguration::get_use_overlap_equivalency),
-		     sigc::mem_fun (*_rc_config, &RCConfiguration::set_use_overlap_equivalency)
+		     sigc::mem_fun (*_rc_config, &RCConfiguration::get_region_equivalence),
+		     sigc::mem_fun (*_rc_config, &RCConfiguration::set_region_equivalence)
 		     );
 
-	add_option (_("Editor"), bco);
+	eqv->add (Overlap, _("whenever they overlap in time"));
+	eqv->add (Enclosed, _("if either encloses the other"));
+	eqv->add (Exact, _("only if they have identical length, position and origin"));
+
+	add_option (_("Editor"), eqv);
 
 	ComboOption<LayerModel>* lm = new ComboOption<LayerModel> (
 		"layer-model",
diff --git a/libs/ardour/ardour/rc_configuration_vars.h b/libs/ardour/ardour/rc_configuration_vars.h
index 39f770969..c48d9ee13 100644
--- a/libs/ardour/ardour/rc_configuration_vars.h
+++ b/libs/ardour/ardour/rc_configuration_vars.h
@@ -206,7 +206,7 @@ CONFIG_VARIABLE (bool, verify_remove_last_capture, "verify-remove-last-capture",
 CONFIG_VARIABLE (bool, save_history, "save-history", true)
 CONFIG_VARIABLE (int32_t, saved_history_depth, "save-history-depth", 20)
 CONFIG_VARIABLE (int32_t, history_depth, "history-depth", 20)
-CONFIG_VARIABLE (bool, use_overlap_equivalency, "use-overlap-equivalency", false)
+CONFIG_VARIABLE (RegionEquivalence, region_equivalence, "region-equivalence", Enclosed)
 CONFIG_VARIABLE (bool, periodic_safety_backups, "periodic-safety-backups", true)
 CONFIG_VARIABLE (uint32_t, periodic_safety_backup_interval, "periodic-safety-backup-interval", 120)
 CONFIG_VARIABLE (float, automation_interval_msecs, "automation-interval-msecs", 30)
diff --git a/libs/ardour/ardour/region.h b/libs/ardour/ardour/region.h
index a8a1475fb..3a86bd2e3 100644
--- a/libs/ardour/ardour/region.h
+++ b/libs/ardour/ardour/region.h
@@ -196,9 +196,10 @@ class LIBARDOUR_API Region
 		return Evoral::coverage (first_frame(), last_frame(), start, end);
 	}
 
-	bool equivalent (boost::shared_ptr<const Region>) const;
+	bool exact_equivalent (boost::shared_ptr<const Region>) const;
 	bool size_equivalent (boost::shared_ptr<const Region>) const;
 	bool overlap_equivalent (boost::shared_ptr<const Region>) const;
+	bool enclosed_equivalent (boost::shared_ptr<const Region>) const;
 	bool region_list_equivalent (boost::shared_ptr<const Region>) const;
 	bool source_equivalent (boost::shared_ptr<const Region>) const;
 	bool any_source_equivalent (boost::shared_ptr<const Region>) const;
diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h
index 97dba38d7..45df5e7c1 100644
--- a/libs/ardour/ardour/types.h
+++ b/libs/ardour/ardour/types.h
@@ -568,6 +568,12 @@ namespace ARDOUR {
 	class Bundle;
 	typedef std::vector<boost::shared_ptr<Bundle> > BundleList;
 
+	enum RegionEquivalence {
+		Exact,
+		Enclosed,
+		Overlap
+	};
+
 	enum WaveformScale {
 		Linear,
 		Logarithmic
@@ -699,6 +705,7 @@ std::istream& operator>>(std::istream& o, ARDOUR::ShuttleBehaviour& sf);
 std::istream& operator>>(std::istream& o, ARDOUR::ShuttleUnits& sf);
 std::istream& operator>>(std::istream& o, Timecode::TimecodeFormat& sf);
 std::istream& operator>>(std::istream& o, ARDOUR::DenormalModel& sf);
+std::istream& operator>>(std::istream& o, ARDOUR::RegionEquivalence& sf);
 std::istream& operator>>(std::istream& o, ARDOUR::PositionLockStyle& sf);
 std::istream& operator>>(std::istream& o, ARDOUR::FadeShape& sf);
 std::istream& operator>>(std::istream& o, ARDOUR::RegionSelectionAfterSplit& sf);
@@ -723,6 +730,7 @@ std::ostream& operator<<(std::ostream& o, const ARDOUR::ShuttleBehaviour& sf);
 std::ostream& operator<<(std::ostream& o, const ARDOUR::ShuttleUnits& sf);
 std::ostream& operator<<(std::ostream& o, const Timecode::TimecodeFormat& sf);
 std::ostream& operator<<(std::ostream& o, const ARDOUR::DenormalModel& sf);
+std::ostream& operator<<(std::ostream& o, const ARDOUR::RegionEquivalence& sf);
 std::ostream& operator<<(std::ostream& o, const ARDOUR::PositionLockStyle& sf);
 std::ostream& operator<<(std::ostream& o, const ARDOUR::FadeShape& sf);
 std::ostream& operator<<(std::ostream& o, const ARDOUR::RegionSelectionAfterSplit& sf);
diff --git a/libs/ardour/enums.cc b/libs/ardour/enums.cc
index fa8378072..8b39a7df1 100644
--- a/libs/ardour/enums.cc
+++ b/libs/ardour/enums.cc
@@ -124,6 +124,7 @@ setup_enum_writer ()
 	MidiModel::NoteDiffCommand::Property _MidiModel_NoteDiffCommand_Property;
 	MidiModel::SysExDiffCommand::Property _MidiModel_SysExDiffCommand_Property;
 	MidiModel::PatchChangeDiffCommand::Property _MidiModel_PatchChangeDiffCommand_Property;
+	RegionEquivalence _RegionEquivalence;
 	WaveformScale _WaveformScale;
 	WaveformShape _WaveformShape;
 	Session::PostTransportWork _Session_PostTransportWork;
@@ -664,6 +665,11 @@ setup_enum_writer ()
 	REGISTER_CLASS_ENUM (MidiModel::PatchChangeDiffCommand, Bank);
 	REGISTER (_MidiModel_PatchChangeDiffCommand_Property);
 
+	REGISTER_ENUM (Exact);
+	REGISTER_ENUM (Enclosed);
+	REGISTER_ENUM (Overlap);
+	REGISTER(_RegionEquivalence);
+
 	REGISTER_ENUM(Linear);
 	REGISTER_ENUM(Logarithmic);
 	REGISTER(_WaveformScale);
@@ -957,6 +963,20 @@ std::ostream& operator<<(std::ostream& o, const DenormalModel& var)
 	std::string s = enum_2_string (var);
 	return o << s;
 }
+std::istream& operator>>(std::istream& o, RegionEquivalence& var)
+{
+	std::string s;
+	o >> s;
+	var = (RegionEquivalence) string_2_enum (s, var);
+	return o;
+}
+
+std::ostream& operator<<(std::ostream& o, const RegionEquivalence& var)
+{
+	std::string s = enum_2_string (var);
+	return o << s;
+}
+
 std::istream& operator>>(std::istream& o, WaveformScale& var)
 {
 	std::string s;
diff --git a/libs/ardour/playlist.cc b/libs/ardour/playlist.cc
index 41681a73f..0a6dc48c7 100644
--- a/libs/ardour/playlist.cc
+++ b/libs/ardour/playlist.cc
@@ -830,18 +830,30 @@ Playlist::flush_notifications (bool from_undo)
  void
  Playlist::get_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
  {
-	 if (Config->get_use_overlap_equivalency()) {
-		 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
-			 if ((*i)->overlap_equivalent (other)) {
-				 results.push_back (*i);
+	 switch (Config->get_region_equivalence()) {
+		 case Exact:
+			 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
+				 if ((*i)->exact_equivalent (other)) {
+					 results.push_back (*i);
+				 }
 			 }
-		 }
-	 } else {
-		 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
-			 if ((*i)->equivalent (other)) {
-				 results.push_back (*i);
+			 break;
+
+		 case Enclosed:
+			 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
+				 if ((*i)->enclosed_equivalent (other)) {
+					 results.push_back (*i);
+				 }
 			 }
-		 }
+			 break;
+
+		 case Overlap:
+			 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
+				 if ((*i)->overlap_equivalent (other)) {
+					 results.push_back (*i);
+				 }
+			 }
+			 break;
 	 }
  }
 
diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc
index bd99403cb..9745d3ac2 100644
--- a/libs/ardour/region.cc
+++ b/libs/ardour/region.cc
@@ -1380,7 +1380,14 @@ Region::overlap_equivalent (boost::shared_ptr<const Region> other) const
 }
 
 bool
-Region::equivalent (boost::shared_ptr<const Region> other) const
+Region::enclosed_equivalent (boost::shared_ptr<const Region> other) const
+{
+	return (first_frame() >= other->first_frame() && last_frame() <= other->last_frame()) ||
+	       (first_frame() <= other->first_frame() && last_frame() >= other->last_frame()) ;
+}
+
+bool
+Region::exact_equivalent (boost::shared_ptr<const Region> other) const
 {
 	return _start == other->_start &&
 		_position == other->_position &&

colinf

2018-09-13 16:59

updater  

enclosed-equivalent-regions-5.12.patch (7,609 bytes)   
commit 019a90dbe28d0be8ad94ad8ab44734151744c89a
Author: Colin Fletcher <colin.m.fletcher@googlemail.com>
Date:   Thu Sep 13 16:05:23 2018 +0100

    Implement new 'Enclosed' region equivalence mode.
    
    Now applies to master

diff --git a/gtk2_ardour/rc_option_editor.cc b/gtk2_ardour/rc_option_editor.cc
index e086363a2..8cca0227f 100644
--- a/gtk2_ardour/rc_option_editor.cc
+++ b/gtk2_ardour/rc_option_editor.cc
@@ -2138,7 +2138,6 @@ RCOptionEditor::RCOptionEditor ()
 
 	uint32_t hwcpus = hardware_concurrency ();
 	BoolOption* bo;
-	BoolComboOption* bco;
 
 	if (hwcpus > 1) {
 		add_option (_("General"), new OptionEditorHeading (_("DSP CPU Utilization")));
@@ -2444,16 +2443,18 @@ RCOptionEditor::RCOptionEditor ()
 
 	add_option (_("Editor"), fadeshape);
 
-	bco = new BoolComboOption (
-		     "use-overlap-equivalency",
-		     _("Regions in edit groups are edited together"),
-		     _("whenever they overlap in time"),
-		     _("only if they have identical length and position"),
-		     sigc::mem_fun (*_rc_config, &RCConfiguration::get_use_overlap_equivalency),
-		     sigc::mem_fun (*_rc_config, &RCConfiguration::set_use_overlap_equivalency)
+	ComboOption<RegionEquivalence> *eqv = new ComboOption<RegionEquivalence> (
+		     "region-equivalence",
+		     _("Regions in active edit groups are edited together"),
+		     sigc::mem_fun (*_rc_config, &RCConfiguration::get_region_equivalence),
+		     sigc::mem_fun (*_rc_config, &RCConfiguration::set_region_equivalence)
 		     );
 
-	add_option (_("Editor"), bco);
+	eqv->add (Overlap, _("whenever they overlap in time"));
+	eqv->add (Enclosed, _("if either encloses the other"));
+	eqv->add (Exact, _("only if they have identical length, position and origin"));
+
+	add_option (_("Editor"), eqv);
 
 	ComboOption<LayerModel>* lm = new ComboOption<LayerModel> (
 		"layer-model",
diff --git a/libs/ardour/ardour/rc_configuration_vars.h b/libs/ardour/ardour/rc_configuration_vars.h
index 681c51a32..b7ee95e9e 100644
--- a/libs/ardour/ardour/rc_configuration_vars.h
+++ b/libs/ardour/ardour/rc_configuration_vars.h
@@ -212,7 +212,7 @@ CONFIG_VARIABLE (bool, verify_remove_last_capture, "verify-remove-last-capture",
 CONFIG_VARIABLE (bool, save_history, "save-history", true)
 CONFIG_VARIABLE (int32_t, saved_history_depth, "save-history-depth", 20)
 CONFIG_VARIABLE (int32_t, history_depth, "history-depth", 20)
-CONFIG_VARIABLE (bool, use_overlap_equivalency, "use-overlap-equivalency", false)
+CONFIG_VARIABLE (RegionEquivalence, region_equivalence, "region-equivalence", Enclosed)
 CONFIG_VARIABLE (bool, periodic_safety_backups, "periodic-safety-backups", true)
 CONFIG_VARIABLE (uint32_t, periodic_safety_backup_interval, "periodic-safety-backup-interval", 120)
 CONFIG_VARIABLE (float, automation_interval_msecs, "automation-interval-msecs", 30)
diff --git a/libs/ardour/ardour/region.h b/libs/ardour/ardour/region.h
index b536aa16a..5d0413beb 100644
--- a/libs/ardour/ardour/region.h
+++ b/libs/ardour/ardour/region.h
@@ -201,9 +201,10 @@ public:
 		return Evoral::coverage (first_sample(), last_sample(), start, end);
 	}
 
-	bool equivalent (boost::shared_ptr<const Region>) const;
+	bool exact_equivalent (boost::shared_ptr<const Region>) const;
 	bool size_equivalent (boost::shared_ptr<const Region>) const;
 	bool overlap_equivalent (boost::shared_ptr<const Region>) const;
+	bool enclosed_equivalent (boost::shared_ptr<const Region>) const;
 	bool region_list_equivalent (boost::shared_ptr<const Region>) const;
 	bool source_equivalent (boost::shared_ptr<const Region>) const;
 	bool any_source_equivalent (boost::shared_ptr<const Region>) const;
diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h
index f835a5ff0..366e30318 100644
--- a/libs/ardour/ardour/types.h
+++ b/libs/ardour/ardour/types.h
@@ -605,6 +605,12 @@ namespace ARDOUR {
 	class Bundle;
 	typedef std::vector<boost::shared_ptr<Bundle> > BundleList;
 
+	enum RegionEquivalence {
+		Exact,
+		Enclosed,
+		Overlap
+	};
+
 	enum WaveformScale {
 		Linear,
 		Logarithmic
diff --git a/libs/ardour/ardour/types_convert.h b/libs/ardour/ardour/types_convert.h
index 831761498..dcdc49fae 100644
--- a/libs/ardour/ardour/types_convert.h
+++ b/libs/ardour/ardour/types_convert.h
@@ -68,6 +68,7 @@ DEFINE_ENUM_CONVERT(ARDOUR::PluginType)
 DEFINE_ENUM_CONVERT(ARDOUR::AlignStyle)
 DEFINE_ENUM_CONVERT(ARDOUR::AlignChoice)
 
+DEFINE_ENUM_CONVERT(ARDOUR::RegionEquivalence)
 DEFINE_ENUM_CONVERT(ARDOUR::WaveformScale)
 DEFINE_ENUM_CONVERT(ARDOUR::WaveformShape)
 DEFINE_ENUM_CONVERT(ARDOUR::VUMeterStandard)
diff --git a/libs/ardour/enums.cc b/libs/ardour/enums.cc
index 74e445a37..1173a99b0 100644
--- a/libs/ardour/enums.cc
+++ b/libs/ardour/enums.cc
@@ -127,6 +127,7 @@ setup_enum_writer ()
 	MidiModel::NoteDiffCommand::Property _MidiModel_NoteDiffCommand_Property;
 	MidiModel::SysExDiffCommand::Property _MidiModel_SysExDiffCommand_Property;
 	MidiModel::PatchChangeDiffCommand::Property _MidiModel_PatchChangeDiffCommand_Property;
+	RegionEquivalence _RegionEquivalence;
 	WaveformScale _WaveformScale;
 	WaveformShape _WaveformShape;
 	Session::PostTransportWork _Session_PostTransportWork;
@@ -685,6 +686,11 @@ setup_enum_writer ()
 	REGISTER_ENUM(MidiPortSelection);
 	REGISTER_BITS(_MidiPortFlags);
 
+	REGISTER_ENUM(Exact);
+	REGISTER_ENUM(Enclosed);
+	REGISTER_ENUM(Overlap);
+	REGISTER(_RegionEquivalence);
+
 	REGISTER_ENUM(Linear);
 	REGISTER_ENUM(Logarithmic);
 	REGISTER(_WaveformScale);
diff --git a/libs/ardour/playlist.cc b/libs/ardour/playlist.cc
index c3b91f3f4..c992c1057 100644
--- a/libs/ardour/playlist.cc
+++ b/libs/ardour/playlist.cc
@@ -839,18 +839,28 @@ Playlist::remove_region_internal (boost::shared_ptr<Region> region)
 void
 Playlist::get_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
 {
-	if (Config->get_use_overlap_equivalency()) {
-		for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
-			if ((*i)->overlap_equivalent (other)) {
-				results.push_back (*i);
-			}
-		}
-	} else {
-		for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
-			if ((*i)->equivalent (other)) {
-				results.push_back (*i);
-			}
-		}
+	switch (Config->get_region_equivalence()) {
+		 case Exact:
+			 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
+				 if ((*i)->exact_equivalent (other)) {
+					 results.push_back (*i);
+				 }
+			 }
+			 break;
+		 case Enclosed:
+			 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
+				 if ((*i)->enclosed_equivalent (other)) {
+					 results.push_back (*i);
+				 }
+			 }
+			 break;
+		 case Overlap:
+			 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
+				 if ((*i)->overlap_equivalent (other)) {
+					 results.push_back (*i);
+				 }
+			 }
+			 break;
 	}
 }
 
diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc
index cad32cd4d..d4afb7d9c 100644
--- a/libs/ardour/region.cc
+++ b/libs/ardour/region.cc
@@ -1478,7 +1478,14 @@ Region::overlap_equivalent (boost::shared_ptr<const Region> other) const
 }
 
 bool
-Region::equivalent (boost::shared_ptr<const Region> other) const
+Region::enclosed_equivalent (boost::shared_ptr<const Region> other) const
+{
+	return (first_sample() >= other->first_sample() && last_sample() <= other->last_sample()) ||
+	       (first_sample() <= other->first_sample() && last_sample() >= other->last_sample()) ;
+}
+
+bool
+Region::exact_equivalent (boost::shared_ptr<const Region> other) const
 {
 	return _start == other->_start &&
 		_position == other->_position &&

colinf

2018-09-13 17:02

updater   ~0020385

Attached enclosed-equivalent-regions-5.12.patch applies on master (and 5.12), and Works For Me™.

paul

2018-09-13 18:18

administrator   ~0020386

git-applied to master and committed as 9321f46c453b

system

2020-04-19 20:16

developer   ~0023237

Issue has been closed automatically, by Trigger Close Plugin.
Feel free to re-open with additional information if you think the issue is not resolved.

Issue History

Date Modified Username Field Change
2013-06-07 09:02 colinf New Issue
2013-06-10 16:10 paul Note Added: 0014963
2013-06-10 17:29 colinf Note Added: 0014973
2014-09-19 18:36 colinf Note Added: 0015889
2018-09-13 13:25 colinf File Added: enclosed-equivalent-regions.patch
2018-09-13 16:59 colinf File Added: enclosed-equivalent-regions-5.12.patch
2018-09-13 17:02 colinf Note Added: 0020385
2018-09-13 18:18 paul Note Added: 0020386
2018-09-13 18:18 paul Status new => resolved
2018-09-13 18:18 paul Resolution open => fixed
2018-09-13 18:18 paul Assigned To => paul
2020-04-19 20:16 system Note Added: 0023237
2020-04-19 20:16 system Status resolved => closed