X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fregion.cc;h=c74ce4e41998ec82797f64c6c0112e9a6ee5ce01;hb=54ce76e8fd7d6c4840cbdfabd6034bae008f520e;hp=da26c87f26c41a95aa3516f1d22c4cd5cdc93da3;hpb=7b2975244165b4ffd1dcf4080c1be4c8dcbc6708;p=ardour.git diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc index da26c87f26..c74ce4e419 100644 --- a/libs/ardour/region.cc +++ b/libs/ardour/region.cc @@ -23,21 +23,19 @@ #include #include -#include +#include #include "pbd/xml++.h" -#include "pbd/stacktrace.h" -#include "pbd/enumwriter.h" #include "ardour/debug.h" -#include "ardour/region.h" +#include "ardour/filter.h" #include "ardour/playlist.h" +#include "ardour/playlist_source.h" +#include "ardour/profile.h" +#include "ardour/region.h" +#include "ardour/region_factory.h" #include "ardour/session.h" #include "ardour/source.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 +43,8 @@ using namespace std; using namespace ARDOUR; using namespace PBD; -namespace ARDOUR { +namespace ARDOUR { + class Progress; namespace Properties { PBD::PropertyDescriptor muted; PBD::PropertyDescriptor opaque; @@ -70,60 +69,63 @@ namespace ARDOUR { PBD::PropertyDescriptor stretch; PBD::PropertyDescriptor shift; PBD::PropertyDescriptor position_lock_style; + PBD::PropertyDescriptor layering_index; } } - + PBD::Signal2,const PropertyChange&> Region::RegionPropertyChanged; void Region::make_property_quarks () { Properties::muted.property_id = g_quark_from_static_string (X_("muted")); - DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for muted = %1\n", Properties::muted.property_id)); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for muted = %1\n", Properties::muted.property_id)); Properties::opaque.property_id = g_quark_from_static_string (X_("opaque")); - DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for opaque = %1\n", Properties::opaque.property_id)); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for opaque = %1\n", Properties::opaque.property_id)); Properties::locked.property_id = g_quark_from_static_string (X_("locked")); - DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for locked = %1\n", Properties::locked.property_id)); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for locked = %1\n", Properties::locked.property_id)); Properties::automatic.property_id = g_quark_from_static_string (X_("automatic")); - DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for automatic = %1\n", Properties::automatic.property_id)); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for automatic = %1\n", Properties::automatic.property_id)); Properties::whole_file.property_id = g_quark_from_static_string (X_("whole-file")); - DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for whole-file = %1\n", Properties::whole_file.property_id)); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for whole-file = %1\n", Properties::whole_file.property_id)); Properties::import.property_id = g_quark_from_static_string (X_("import")); - DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for import = %1\n", Properties::import.property_id)); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for import = %1\n", Properties::import.property_id)); Properties::external.property_id = g_quark_from_static_string (X_("external")); - DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for external = %1\n", Properties::external.property_id)); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for external = %1\n", Properties::external.property_id)); Properties::sync_marked.property_id = g_quark_from_static_string (X_("sync-marked")); - DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for sync-marked = %1\n", Properties::sync_marked.property_id)); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for sync-marked = %1\n", Properties::sync_marked.property_id)); Properties::left_of_split.property_id = g_quark_from_static_string (X_("left-of-split")); - DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for left-of-split = %1\n", Properties::left_of_split.property_id)); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for left-of-split = %1\n", Properties::left_of_split.property_id)); Properties::right_of_split.property_id = g_quark_from_static_string (X_("right-of-split")); - DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for right-of-split = %1\n", Properties::right_of_split.property_id)); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for right-of-split = %1\n", Properties::right_of_split.property_id)); Properties::hidden.property_id = g_quark_from_static_string (X_("hidden")); - DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for hidden = %1\n", Properties::hidden.property_id)); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for hidden = %1\n", Properties::hidden.property_id)); Properties::position_locked.property_id = g_quark_from_static_string (X_("position-locked")); - DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for position-locked = %1\n", Properties::position_locked.property_id)); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for position-locked = %1\n", Properties::position_locked.property_id)); Properties::valid_transients.property_id = g_quark_from_static_string (X_("valid-transients")); - DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for valid-transients = %1\n", Properties::valid_transients.property_id)); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for valid-transients = %1\n", Properties::valid_transients.property_id)); Properties::start.property_id = g_quark_from_static_string (X_("start")); - DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for start = %1\n", Properties::start.property_id)); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for start = %1\n", Properties::start.property_id)); Properties::length.property_id = g_quark_from_static_string (X_("length")); - DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for length = %1\n", Properties::length.property_id)); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for length = %1\n", Properties::length.property_id)); Properties::position.property_id = g_quark_from_static_string (X_("position")); - DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for position = %1\n", Properties::position.property_id)); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for position = %1\n", Properties::position.property_id)); Properties::sync_position.property_id = g_quark_from_static_string (X_("sync-position")); - DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for sync-position = %1\n", Properties::sync_position.property_id)); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for sync-position = %1\n", Properties::sync_position.property_id)); Properties::layer.property_id = g_quark_from_static_string (X_("layer")); - DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for layer = %1\n", Properties::layer.property_id)); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for layer = %1\n", Properties::layer.property_id)); Properties::ancestral_start.property_id = g_quark_from_static_string (X_("ancestral-start")); - DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for ancestral-start = %1\n", Properties::ancestral_start.property_id)); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for ancestral-start = %1\n", Properties::ancestral_start.property_id)); Properties::ancestral_length.property_id = g_quark_from_static_string (X_("ancestral-length")); - DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for ancestral-length = %1\n", Properties::ancestral_length.property_id)); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for ancestral-length = %1\n", Properties::ancestral_length.property_id)); Properties::stretch.property_id = g_quark_from_static_string (X_("stretch")); - DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for stretch = %1\n", Properties::stretch.property_id)); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for stretch = %1\n", Properties::stretch.property_id)); Properties::shift.property_id = g_quark_from_static_string (X_("shift")); - DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for shift = %1\n", Properties::shift.property_id)); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for shift = %1\n", Properties::shift.property_id)); Properties::position_lock_style.property_id = g_quark_from_static_string (X_("positional-lock-style")); - DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for position_lock_style = %1\n", Properties::position_lock_style.property_id)); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for position_lock_style = %1\n", Properties::position_lock_style.property_id)); + Properties::layering_index.property_id = g_quark_from_static_string (X_("layering-index")); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for layering_index = %1\n", Properties::layering_index.property_id)); } void @@ -148,63 +150,63 @@ Region::register_properties () add_property (_length); add_property (_position); add_property (_sync_position); - add_property (_layer); add_property (_ancestral_start); add_property (_ancestral_length); add_property (_stretch); add_property (_shift); add_property (_position_lock_style); + add_property (_layering_index); } #define REGION_DEFAULT_STATE(s,l) \ - _muted (Properties::muted, false) \ + _sync_marked (Properties::sync_marked, false) \ + , _left_of_split (Properties::left_of_split, false) \ + , _right_of_split (Properties::right_of_split, false) \ + , _valid_transients (Properties::valid_transients, false) \ + , _start (Properties::start, (s)) \ + , _length (Properties::length, (l)) \ + , _position (Properties::position, 0) \ + , _sync_position (Properties::sync_position, (s)) \ + , _muted (Properties::muted, false) \ , _opaque (Properties::opaque, true) \ , _locked (Properties::locked, false) \ , _automatic (Properties::automatic, false) \ , _whole_file (Properties::whole_file, false) \ , _import (Properties::import, false) \ , _external (Properties::external, false) \ - , _sync_marked (Properties::sync_marked, false) \ - , _left_of_split (Properties::left_of_split, false) \ - , _right_of_split (Properties::right_of_split, false) \ , _hidden (Properties::hidden, false) \ , _position_locked (Properties::position_locked, false) \ - , _valid_transients (Properties::valid_transients, false) \ - , _start (Properties::start, (s)) \ - , _length (Properties::length, (l)) \ - , _position (Properties::position, 0) \ - , _sync_position (Properties::sync_position, (s)) \ - , _layer (Properties::layer, 0) \ , _ancestral_start (Properties::ancestral_start, (s)) \ , _ancestral_length (Properties::ancestral_length, (l)) \ , _stretch (Properties::stretch, 1.0) \ , _shift (Properties::shift, 1.0) \ - , _position_lock_style (Properties::position_lock_style, _type == DataType::AUDIO ? AudioTime : MusicTime) + , _position_lock_style (Properties::position_lock_style, _type == DataType::AUDIO ? AudioTime : MusicTime) \ + , _layering_index (Properties::layering_index, 0) #define REGION_COPY_STATE(other) \ - _muted (other->_muted) \ - , _opaque (other->_opaque) \ - , _locked (other->_locked) \ - , _automatic (other->_automatic) \ - , _whole_file (other->_whole_file) \ - , _import (other->_import) \ - , _external (other->_external) \ - , _sync_marked (other->_sync_marked) \ - , _left_of_split (other->_left_of_split) \ - , _right_of_split (other->_right_of_split) \ - , _hidden (other->_hidden) \ - , _position_locked (other->_position_locked) \ - , _valid_transients (other->_valid_transients) \ - , _start(other->_start) \ - , _length(other->_length) \ - , _position(other->_position) \ - , _sync_position(other->_sync_position) \ - , _layer (other->_layer) \ - , _ancestral_start (other->_ancestral_start) \ - , _ancestral_length (other->_ancestral_length) \ - , _stretch (other->_stretch) \ - , _shift (other->_shift) \ - , _position_lock_style (other->_position_lock_style) + _sync_marked (Properties::sync_marked, other->_sync_marked) \ + , _left_of_split (Properties::left_of_split, other->_left_of_split) \ + , _right_of_split (Properties::right_of_split, other->_right_of_split) \ + , _valid_transients (Properties::valid_transients, other->_valid_transients) \ + , _start(Properties::start, other->_start) \ + , _length(Properties::length, other->_length) \ + , _position(Properties::position, other->_position) \ + , _sync_position(Properties::sync_position, other->_sync_position) \ + , _muted (Properties::muted, other->_muted) \ + , _opaque (Properties::opaque, other->_opaque) \ + , _locked (Properties::locked, other->_locked) \ + , _automatic (Properties::automatic, other->_automatic) \ + , _whole_file (Properties::whole_file, other->_whole_file) \ + , _import (Properties::import, other->_import) \ + , _external (Properties::external, other->_external) \ + , _hidden (Properties::hidden, other->_hidden) \ + , _position_locked (Properties::position_locked, other->_position_locked) \ + , _ancestral_start (Properties::ancestral_start, other->_ancestral_start) \ + , _ancestral_length (Properties::ancestral_length, other->_ancestral_length) \ + , _stretch (Properties::stretch, other->_stretch) \ + , _shift (Properties::shift, other->_shift) \ + , _position_lock_style (Properties::position_lock_style, other->_position_lock_style) \ + , _layering_index (Properties::layering_index, other->_layering_index) /* derived-from-derived constructor (no sources in constructor) */ Region::Region (Session& s, framepos_t start, framecnt_t length, const string& name, DataType type) @@ -214,9 +216,7 @@ Region::Region (Session& s, framepos_t start, framecnt_t length, const string& n , _last_length (length) , _last_position (0) , _first_edit (EditChangesNothing) - , _read_data_count(0) - , _last_layer_op(0) - , _pending_explicit_relayer (false) + , _layer (0) { register_properties (); @@ -231,9 +231,7 @@ Region::Region (const SourceList& srcs) , _last_length (0) , _last_position (0) , _first_edit (EditChangesNothing) - , _read_data_count(0) - , _last_layer_op (0) - , _pending_explicit_relayer (false) + , _layer (0) { register_properties (); @@ -245,24 +243,15 @@ 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) , _last_length (other->_last_length) , _last_position(other->_last_position) \ , _first_edit (EditChangesNothing) - , _read_data_count(0) - , _last_layer_op (0) - , _pending_explicit_relayer (false) - + , _layer (other->_layer) { register_properties (); @@ -276,70 +265,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,46 +309,74 @@ 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) - , _pending_explicit_relayer (false) + , _last_position(other->_last_position) \ + , _first_edit (EditChangesNothing) + , _layer (other->_layer) { 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) - , _pending_explicit_relayer (false) + , _layer (other->_layer) { register_properties (); @@ -410,7 +391,7 @@ Region::Region (boost::shared_ptr other) _extra_xml = 0; } - use_sources (other->_sources); + use_sources (srcs); assert(_sources.size() > 0); } @@ -432,6 +413,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 +421,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()) { @@ -452,7 +434,7 @@ Region::set_length (framecnt_t len, void */*src*/) length impossible. */ - if (max_frames - len < _position) { + if (max_framepos - len < _position) { return; } @@ -462,7 +444,7 @@ Region::set_length (framecnt_t len, void */*src*/) _last_length = _length; - _length = len; + set_length_internal (len); _whole_file = false; first_edit (); maybe_uncopy (); @@ -476,6 +458,12 @@ Region::set_length (framecnt_t len, void */*src*/) } } +void +Region::set_length_internal (framecnt_t len) +{ + _length = len; +} + void Region::maybe_uncopy () { @@ -493,6 +481,7 @@ Region::first_edit () _first_edit = EditChangesNothing; send_change (Properties::name); + RegionFactory::CheckNewRegion (shared_from_this()); } } @@ -518,7 +507,7 @@ Region::at_natural_position () const } void -Region::move_to_natural_position (void *src) +Region::move_to_natural_position () { boost::shared_ptr pl (playlist()); @@ -529,7 +518,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); } } @@ -550,15 +539,11 @@ 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); + _session.bbt_time (_position, _bbt_time); } send_change (Properties::position_lock_style); @@ -566,7 +551,7 @@ Region::set_position_lock_style (PositionLockStyle ps) } void -Region::update_position_after_tempo_map_change () +Region::update_after_tempo_map_change () { boost::shared_ptr pl (playlist()); @@ -577,23 +562,39 @@ Region::update_position_after_tempo_map_change () TempoMap& map (_session.tempo_map()); framepos_t pos = map.frame_time (_bbt_time); set_position_internal (pos, false); + + /* do this even if the position is the same. this helps out + a GUI that has moved its representation already. + */ + send_change (Properties::position); } void -Region::set_position (framepos_t pos, void* /*src*/) +Region::set_position (framepos_t pos) { if (!can_move()) { return; } set_position_internal (pos, true); + + /* do this even if the position is the same. this helps out + a GUI that has moved its representation already. + */ + send_change (Properties::position); + } void Region::set_position_internal (framepos_t pos, bool allow_bbt_recompute) { + /* We emit a change of Properties::position even if the position hasn't changed + (see Region::set_position), so we must always set this up so that + e.g. Playlist::notify_region_moved doesn't use an out-of-date last_position. + */ + _last_position = _position; + if (_position != pos) { - _last_position = _position; _position = pos; /* check that the new _position wouldn't make the current @@ -602,9 +603,9 @@ Region::set_position_internal (framepos_t pos, bool allow_bbt_recompute) XXX is this the right thing to do? */ - if (max_frames - _length < _position) { + if (max_framepos - _length < _position) { _last_length = _length; - _length = max_frames - _position; + _length = max_framepos - _position; } if (allow_bbt_recompute) { @@ -613,48 +614,18 @@ Region::set_position_internal (framepos_t pos, bool allow_bbt_recompute) //invalidate_transients (); } - - /* do this even if the position is the same. this helps out - a GUI that has moved its representation already. - */ - send_change (Properties::position); -} - -void -Region::set_position_on_top (framepos_t pos, void* /*src*/) -{ - if (locked()) { - return; - } - - if (_position != pos) { - _last_position = _position; - _position = pos; - } - - boost::shared_ptr pl (playlist()); - - if (pl) { - pl->raise_region_to_top (shared_from_this ()); - } - - /* do this even if the position is the same. this helps out - a GUI that has moved its representation already. - */ - - send_change (Properties::position); } void Region::recompute_position_from_lock_style () { if (_position_lock_style == MusicTime) { - _session.tempo_map().bbt_time (_position, _bbt_time); + _session.bbt_time (_position, _bbt_time); } } void -Region::nudge_position (frameoffset_t n, void* /*src*/) +Region::nudge_position (frameoffset_t n) { if (locked()) { return; @@ -664,22 +635,24 @@ Region::nudge_position (frameoffset_t n, void* /*src*/) return; } - _last_position = _position; + framepos_t new_position = _position; if (n > 0) { - if (_position > max_frames - n) { - _position = max_frames; + if (_position > max_framepos - n) { + new_position = max_framepos; } else { - _position += n; + new_position += n; } } else { if (_position < -n) { - _position = 0; + new_position = 0; } else { - _position += n; + new_position += n; } } + set_position_internal (new_position, true); + send_change (Properties::position); } @@ -693,7 +666,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; @@ -709,7 +682,7 @@ Region::set_start (framepos_t pos, void* /*src*/) return; } - _start = pos; + set_start_internal (pos); _whole_file = false; first_edit (); invalidate_transients (); @@ -719,24 +692,19 @@ 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; } - framepos_t new_start; - frameoffset_t start_shift; - if (new_position > _position) { - start_shift = new_position - _position; - } else { - start_shift = -(_position - new_position); - } + framepos_t new_start; + frameoffset_t const start_shift = new_position - _position; if (start_shift > 0) { - if (_start > max_frames - start_shift) { - new_start = max_frames; + if (_start > max_framepos - start_shift) { + new_start = max_framepos; } else { new_start = _start + start_shift; } @@ -752,6 +720,7 @@ Region::trim_start (framepos_t new_position, void */*src*/) } else { new_start = _start + start_shift; } + } else { return; } @@ -760,7 +729,7 @@ Region::trim_start (framepos_t new_position, void */*src*/) return; } - _start = new_start; + set_start_internal (new_start); _whole_file = false; first_edit (); @@ -768,32 +737,32 @@ 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 (nframes_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 (nframes_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 (nframes_t new_position, bool reset_fade, void *src) +Region::modify_front (framepos_t new_position, bool reset_fade) { if (locked()) { return; } - nframes_t end = last_frame(); - nframes_t source_zero; + framepos_t end = last_frame(); + framepos_t source_zero; if (_position > _start) { source_zero = _position - _start; @@ -802,14 +771,15 @@ Region::modify_front (nframes_t new_position, bool reset_fade, void *src) } if (new_position < end) { /* can't trim it zero or negative length */ - - nframes_t newlen = 0; - nframes64_t delta = 0; - - /* can't trim it back passed where source position zero is located */ - - new_position = max (new_position, source_zero); - + + framecnt_t newlen = 0; + framepos_t delta = 0; + + if (!can_trim_start_before_source_start ()) { + /* 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); @@ -817,17 +787,17 @@ Region::modify_front (nframes_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; + _right_of_split = true; } - - if (!property_changes_suspended()) { + + if (!property_changes_suspended()) { recompute_at_start (); } - + if (_transients.size() > 0){ adjust_transients(delta); } @@ -835,16 +805,16 @@ Region::modify_front (nframes_t new_position, bool reset_fade, void *src) } void -Region::modify_end (nframes_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); if (reset_fade) { - _left_of_split = true; + _left_of_split = true; } if (!property_changes_suspended()) { recompute_at_end (); @@ -857,19 +827,19 @@ Region::modify_end (nframes_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 (); @@ -878,32 +848,27 @@ 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) { - frameoffset_t start_shift; framepos_t new_start; if (locked()) { return; } - if (position > _position) { - start_shift = position - _position; - } else { - start_shift = -(_position - position); - } + frameoffset_t const start_shift = position - _position; if (start_shift > 0) { - if (_start > max_frames - start_shift) { - new_start = max_frames; + if (_start > max_framepos - start_shift) { + new_start = max_framepos; } else { new_start = _start + start_shift; } } else if (start_shift < 0) { - if (_start < -start_shift) { + if (_start < -start_shift && !can_trim_start_before_source_start ()) { new_start = 0; } else { new_start = _start + start_shift; @@ -920,24 +885,34 @@ Region::trim_to_internal (framepos_t position, framecnt_t length, void */*src*/) PropertyChange what_changed; if (_start != new_start) { - _start = new_start; + set_start_internal (new_start); what_changed.add (Properties::start); } - if (_length != length) { - if (!property_changes_suspended()) { - _last_length = _length; - } - _length = 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; } - _position = position; + set_position_internal (position, true); 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; @@ -1013,9 +988,13 @@ Region::set_position_locked (bool yn) } } +/** Set the region's sync point. + * @param absolute_pos Session time. + */ void Region::set_sync_position (framepos_t absolute_pos) { + /* position within our file */ framepos_t const file_pos = _start + (absolute_pos - _position); if (file_pos != _sync_position) { @@ -1024,6 +1003,7 @@ Region::set_sync_position (framepos_t absolute_pos) if (!property_changes_suspended()) { maybe_uncopy (); } + send_change (Properties::sync_position); } } @@ -1036,15 +1016,15 @@ Region::clear_sync_position () if (!property_changes_suspended()) { maybe_uncopy (); } + send_change (Properties::sync_position); } } -framepos_t +/* @return the sync point relative the first frame of the region */ +frameoffset_t Region::sync_offset (int& dir) const { - /* returns the sync point relative the first frame of the region */ - if (sync_marked()) { if (_sync_position > _start) { dir = 1; @@ -1074,7 +1054,7 @@ Region::adjust_to_sync (framepos_t pos) const pos = 0; } } else { - if (max_frames - pos > offset) { + if (max_framepos - pos > offset) { pos += offset; } } @@ -1082,13 +1062,15 @@ Region::adjust_to_sync (framepos_t pos) const return pos; } +/** @return Sync position in session time */ framepos_t Region::sync_position() const { if (sync_marked()) { - return _sync_position; + return _position - _start + _sync_position; } else { - return _start; + /* if sync has not been marked, use the start of the region */ + return _position; } } @@ -1132,11 +1114,7 @@ Region::lower_to_bottom () void Region::set_layer (layer_t l) { - if (_layer != l) { - _layer = l; - - send_change (Properties::layer); - } + _layer = l; } XMLNode& @@ -1150,7 +1128,7 @@ Region::state () add_properties (*node); - _id.print (buf, sizeof (buf)); + id().print (buf, sizeof (buf)); node->add_property ("id", buf); node->add_property ("type", _type.to_string()); @@ -1191,6 +1169,28 @@ Region::state () node->add_property (buf2, buf); } + /* Only store nested sources for the whole-file region that acts + as the parent/root of all regions using it. + */ + + if (_whole_file && 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); } @@ -1212,15 +1212,15 @@ Region::set_state (const XMLNode& node, int version) } int -Region::_set_state (const XMLNode& node, int version, PropertyChange& what_changed, bool send) +Region::_set_state (const XMLNode& node, int /*version*/, PropertyChange& what_changed, bool send) { const XMLProperty* prop; + Stateful::save_extra_xml (node); + what_changed = set_values (node); - if ((prop = node.property (X_("id")))) { - _id = prop->value(); - } + set_id (node); if (_position_lock_style == MusicTime) { if ((prop = node.property ("bbt-position")) == 0) { @@ -1242,37 +1242,22 @@ Region::_set_state (const XMLNode& node, int version, PropertyChange& what_chang 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; } @@ -1280,7 +1265,7 @@ Region::_set_state (const XMLNode& node, int version, PropertyChange& what_chang void Region::suspend_property_changes () { - Stateful::suspend_property_changes (); + Stateful::suspend_property_changes (); _last_length = _length; _last_position = _position; } @@ -1303,10 +1288,10 @@ Region::send_change (const PropertyChange& what_changed) return; } - Stateful::send_change (what_changed); + Stateful::send_change (what_changed); + + if (!Stateful::property_changes_suspended()) { - if (!_no_property_changes) { - /* Try and send a shared_pointer unless this is part of the constructor. If so, do nothing. */ @@ -1320,16 +1305,10 @@ Region::send_change (const PropertyChange& what_changed) } } -void -Region::set_last_layer_op (uint64_t when) -{ - _last_layer_op = when; -} - bool Region::overlap_equivalent (boost::shared_ptr other) const { - return coverage (other->first_frame(), other->last_frame()) != OverlapNone; + return coverage (other->first_frame(), other->last_frame()) != Evoral::OverlapNone; } bool @@ -1356,7 +1335,7 @@ Region::region_list_equivalent (boost::shared_ptr other) const void Region::source_deleted (boost::weak_ptr) { - drop_sources (); + drop_sources (); if (!_session.deletion_in_progress()) { /* this is a very special case: at least one of the region's @@ -1387,16 +1366,16 @@ Region::master_source_names () void Region::set_master_sources (const SourceList& srcs) { - for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) { - (*i)->dec_use_count (); - } + for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) { + (*i)->dec_use_count (); + } _master_sources = srcs; assert (_sources.size() == _master_sources.size()); - for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) { - (*i)->inc_use_count (); - } + for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) { + (*i)->inc_use_count (); + } } bool @@ -1404,11 +1383,11 @@ 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; - } + + if ((_sources.size() != other->_sources.size()) || + (_master_sources.size() != other->_master_sources.size())) { + return false; + } SourceList::const_iterator i; SourceList::const_iterator io; @@ -1428,6 +1407,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 { @@ -1435,15 +1435,24 @@ Region::uses_source (boost::shared_ptr source) const if (*i == source) { return true; } + + boost::shared_ptr ps = boost::dynamic_pointer_cast (*i); + + if (ps) { + if (ps->playlist()->uses_source (source)) { + return true; + } + } } + return false; } -sframes_t +framecnt_t Region::source_length(uint32_t n) const { - assert (n < _sources.size()); - return _sources[n]->length(_position - _start); + assert (n < _sources.size()); + return _sources[n]->length (_position - _start); } bool @@ -1530,9 +1539,9 @@ Region::get_parent() const } int -Region::apply (Filter& filter) +Region::apply (Filter& filter, Progress* progress) { - return filter.run (shared_from_this()); + return filter.run (shared_from_this(), progress); } @@ -1541,24 +1550,24 @@ Region::invalidate_transients () { _valid_transients = false; _transients.clear (); - + send_change (PropertyChange (Properties::valid_transients)); } void Region::drop_sources () { - for (SourceList::const_iterator i = _sources.begin (); i != _sources.end(); ++i) { - (*i)->dec_use_count (); - } + for (SourceList::const_iterator i = _sources.begin (); i != _sources.end(); ++i) { + (*i)->dec_use_count (); + } _sources.clear (); - for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) { - (*i)->dec_use_count (); - } + for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) { + (*i)->dec_use_count (); + } - _master_sources.clear (); + _master_sources.clear (); } void @@ -1569,32 +1578,105 @@ Region::use_sources (SourceList const & s) for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) { _sources.push_back (*i); - (*i)->inc_use_count (); + (*i)->inc_use_count (); _master_sources.push_back (*i); - (*i)->inc_use_count (); + (*i)->inc_use_count (); - /* connect only once to DropReferences, even if sources are replicated - */ + /* connect only once to DropReferences, even if sources are replicated + */ if (unique_srcs.find (*i) == unique_srcs.end ()) { unique_srcs.insert (*i); - (*i)->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr(*i))); - } + (*i)->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr(*i))); + } + } +} + +Trimmable::CanTrim +Region::can_trim () const +{ + CanTrim ct = CanTrim (0); + + if (locked()) { + return ct; + } + + /* if not locked, we can always move the front later, and the end earlier + */ + + ct = CanTrim (ct | FrontTrimLater | EndTrimEarlier); + + if (start() != 0 || can_trim_start_before_source_start ()) { + ct = CanTrim (ct | FrontTrimEarlier); + } + + if (!_sources.empty()) { + if ((start() + length()) < _sources.front()->length (0)) { + ct = CanTrim (ct | EndTrimLater); + } } + + return ct; } -PropertyList* -Region::property_factory (const XMLNode& history_node) const +uint32_t +Region::max_source_level () const { - PropertyList* prop_list = new PropertyList; + uint32_t lvl = 0; - for (OwnedPropertyList::const_iterator i = _properties->begin(); i != _properties->end(); ++i) { - PropertyBase* prop = i->second->maybe_clone_self_if_found_in_history_node (history_node); + for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) { + lvl = max (lvl, (*i)->level()); + } - if (prop) { - prop_list->add (prop); - } - } + return lvl; +} - return prop_list; +bool +Region::is_compound () const +{ + return max_source_level() > 0; } + +void +Region::post_set (const PropertyChange& pc) +{ + if (pc.contains (Properties::position)) { + recompute_position_from_lock_style (); + } +} + +void +Region::set_start_internal (framecnt_t s) +{ + _start = s; +} + +framepos_t +Region::earliest_possible_position () const +{ + if (_start > _position) { + return 0; + } else { + return _position - _start; + } +} + +framecnt_t +Region::latest_possible_frame () const +{ + framecnt_t minlen = max_framecnt; + + for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) { + /* non-audio regions have a length that may vary based on their + * position, so we have to pass it in the call. + */ + minlen = min (minlen, (*i)->length (_position)); + } + + /* the latest possible last frame is determined by the current + * position, plus the shortest source extent past _start. + */ + + return _position + (minlen - _start) - 1; +} +