13
0

region groups: define an API in region.h for grouped regions

This commit is contained in:
Ben Loftis 2023-08-07 09:05:27 -05:00 committed by Robin Gareus
parent 92fbee6312
commit 1d5ec57794
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04
2 changed files with 66 additions and 0 deletions

View File

@ -76,6 +76,7 @@ namespace Properties {
LIBARDOUR_API extern PBD::PropertyDescriptor<float> shift;
LIBARDOUR_API extern PBD::PropertyDescriptor<uint64_t> layering_index;
LIBARDOUR_API extern PBD::PropertyDescriptor<std::string> tags;
LIBARDOUR_API extern PBD::PropertyDescriptor<uint64_t> reg_group;
LIBARDOUR_API extern PBD::PropertyDescriptor<bool> contents; // type doesn't matter here, used for signal only
};
@ -155,6 +156,52 @@ public:
timepos_t ancestral_start () const { return _ancestral_start.val(); }
timecnt_t ancestral_length () const { return _ancestral_length.val(); }
/** Region Groups:
* every region has a group-id. regions that have the same group-id (excepting zero) are 'grouped'
* if you select a 'grouped' region, then all other regions in the group will be selected
* operations like Import, Record, and Paste assign a group-id to the new regions they create
* users can explicitly group regions, which implies a stronger connection and gets the 'explicit' flag
* users can explicitly ungroup regions, which prevents ardour from applying equivalent-regions logic
* regions with no flags and no group-id (prior sessions) will revert to equivalent-regions logic */
/** RegionGroupRetainer is an RAII construct to retain a group-id for the length of an operation that creates regions */
struct RegionGroupRetainer {
RegionGroupRetainer ()
{
if (_retained_group_id == 0) {
_next_group_id++;
_retained_group_id = _next_group_id << 4;
_clear_on_destruction = true;
} else {
_clear_on_destruction = false;
}
}
~RegionGroupRetainer ()
{
if (_clear_on_destruction) {
_retained_group_id = 0;
}
}
bool _clear_on_destruction;
};
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);
}
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 unset_region_group () { _reg_group = Explicit; }
bool is_explicitly_grouped() { return (_reg_group & Explicit) == Explicit; }
bool is_implicitly_ungrouped() { return (_reg_group == NoGroup); }
bool is_explicitly_ungrouped() { return (_reg_group == Explicit); }
float stretch () const { return _stretch; }
float shift () const { return _shift; }
@ -536,6 +583,7 @@ private:
PBD::Property<float> _shift;
PBD::Property<uint64_t> _layering_index;
PBD::Property<std::string> _tags;
PBD::Property<uint64_t> _reg_group;
PBD::Property<bool> _contents; // type is irrelevant
timecnt_t _last_length;
@ -548,6 +596,14 @@ 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
};
static uint64_t _retained_group_id;
static uint64_t _next_group_id;
std::atomic<int> _source_deleted;
Glib::Threads::Mutex _source_list_lock;
PBD::ScopedConnectionList _source_deleted_connections;

View File

@ -80,6 +80,7 @@ namespace ARDOUR {
PBD::PropertyDescriptor<float> shift;
PBD::PropertyDescriptor<uint64_t> layering_index;
PBD::PropertyDescriptor<std::string> tags;
PBD::PropertyDescriptor<uint64_t> reg_group;
PBD::PropertyDescriptor<bool> contents;
/* these properties are used as a convenience for announcing changes to state, but aren't stored as properties */
@ -90,6 +91,10 @@ namespace ARDOUR {
PBD::Signal2<void,std::shared_ptr<ARDOUR::RegionList>,const PropertyChange&> Region::RegionsPropertyChanged;
/* these static values are used by Region Groups to assign a group-id across the scope of an operation that might span many function calls */
uint64_t Region::_retained_group_id = 0;
uint64_t Region::_next_group_id = 0;
void
Region::make_property_quarks ()
{
@ -147,6 +152,8 @@ Region::make_property_quarks ()
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for contents = %1\n", Properties::contents.property_id));
Properties::time_domain.property_id = g_quark_from_static_string (X_("time_domain"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for time_domain = %1\n", Properties::time_domain.property_id));
Properties::reg_group.property_id = g_quark_from_static_string (X_("rgroup"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for region_group = %1\n", Properties::reg_group.property_id));
}
void
@ -177,6 +184,7 @@ Region::register_properties ()
add_property (_shift);
add_property (_layering_index);
add_property (_tags);
add_property (_reg_group);
add_property (_contents);
}
@ -208,6 +216,7 @@ Region::register_properties ()
, _shift (Properties::shift, 1.0) \
, _layering_index (Properties::layering_index, 0) \
, _tags (Properties::tags, "") \
, _reg_group (Properties::reg_group, 0) \
, _contents (Properties::contents, false)
#define REGION_COPY_STATE(other) \
@ -240,6 +249,7 @@ Region::register_properties ()
, _shift (Properties::shift, other->_shift) \
, _layering_index (Properties::layering_index, other->_layering_index) \
, _tags (Properties::tags, other->_tags) \
, _reg_group (Properties::reg_group, other->_reg_group) \
, _contents (Properties::contents, other->_contents)
/* derived-from-derived constructor (no sources in constructor) */