X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fregion.cc;h=17698d88a75f22fd1f223a581816ceea7933f973;hb=a473d630eb165272992e90f8d854b1d66ec0be63;hp=68325c603c908b0f88fde4edbe1442052ec5c676;hpb=fb21bf14800d3e682073365d4836e49408ffe25e;p=ardour.git diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc index 68325c603c..17698d88a7 100644 --- a/libs/ardour/region.cc +++ b/libs/ardour/region.cc @@ -29,14 +29,16 @@ #include "pbd/enumwriter.h" #include "ardour/debug.h" -#include "ardour/region.h" +#include "ardour/file_source.h" +#include "ardour/filter.h" #include "ardour/playlist.h" +#include "ardour/profile.h" +#include "ardour/region.h" +#include "ardour/region_factory.h" #include "ardour/session.h" #include "ardour/source.h" +#include "ardour/source_factory.h" #include "ardour/tempo.h" -#include "ardour/region_factory.h" -#include "ardour/filter.h" -#include "ardour/profile.h" #include "ardour/utils.h" #include "i18n.h" @@ -45,7 +47,7 @@ using namespace std; using namespace ARDOUR; using namespace PBD; -namespace ARDOUR { +namespace ARDOUR { namespace Properties { PBD::PropertyDescriptor muted; PBD::PropertyDescriptor opaque; @@ -72,7 +74,7 @@ namespace ARDOUR { PBD::PropertyDescriptor position_lock_style; } } - + PBD::Signal2,const PropertyChange&> Region::RegionPropertyChanged; void @@ -245,14 +247,8 @@ Region::Region (const SourceList& srcs) assert (_type == srcs.front()->type()); } -/** Create a new Region from part of an existing one, starting at one of two places: - - if \a offset_relative is true, then the start within \a other is given by \a offset - (i.e. relative to the start of \a other's sources, the start is \a offset + \a other.start() - - if @param offset_relative is false, then the start within the source is given \a offset. -*/ -Region::Region (boost::shared_ptr other, frameoffset_t offset, bool offset_relative) +/** Create a new Region from an existing one */ +Region::Region (boost::shared_ptr other) : SessionObject(other->session(), other->name()) , _type (other->data_type()) , REGION_COPY_STATE (other) @@ -276,70 +272,34 @@ Region::Region (boost::shared_ptr other, frameoffset_t offset, boo use_sources (other->_sources); - if (!offset_relative) { + _position_lock_style = other->_position_lock_style; + _first_edit = other->_first_edit; - /* not sure why we do this, but its a hangover from ardour before - property lists. this would be nice to remove. - */ + _start = 0; // It seems strange _start is not inherited here? - _position_lock_style = other->_position_lock_style; - _first_edit = other->_first_edit; - - if (offset == 0) { - - _start = 0; - - /* sync pos is relative to start of file. our start-in-file is now zero, - so set our sync position to whatever the the difference between - _start and _sync_pos was in the other region. - - result is that our new sync pos points to the same point in our source(s) - as the sync in the other region did in its source(s). - - since we start at zero in our source(s), it is not possible to use a sync point that - is before the start. reset it to _start if that was true in the other region. - */ - - if (other->sync_marked()) { - if (other->_start < other->_sync_position) { - /* sync pos was after the start point of the other region */ - _sync_position = other->_sync_position - other->_start; - } else { - /* sync pos was before the start point of the other region. not possible here. */ - _sync_marked = false; - _sync_position = _start; - } - } else { - _sync_marked = false; - _sync_position = _start; - } - } else { - /* XXX do something else ! */ - fatal << string_compose (_("programming error: %1"), X_("Region+offset constructor used with illegal combination of offset+relative")) - << endmsg; - /*NOTREACHED*/ - } + /* sync pos is relative to start of file. our start-in-file is now zero, + so set our sync position to whatever the the difference between + _start and _sync_pos was in the other region. - } else { + result is that our new sync pos points to the same point in our source(s) + as the sync in the other region did in its source(s). - _start = other->_start + offset; - - /* if the other region had a distinct sync point - set, then continue to use it as best we can. - otherwise, reset sync point back to start. - */ - - if (other->sync_marked()) { - if (other->_sync_position < _start) { - _sync_marked = false; - _sync_position = _start; - } else { - _sync_position = other->_sync_position; - } + since we start at zero in our source(s), it is not possible to use a sync point that + is before the start. reset it to _start if that was true in the other region. + */ + + if (other->sync_marked()) { + if (other->_start < other->_sync_position) { + /* sync pos was after the start point of the other region */ + _sync_position = other->_sync_position - other->_start; } else { + /* sync pos was before the start point of the other region. not possible here. */ _sync_marked = false; _sync_position = _start; } + } else { + _sync_marked = false; + _sync_position = _start; } if (Profile->get_sae()) { @@ -356,45 +316,78 @@ Region::Region (boost::shared_ptr other, frameoffset_t offset, boo assert (_type == other->data_type()); } -/** Create a copy of @param other but with different sources. Used by filters */ -Region::Region (boost::shared_ptr other, const SourceList& srcs) - : SessionObject (other->session(), other->name()) - , _type (srcs.front()->type()) +/** Create a new Region from part of an existing one. + + the start within \a other is given by \a offset + (i.e. relative to the start of \a other's sources, the start is \a offset + \a other.start() +*/ +Region::Region (boost::shared_ptr other, frameoffset_t offset) + : SessionObject(other->session(), other->name()) + , _type (other->data_type()) , REGION_COPY_STATE (other) , _last_length (other->_last_length) - , _last_position (other->_last_position) - , _first_edit (EditChangesID) - , _read_data_count (0) - , _last_layer_op (other->_last_layer_op) + , _last_position(other->_last_position) \ + , _first_edit (EditChangesNothing) + , _read_data_count(0) + , _last_layer_op (0) , _pending_explicit_relayer (false) + { register_properties (); + /* override state that may have been incorrectly inherited from the other region + */ + + _position = 0; _locked = false; - _position_locked = false; + _whole_file = false; + _hidden = false; - other->_first_edit = EditChangesName; + use_sources (other->_sources); - if (other->_extra_xml) { - _extra_xml = new XMLNode (*other->_extra_xml); + _start = other->_start + offset; + + /* if the other region had a distinct sync point + set, then continue to use it as best we can. + otherwise, reset sync point back to start. + */ + + if (other->sync_marked()) { + if (other->_sync_position < _start) { + _sync_marked = false; + _sync_position = _start; + } else { + _sync_position = other->_sync_position; + } } else { - _extra_xml = 0; + _sync_marked = false; + _sync_position = _start; } - use_sources (srcs); - assert(_sources.size() > 0); + if (Profile->get_sae()) { + /* reset sync point to start if its ended up + outside region bounds. + */ + + if (_sync_position < _start || _sync_position >= _start + _length) { + _sync_marked = false; + _sync_position = _start; + } + } + + assert (_type == other->data_type()); } -/** Simple "copy" constructor */ -Region::Region (boost::shared_ptr other) - : SessionObject(other->session(), other->name()) - , _type(other->data_type()) +/** Create a copy of @param other but with different sources. Used by filters */ +Region::Region (boost::shared_ptr other, const SourceList& srcs) + : SessionObject (other->session(), other->name()) + , _type (srcs.front()->type()) , REGION_COPY_STATE (other) , _last_length (other->_last_length) , _last_position (other->_last_position) , _first_edit (EditChangesID) - , _read_data_count(0) - , _last_layer_op(other->_last_layer_op) + , _read_data_count (0) + , _last_layer_op (other->_last_layer_op) , _pending_explicit_relayer (false) { register_properties (); @@ -410,7 +403,7 @@ Region::Region (boost::shared_ptr other) _extra_xml = 0; } - use_sources (other->_sources); + use_sources (srcs); assert(_sources.size() > 0); } @@ -432,6 +425,7 @@ Region::set_name (const std::string& str) if (_name != str) { SessionObject::set_name(str); // EMIT SIGNAL NameChanged() assert(_name == str); + send_change (Properties::name); } @@ -439,7 +433,7 @@ Region::set_name (const std::string& str) } void -Region::set_length (framecnt_t len, void */*src*/) +Region::set_length (framecnt_t len) { //cerr << "Region::set_length() len = " << len << endl; if (locked()) { @@ -499,6 +493,7 @@ Region::first_edit () _first_edit = EditChangesNothing; send_change (Properties::name); + RegionFactory::CheckNewRegion (shared_from_this()); } } @@ -524,7 +519,7 @@ Region::at_natural_position () const } void -Region::move_to_natural_position (void *src) +Region::move_to_natural_position () { boost::shared_ptr pl (playlist()); @@ -535,7 +530,7 @@ Region::move_to_natural_position (void *src) boost::shared_ptr whole_file_region = get_parent(); if (whole_file_region) { - set_position (whole_file_region->position() + _start, src); + set_position (whole_file_region->position() + _start); } } @@ -556,18 +551,19 @@ Region::set_position_lock_style (PositionLockStyle ps) if (_position_lock_style != ps) { boost::shared_ptr pl (playlist()); - + if (!pl) { return; } - + _position_lock_style = ps; - + if (_position_lock_style == MusicTime) { _session.tempo_map().bbt_time (_position, _bbt_time); } send_change (Properties::position_lock_style); + } } @@ -591,7 +587,7 @@ Region::update_position_after_tempo_map_change () } void -Region::set_position (framepos_t pos, void* /*src*/) +Region::set_position (framepos_t pos) { if (!can_move()) { return; @@ -603,7 +599,7 @@ Region::set_position (framepos_t pos, void* /*src*/) a GUI that has moved its representation already. */ send_change (Properties::position); - + } void @@ -633,7 +629,7 @@ Region::set_position_internal (framepos_t pos, bool allow_bbt_recompute) } void -Region::set_position_on_top (framepos_t pos, void* /*src*/) +Region::set_position_on_top (framepos_t pos) { if (locked()) { return; @@ -652,7 +648,6 @@ Region::set_position_on_top (framepos_t pos, void* /*src*/) /* do this even if the position is the same. this helps out a GUI that has moved its representation already. */ - send_change (Properties::position); } @@ -665,7 +660,7 @@ Region::recompute_position_from_lock_style () } void -Region::nudge_position (frameoffset_t n, void* /*src*/) +Region::nudge_position (frameoffset_t n) { if (locked()) { return; @@ -706,7 +701,7 @@ Region::set_ancestral_data (framepos_t s, framecnt_t l, float st, float sh) } void -Region::set_start (framepos_t pos, void* /*src*/) +Region::set_start (framepos_t pos) { if (locked() || position_locked()) { return; @@ -732,7 +727,7 @@ Region::set_start (framepos_t pos, void* /*src*/) } void -Region::trim_start (framepos_t new_position, void */*src*/) +Region::trim_start (framepos_t new_position) { if (locked() || position_locked()) { return; @@ -759,7 +754,7 @@ Region::trim_start (framepos_t new_position, void */*src*/) } else { new_start = _start + start_shift; } - + } else { return; } @@ -776,25 +771,25 @@ Region::trim_start (framepos_t new_position, void */*src*/) } void -Region::trim_front (framepos_t new_position, void *src) +Region::trim_front (framepos_t new_position) { - modify_front (new_position, false, src); + modify_front (new_position, false); } void -Region::cut_front (framepos_t new_position, void *src) +Region::cut_front (framepos_t new_position) { - modify_front (new_position, true, src); + modify_front (new_position, true); } void -Region::cut_end (framepos_t new_endpoint, void *src) +Region::cut_end (framepos_t new_endpoint) { - modify_end (new_endpoint, true, src); + modify_end (new_endpoint, true); } void -Region::modify_front (framepos_t new_position, bool reset_fade, void *src) +Region::modify_front (framepos_t new_position, bool reset_fade) { if (locked()) { return; @@ -810,7 +805,7 @@ Region::modify_front (framepos_t new_position, bool reset_fade, void *src) } if (new_position < end) { /* can't trim it zero or negative length */ - + framecnt_t newlen = 0; framepos_t delta = 0; @@ -818,7 +813,7 @@ Region::modify_front (framepos_t new_position, bool reset_fade, void *src) /* can't trim it back past where source position zero is located */ new_position = max (new_position, source_zero); } - + if (new_position > _position) { newlen = _length - (new_position - _position); delta = -1 * (new_position - _position); @@ -826,17 +821,17 @@ Region::modify_front (framepos_t new_position, bool reset_fade, void *src) newlen = _length + (_position - new_position); delta = _position - new_position; } - - trim_to_internal (new_position, newlen, src); - + + trim_to_internal (new_position, newlen); + if (reset_fade) { _right_of_split = true; } - + if (!property_changes_suspended()) { recompute_at_start (); } - + if (_transients.size() > 0){ adjust_transients(delta); } @@ -844,14 +839,14 @@ Region::modify_front (framepos_t new_position, bool reset_fade, void *src) } void -Region::modify_end (framepos_t new_endpoint, bool reset_fade, void* /*src*/) +Region::modify_end (framepos_t new_endpoint, bool reset_fade) { if (locked()) { return; } if (new_endpoint > _position) { - trim_to_internal (_position, new_endpoint - _position +1, this); + trim_to_internal (_position, new_endpoint - _position +1); if (reset_fade) { _left_of_split = true; } @@ -866,19 +861,19 @@ Region::modify_end (framepos_t new_endpoint, bool reset_fade, void* /*src*/) */ void -Region::trim_end (framepos_t new_endpoint, void* src) +Region::trim_end (framepos_t new_endpoint) { - modify_end (new_endpoint, false, src); + modify_end (new_endpoint, false); } void -Region::trim_to (framepos_t position, framecnt_t length, void *src) +Region::trim_to (framepos_t position, framecnt_t length) { if (locked()) { return; } - trim_to_internal (position, length, src); + trim_to_internal (position, length); if (!property_changes_suspended()) { recompute_at_start (); @@ -887,7 +882,7 @@ Region::trim_to (framepos_t position, framecnt_t length, void *src) } void -Region::trim_to_internal (framepos_t position, framecnt_t length, void */*src*/) +Region::trim_to_internal (framepos_t position, framecnt_t length) { framepos_t new_start; @@ -927,13 +922,15 @@ Region::trim_to_internal (framepos_t position, framecnt_t length, void */*src*/) _start = new_start; what_changed.add (Properties::start); } - if (_length != length) { - if (!property_changes_suspended()) { - _last_length = _length; - } - set_length_internal (length); - what_changed.add (Properties::length); - } + + /* Set position before length, otherwise for MIDI regions this bad thing happens: + * 1. we call set_length_internal; length in beats is computed using the region's current + * (soon-to-be old) position + * 2. we call set_position_internal; position is set and length in frames re-computed using + * length in beats from (1) but at the new position, which is wrong if the region + * straddles a tempo/meter change. + */ + if (_position != position) { if (!property_changes_suspended()) { _last_position = _position; @@ -942,6 +939,14 @@ Region::trim_to_internal (framepos_t position, framecnt_t length, void */*src*/) what_changed.add (Properties::position); } + if (_length != length) { + if (!property_changes_suspended()) { + _last_length = _length; + } + set_length_internal (length); + what_changed.add (Properties::length); + } + _whole_file = false; PropertyChange start_and_length; @@ -1032,6 +1037,7 @@ Region::set_sync_position (framepos_t absolute_pos) if (!property_changes_suspended()) { maybe_uncopy (); } + send_change (Properties::sync_position); } } @@ -1044,6 +1050,7 @@ Region::clear_sync_position () if (!property_changes_suspended()) { maybe_uncopy (); } + send_change (Properties::sync_position); } } @@ -1200,6 +1207,24 @@ Region::state () node->add_property (buf2, buf); } + if (max_source_level() > 0) { + + XMLNode* nested_node = new XMLNode (X_("NestedSource")); + + /* region is compound - get its playlist and + store that before we list the region that + needs it ... + */ + + for (SourceList::const_iterator s = _sources.begin(); s != _sources.end(); ++s) { + nested_node->add_child_nocopy ((*s)->get_state ()); + } + + if (nested_node) { + node->add_child_nocopy (*nested_node); + } + } + if (_extra_xml) { node->add_child_copy (*_extra_xml); } @@ -1224,6 +1249,17 @@ int Region::_set_state (const XMLNode& node, int /*version*/, PropertyChange& what_changed, bool send) { const XMLProperty* prop; + const XMLNodeList& nlist = node.children(); + + for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) { + + XMLNode *child = (*niter); + + if (child->name () == "Extra") { + delete _extra_xml; + _extra_xml = new XMLNode (*child); + } + } what_changed = set_values (node); @@ -1251,37 +1287,22 @@ Region::_set_state (const XMLNode& node, int /*version*/, PropertyChange& what_c if (_stretch == 0.0f) { _stretch = 1.0f; } - + if (_shift == 0.0f) { _shift = 1.0f; } - const XMLNodeList& nlist = node.children(); - - for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) { - - XMLNode *child; - - child = (*niter); - - if (child->name () == "Extra") { - delete _extra_xml; - _extra_xml = new XMLNode (*child); - break; - } - } - if (send) { send_change (what_changed); } - + /* Quick fix for 2.x sessions when region is muted */ if ((prop = node.property (X_("flags")))) { if (string::npos != prop->value().find("Muted")){ set_muted (true); } } - + return 0; } @@ -1315,7 +1336,7 @@ Region::send_change (const PropertyChange& what_changed) Stateful::send_change (what_changed); if (!Stateful::frozen()) { - + /* Try and send a shared_pointer unless this is part of the constructor. If so, do nothing. */ @@ -1413,7 +1434,7 @@ Region::source_equivalent (boost::shared_ptr other) const { if (!other) return false; - + if ((_sources.size() != other->_sources.size()) || (_master_sources.size() != other->_master_sources.size())) { return false; @@ -1437,6 +1458,27 @@ Region::source_equivalent (boost::shared_ptr other) const return true; } +std::string +Region::source_string () const +{ + //string res = itos(_sources.size()); + + stringstream res; + res << _sources.size() << ":"; + + SourceList::const_iterator i; + + for (i = _sources.begin(); i != _sources.end(); ++i) { + res << (*i)->id() << ":"; + } + + for (i = _master_sources.begin(); i != _master_sources.end(); ++i) { + res << (*i)->id() << ":"; + } + + return res.str(); +} + bool Region::uses_source (boost::shared_ptr source) const { @@ -1448,6 +1490,20 @@ Region::uses_source (boost::shared_ptr source) const return false; } +bool +Region::uses_source_path (const std::string& path) const +{ + for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) { + boost::shared_ptr fs = boost::dynamic_pointer_cast (*i); + if (fs) { + if (fs->path() == path) { + return true; + } + } + } + return false; +} + framecnt_t Region::source_length(uint32_t n) const { @@ -1550,7 +1606,7 @@ Region::invalidate_transients () { _valid_transients = false; _transients.clear (); - + send_change (PropertyChange (Properties::valid_transients)); } @@ -1601,7 +1657,7 @@ Region::can_trim () const return ct; } - /* if not locked, we can always move the front later, and the end earlier + /* if not locked, we can always move the front later, and the end earlier */ ct = CanTrim (ct | FrontTrimLater | EndTrimEarlier); @@ -1618,4 +1674,21 @@ Region::can_trim () const return ct; } - + +uint32_t +Region::max_source_level () const +{ + uint32_t lvl = 0; + + for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) { + lvl = max (lvl, (*i)->level()); + } + + return lvl; +} + +bool +Region::is_compound () const +{ + return max_source_level() > 0; +}