mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-06 14:54:56 +01:00
Preserve existing region-group relationships
This solves several issues related to splitting or pasting regions, when there is more than one layer. Rather than assign a new group-id for "all the regions on the right of a split", only ions that had a *prior* group-relationship should be propagated into the new group. Signed-off-by: Robin Gareus <robin@gareus.org>
This commit is contained in:
parent
b2f36804be
commit
0a12986639
4 changed files with 62 additions and 15 deletions
|
|
@ -91,6 +91,12 @@ enum LIBARDOUR_API RegionEditState {
|
|||
EditChangesID = 2
|
||||
};
|
||||
|
||||
enum LIBARDOUR_API RegionOperationFlag {
|
||||
LeftOfSplit = 0,
|
||||
InnerSplit = 1, // when splitting a Range, there's left/center/right parts of the split
|
||||
RightOfSplit = 2,
|
||||
Paste = 4
|
||||
};
|
||||
|
||||
class LIBARDOUR_API Region
|
||||
: public SessionObject
|
||||
|
|
@ -170,9 +176,11 @@ public:
|
|||
struct RegionGroupRetainer {
|
||||
RegionGroupRetainer ()
|
||||
{
|
||||
Glib::Threads::Mutex::Lock lm (_operation_rgroup_mutex);
|
||||
if (_retained_group_id == 0) {
|
||||
_next_group_id++;
|
||||
_retained_group_id = _next_group_id << 4;
|
||||
++_next_group_id;
|
||||
_operation_rgroup_map.clear (); // this is used for split & paste operations that honor the region's prior grouping
|
||||
_retained_group_id = _next_group_id << 4; // this is used for newly created regions via recording or importing
|
||||
_clear_on_destruction = true;
|
||||
} else {
|
||||
_clear_on_destruction = false;
|
||||
|
|
@ -181,7 +189,9 @@ public:
|
|||
~RegionGroupRetainer ()
|
||||
{
|
||||
if (_clear_on_destruction) {
|
||||
Glib::Threads::Mutex::Lock lm (_operation_rgroup_mutex);
|
||||
_retained_group_id = 0;
|
||||
_operation_rgroup_map.clear();
|
||||
}
|
||||
}
|
||||
bool _clear_on_destruction;
|
||||
|
|
@ -190,14 +200,16 @@ public:
|
|||
static uint64_t next_group_id () { return _next_group_id; }
|
||||
static void set_next_group_id (uint64_t ngid) { _next_group_id = ngid; }
|
||||
|
||||
/* access the shared group-id, potentially with an Alt identifier (for left/center/right splits) */
|
||||
static uint64_t get_retained_group_id (bool alt = false)
|
||||
{
|
||||
return _retained_group_id | (alt ? Alt : NoGroup);
|
||||
/* access the retained group-id for actions like Recording, Import */
|
||||
static uint64_t get_retained_group_id () {
|
||||
return _retained_group_id;
|
||||
}
|
||||
|
||||
/* access the group-id for an operation on a region, honoring the existing region's group status */
|
||||
static uint64_t get_region_operation_group_id (uint64_t old_region_group, RegionOperationFlag flags);
|
||||
|
||||
uint64_t region_group () const { return _reg_group; }
|
||||
void set_region_group (bool explicitly, bool alt = false) { _reg_group = get_retained_group_id (alt) | (explicitly ? Explicit : NoGroup); }
|
||||
void set_region_group (bool explicitly) { _reg_group = get_retained_group_id () | (explicitly ? Explicit : NoGroup); }
|
||||
void unset_region_group () { _reg_group = Explicit; }
|
||||
|
||||
bool is_explicitly_grouped() { return (_reg_group & Explicit) == Explicit; }
|
||||
|
|
@ -599,13 +611,15 @@ private:
|
|||
void use_sources (SourceList const &);
|
||||
|
||||
enum RegionGroupFlags : uint64_t {
|
||||
NoGroup = 0x0, //no flag: implicitly grouped if the id is nonzero; or implicitly 'un-grouped' if the group-id is zero
|
||||
Explicit = 0x1, //the user has explicitly grouped or ungrouped this region. explicitly grouped regions can cross track-group boundaries
|
||||
Alt = 0x8, //this accommodates some operations (separate) that generate left/center/right region groups. add more bits here, if needed
|
||||
NoGroup = 0x0, // no flag: implicitly grouped if the id is nonzero; or implicitly 'un-grouped' if the group-id is zero
|
||||
Explicit = 0x1, // the user has explicitly grouped or ungrouped this region. explicitly grouped regions can cross track-group boundaries
|
||||
};
|
||||
static uint64_t _retained_group_id;
|
||||
static uint64_t _next_group_id;
|
||||
|
||||
static Glib::Threads::Mutex _operation_rgroup_mutex;
|
||||
static std::map<uint64_t, uint64_t> _operation_rgroup_map;
|
||||
|
||||
std::atomic<int> _source_deleted;
|
||||
Glib::Threads::Mutex _source_list_lock;
|
||||
PBD::ScopedConnectionList _source_deleted_connections;
|
||||
|
|
|
|||
|
|
@ -233,7 +233,7 @@ MidiPlaylist::_split_region (std::shared_ptr<Region> region, timepos_t const & p
|
|||
plist.add (Properties::length, after);
|
||||
plist.add (Properties::name, after_name);
|
||||
plist.add (Properties::right_of_split, true);
|
||||
plist.add (Properties::reg_group, Region::get_retained_group_id());
|
||||
plist.add (Properties::reg_group, Region::get_region_operation_group_id (region->region_group(), RightOfSplit));
|
||||
|
||||
/* same note as above */
|
||||
right = RegionFactory::create (region, before, plist, true, &thawlist);
|
||||
|
|
|
|||
|
|
@ -1063,7 +1063,7 @@ Playlist::partition_internal (timepos_t const & start, timepos_t const & end, bo
|
|||
plist.add (Properties::automatic, true);
|
||||
plist.add (Properties::left_of_split, true);
|
||||
plist.add (Properties::right_of_split, true);
|
||||
plist.add (Properties::reg_group, Region::get_retained_group_id(true));
|
||||
plist.add (Properties::reg_group, Region::get_region_operation_group_id (current->region_group(), InnerSplit));
|
||||
|
||||
/* see note in ::_split_region()
|
||||
*/
|
||||
|
|
@ -1083,7 +1083,7 @@ Playlist::partition_internal (timepos_t const & start, timepos_t const & end, bo
|
|||
plist.add (Properties::name, new_name);
|
||||
plist.add (Properties::automatic, true);
|
||||
plist.add (Properties::right_of_split, true);
|
||||
plist.add (Properties::reg_group, Region::get_retained_group_id());
|
||||
plist.add (Properties::reg_group, Region::get_region_operation_group_id (current->region_group(), RightOfSplit));
|
||||
|
||||
region = RegionFactory::create (current, pos1.distance (pos3), plist, true, &thawlist );
|
||||
|
||||
|
|
@ -1161,7 +1161,7 @@ Playlist::partition_internal (timepos_t const & start, timepos_t const & end, bo
|
|||
plist.add (Properties::name, new_name);
|
||||
plist.add (Properties::automatic, true);
|
||||
plist.add (Properties::right_of_split, true);
|
||||
plist.add (Properties::reg_group, Region::get_retained_group_id());
|
||||
plist.add (Properties::reg_group, Region::get_region_operation_group_id (current->region_group(), RightOfSplit));
|
||||
|
||||
region = RegionFactory::create (current, plist, true, &thawlist);
|
||||
|
||||
|
|
@ -1539,7 +1539,7 @@ Playlist::_split_region (std::shared_ptr<Region> region, timepos_t const & play
|
|||
plist.add (Properties::length, after);
|
||||
plist.add (Properties::name, after_name);
|
||||
plist.add (Properties::right_of_split, true);
|
||||
plist.add (Properties::reg_group, Region::get_retained_group_id());
|
||||
plist.add (Properties::reg_group, Region::get_region_operation_group_id (region->region_group(), RightOfSplit));
|
||||
|
||||
/* same note as above */
|
||||
right = RegionFactory::create (region, before, plist, true, &thawlist);
|
||||
|
|
|
|||
|
|
@ -95,6 +95,39 @@ PBD::Signal2<void,std::shared_ptr<ARDOUR::RegionList>,const PropertyChange&> Reg
|
|||
uint64_t Region::_retained_group_id = 0;
|
||||
uint64_t Region::_next_group_id = 0;
|
||||
|
||||
std::map<uint64_t, uint64_t> Region::_operation_rgroup_map;
|
||||
Glib::Threads::Mutex Region::_operation_rgroup_mutex;
|
||||
|
||||
/* access the group-id for an operation on a region, honoring the existing region's group status */
|
||||
uint64_t
|
||||
Region::get_region_operation_group_id (uint64_t old_region_group, RegionOperationFlag flags) {
|
||||
/* if the region was ungrouped, stay ungrouped */
|
||||
if ((old_region_group == NoGroup) || (old_region_group == Explicit)) {
|
||||
return old_region_group;
|
||||
}
|
||||
|
||||
/* separate and preserve the Explicit flag: */
|
||||
bool expl = (old_region_group & Explicit) == Explicit;
|
||||
|
||||
/* remove all flags */
|
||||
old_region_group = (old_region_group >> 4) << 4;
|
||||
|
||||
/* apply flags to create a key, which will be used to recognize regions that belong in the same group */
|
||||
uint64_t region_group_key = old_region_group | flags;
|
||||
|
||||
/* since the GUI is single-threaded, and it's hard/impossible to edit
|
||||
* during a rec-stop, this 'should' never be contentious
|
||||
*/
|
||||
Glib::Threads::Mutex::Lock lm (_operation_rgroup_mutex);
|
||||
|
||||
/* if a region group has not been assigned for this key, assign one */
|
||||
if (_operation_rgroup_map.find (region_group_key) == _operation_rgroup_map.end ()) {
|
||||
_operation_rgroup_map[region_group_key] = _next_group_id++;
|
||||
}
|
||||
|
||||
return ((_operation_rgroup_map[region_group_key] << 4) | expl);
|
||||
}
|
||||
|
||||
void
|
||||
Region::make_property_quarks ()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue