X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fregion.cc;h=ba18cbc62db3d440efe873c3f558e3780d3c2824;hb=24b514797ab265bf48eb93d6c2c812ce5232fdba;hp=952e8b5c9cd8a3ecb1bbda4b062fa790da782035;hpb=72393f101ba2cae980838dd0d857719719ecc3d7;p=ardour.git diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc index 952e8b5c9c..ba18cbc62d 100644 --- a/libs/ardour/region.cc +++ b/libs/ardour/region.cc @@ -36,6 +36,7 @@ #include "ardour/session.h" #include "ardour/source.h" #include "ardour/tempo.h" +#include "ardour/transient_detector.h" #include "i18n.h" @@ -49,6 +50,7 @@ namespace ARDOUR { PBD::PropertyDescriptor muted; PBD::PropertyDescriptor opaque; PBD::PropertyDescriptor locked; + PBD::PropertyDescriptor video_locked; PBD::PropertyDescriptor automatic; PBD::PropertyDescriptor whole_file; PBD::PropertyDescriptor import; @@ -79,53 +81,55 @@ 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::video_locked.property_id = g_quark_from_static_string (X_("video-locked")); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for video-locked = %1\n", Properties::video_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)); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for layering_index = %1\n", Properties::layering_index.property_id)); } void @@ -136,6 +140,7 @@ Region::register_properties () add_property (_muted); add_property (_opaque); add_property (_locked); + add_property (_video_locked); add_property (_automatic); add_property (_whole_file); add_property (_import); @@ -167,9 +172,13 @@ Region::register_properties () , _length (Properties::length, (l)) \ , _position (Properties::position, 0) \ , _sync_position (Properties::sync_position, (s)) \ + , _transient_user_start (0) \ + , _transient_analysis_start (0) \ + , _transient_analysis_end (0) \ , _muted (Properties::muted, false) \ , _opaque (Properties::opaque, true) \ , _locked (Properties::locked, false) \ + , _video_locked (Properties::video_locked, false) \ , _automatic (Properties::automatic, false) \ , _whole_file (Properties::whole_file, false) \ , _import (Properties::import, false) \ @@ -192,9 +201,15 @@ Region::register_properties () , _length(Properties::length, other->_length) \ , _position(Properties::position, other->_position) \ , _sync_position(Properties::sync_position, other->_sync_position) \ - , _muted (Properties::muted, other->_muted) \ + , _user_transients (other->_user_transients) \ + , _transient_user_start (other->_transient_user_start) \ + , _transients (other->_transients) \ + , _transient_analysis_start (other->_transient_analysis_start) \ + , _transient_analysis_end (other->_transient_analysis_end) \ + , _muted (Properties::muted, other->_muted) \ , _opaque (Properties::opaque, other->_opaque) \ , _locked (Properties::locked, other->_locked) \ + , _video_locked (Properties::video_locked, other->_video_locked) \ , _automatic (Properties::automatic, other->_automatic) \ , _whole_file (Properties::whole_file, other->_whole_file) \ , _import (Properties::import, other->_import) \ @@ -258,17 +273,19 @@ Region::Region (boost::shared_ptr other) /* override state that may have been incorrectly inherited from the other region */ - _position = 0; + _position = other->_position; _locked = false; _whole_file = false; _hidden = false; use_sources (other->_sources); + set_master_sources (other->_master_sources); _position_lock_style = other->_position_lock_style; _first_edit = other->_first_edit; - _start = 0; // It seems strange _start is not inherited here? + _start = other->_start; + _beat = other->_beat; /* 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 @@ -295,17 +312,6 @@ Region::Region (boost::shared_ptr other) _sync_position = _start; } - 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()); } @@ -321,6 +327,7 @@ Region::Region (boost::shared_ptr other, frameoffset_t offset) , _last_length (other->_last_length) , _last_position(other->_last_position) \ , _first_edit (EditChangesNothing) + , _beat (0.0) , _layer (other->_layer) { register_properties (); @@ -328,14 +335,16 @@ Region::Region (boost::shared_ptr other, frameoffset_t offset) /* override state that may have been incorrectly inherited from the other region */ - _position = 0; + _position = other->_position + offset; _locked = false; _whole_file = false; _hidden = false; use_sources (other->_sources); + set_master_sources (other->_master_sources); _start = other->_start + offset; + _beat = _session.tempo_map().beat_at_frame (_position); /* if the other region had a distinct sync point set, then continue to use it as best we can. @@ -354,17 +363,6 @@ Region::Region (boost::shared_ptr other, frameoffset_t offset) _sync_position = _start; } - 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()); } @@ -443,12 +441,11 @@ Region::set_length (framecnt_t len) } - _last_length = _length; set_length_internal (len); _whole_file = false; first_edit (); maybe_uncopy (); - invalidate_transients (); + maybe_invalidate_transients (); if (!property_changes_suspended()) { recompute_at_end (); @@ -461,6 +458,7 @@ Region::set_length (framecnt_t len) void Region::set_length_internal (framecnt_t len) { + _last_length = _length; _length = len; } @@ -543,7 +541,7 @@ Region::set_position_lock_style (PositionLockStyle ps) _position_lock_style = ps; if (_position_lock_style == MusicTime) { - _session.bbt_time (_position, _bbt_time); + _beat = _session.tempo_map().beat_at_frame (_position); } send_change (Properties::position_lock_style); @@ -551,7 +549,7 @@ Region::set_position_lock_style (PositionLockStyle ps) } void -Region::update_after_tempo_map_change () +Region::update_after_tempo_map_change (bool send) { boost::shared_ptr pl (playlist()); @@ -559,14 +557,16 @@ Region::update_after_tempo_map_change () return; } - TempoMap& map (_session.tempo_map()); - framepos_t pos = map.frame_time (_bbt_time); + const framepos_t pos = _session.tempo_map().frame_at_beat (_beat); 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); + + if (send) { + send_change (Properties::position); + } } void @@ -581,19 +581,34 @@ Region::set_position (framepos_t pos) /* do this even if the position is the same. this helps out a GUI that has moved its representation already. */ - send_change (Properties::position); + PropertyChange p_and_l; + + p_and_l.add (Properties::position); + /* Currently length change due to position change is only implemented + for MidiRegion (Region has no length in beats). + Notify a length change regardless (its more efficient for MidiRegions), + and when Region has a _length_beats we will need it here anyway). + */ + if (position_lock_style() == MusicTime) { + p_and_l.add (Properties::length); + } + + send_change (p_and_l); } +/** A gui may need to create a region, then place it in an initial + * position determined by the user. + * When this takes place within one gui operation, we have to reset + * _last_position to prevent an implied move. + */ void -Region::set_position_internal (framepos_t pos, bool allow_bbt_recompute) +Region::set_initial_position (framepos_t pos) { - /* 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 (!can_move()) { + return; + } + if (_position != pos) { _position = pos; @@ -608,11 +623,42 @@ Region::set_position_internal (framepos_t pos, bool allow_bbt_recompute) _length = max_framepos - _position; } + recompute_position_from_lock_style (); + /* ensure that this move doesn't cause a range move */ + _last_position = _position; + } + + + /* 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) { + _position = pos; + if (allow_bbt_recompute) { recompute_position_from_lock_style (); } + /* check that the new _position wouldn't make the current + length impossible - if so, change the length. - //invalidate_transients (); + XXX is this the right thing to do? + */ + if (max_framepos - _length < _position) { + _last_length = _length; + _length = max_framepos - _position; + } } } @@ -620,14 +666,14 @@ void Region::recompute_position_from_lock_style () { if (_position_lock_style == MusicTime) { - _session.bbt_time (_position, _bbt_time); + _beat = _session.tempo_map().beat_at_frame (_position); } } void Region::nudge_position (frameoffset_t n) { - if (locked()) { + if (locked() || video_locked()) { return; } @@ -668,7 +714,7 @@ Region::set_ancestral_data (framepos_t s, framecnt_t l, float st, float sh) void Region::set_start (framepos_t pos) { - if (locked() || position_locked()) { + if (locked() || position_locked() || video_locked()) { return; } /* This just sets the start, nothing else. It effectively shifts @@ -685,40 +731,39 @@ Region::set_start (framepos_t pos) set_start_internal (pos); _whole_file = false; first_edit (); - invalidate_transients (); + maybe_invalidate_transients (); send_change (Properties::start); } } void -Region::trim_start (framepos_t new_position) +Region::move_start (frameoffset_t distance) { - if (locked() || position_locked()) { + if (locked() || position_locked() || video_locked()) { return; } framepos_t new_start; - frameoffset_t const start_shift = new_position - _position; - if (start_shift > 0) { + if (distance > 0) { - if (_start > max_framepos - start_shift) { - new_start = max_framepos; + if (_start > max_framepos - distance) { + new_start = max_framepos; // makes no sense } else { - new_start = _start + start_shift; + new_start = _start + distance; } if (!verify_start (new_start)) { return; } - } else if (start_shift < 0) { + } else if (distance < 0) { - if (_start < -start_shift) { + if (_start < -distance) { new_start = 0; } else { - new_start = _start + start_shift; + new_start = _start + distance; } } else { @@ -730,6 +775,7 @@ Region::trim_start (framepos_t new_position) } set_start_internal (new_start); + _whole_file = false; first_edit (); @@ -773,7 +819,6 @@ Region::modify_front (framepos_t new_position, bool reset_fade) if (new_position < end) { /* can't trim it zero or negative length */ 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 */ @@ -782,10 +827,8 @@ Region::modify_front (framepos_t new_position, bool reset_fade) if (new_position > _position) { newlen = _length - (new_position - _position); - delta = -1 * (new_position - _position); } else { newlen = _length + (_position - new_position); - delta = _position - new_position; } trim_to_internal (new_position, newlen); @@ -798,9 +841,7 @@ Region::modify_front (framepos_t new_position, bool reset_fade) recompute_at_start (); } - if (_transients.size() > 0){ - adjust_transients(delta); - } + maybe_invalidate_transients (); } } @@ -889,6 +930,7 @@ Region::trim_to_internal (framepos_t position, framecnt_t length) what_changed.add (Properties::start); } + /* 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 @@ -979,6 +1021,15 @@ Region::set_locked (bool yn) } } +void +Region::set_video_locked (bool yn) +{ + if (video_locked() != yn) { + _video_locked = yn; + send_change (Properties::video_locked); + } +} + void Region::set_position_locked (bool yn) { @@ -1123,10 +1174,21 @@ Region::state () XMLNode *node = new XMLNode ("Region"); char buf[64]; char buf2[64]; - LocaleGuard lg (X_("POSIX")); + LocaleGuard lg; const char* fe = NULL; - add_properties (*node); + /* custom version of 'add_properties (*node);' + * skip values that have have dedicated save functions + * in AudioRegion::state() + */ + for (OwnedPropertyList::iterator i = _properties->begin(); i != _properties->end(); ++i) { + if (!strcmp(i->second->property_name(), (const char*)"Envelope")) continue; + if (!strcmp(i->second->property_name(), (const char*)"FadeIn")) continue; + if (!strcmp(i->second->property_name(), (const char*)"FadeOut")) continue; + if (!strcmp(i->second->property_name(), (const char*)"InverseFadeIn")) continue; + if (!strcmp(i->second->property_name(), (const char*)"InverseFadeOut")) continue; + i->second->get_value (*node); + } id().print (buf, sizeof (buf)); node->add_property ("id", buf); @@ -1152,9 +1214,8 @@ Region::state () /* note: flags are stored by derived classes */ if (_position_lock_style != AudioTime) { - stringstream str; - str << _bbt_time; - node->add_property ("bbt-position", str.str()); + snprintf (buf, sizeof(buf), "%lf", _beat); + node->add_property ("beat", buf); } for (uint32_t n=0; n < _sources.size(); ++n) { @@ -1214,7 +1275,8 @@ Region::set_state (const XMLNode& node, int version) int Region::_set_state (const XMLNode& node, int /*version*/, PropertyChange& what_changed, bool send) { - const XMLProperty* prop; + XMLProperty const * prop; + Timecode::BBT_Time bbt_time; Stateful::save_extra_xml (node); @@ -1224,14 +1286,23 @@ Region::_set_state (const XMLNode& node, int /*version*/, PropertyChange& what_c if (_position_lock_style == MusicTime) { if ((prop = node.property ("bbt-position")) == 0) { - /* missing BBT info, revert to audio time locking */ - _position_lock_style = AudioTime; + if ((prop = node.property ("beat")) == 0) { + /* missing BBT info, revert to audio time locking */ + _position_lock_style = AudioTime; + } else { + if (sscanf (prop->value().c_str(), "%lf", &_beat) != 1) { + _position_lock_style = AudioTime; + } + } + } else { if (sscanf (prop->value().c_str(), "%d|%d|%d", - &_bbt_time.bars, - &_bbt_time.beats, - &_bbt_time.ticks) != 3) { + &bbt_time.bars, + &bbt_time.beats, + &bbt_time.ticks) != 3) { _position_lock_style = AudioTime; + } else { + _beat = _session.tempo_map().beat_at_bbt (bbt_time); } } } @@ -1258,6 +1329,10 @@ Region::_set_state (const XMLNode& node, int /*version*/, PropertyChange& what_c } } + // saved property is invalid, region-transients are not saved + if (_user_transients.size() == 0){ + _valid_transients = false; + } return 0; } @@ -1447,19 +1522,75 @@ Region::source_string () const return res.str(); } +void +Region::deep_sources (std::set > & sources) const +{ + for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) { + + boost::shared_ptr ps = boost::dynamic_pointer_cast (*i); + + if (ps) { + if (sources.find (ps) == sources.end()) { + /* (Playlist)Source not currently in + accumulating set, so recurse. + */ + ps->playlist()->deep_sources (sources); + } + } + + /* add this source */ + sources.insert (*i); + } + + for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) { + + boost::shared_ptr ps = boost::dynamic_pointer_cast (*i); + + if (ps) { + if (sources.find (ps) == sources.end()) { + /* (Playlist)Source not currently in + accumulating set, so recurse. + */ + ps->playlist()->deep_sources (sources); + } + } + + /* add this source */ + sources.insert (*i); + } +} + bool -Region::uses_source (boost::shared_ptr source) const +Region::uses_source (boost::shared_ptr source, bool shallow) const { for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) { if (*i == source) { return true; } - boost::shared_ptr ps = boost::dynamic_pointer_cast (*i); + if (!shallow) { + boost::shared_ptr ps = boost::dynamic_pointer_cast (*i); - if (ps) { - if (ps->playlist()->uses_source (source)) { - return true; + if (ps) { + if (ps->playlist()->uses_source (source)) { + return true; + } + } + } + } + + for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) { + if (*i == source) { + return true; + } + + if (!shallow) { + boost::shared_ptr ps = boost::dynamic_pointer_cast (*i); + + if (ps) { + if (ps->playlist()->uses_source (source)) { + return true; + } } } } @@ -1467,6 +1598,7 @@ Region::uses_source (boost::shared_ptr source) const return false; } + framecnt_t Region::source_length(uint32_t n) const { @@ -1475,7 +1607,7 @@ Region::source_length(uint32_t n) const } bool -Region::verify_length (framecnt_t len) +Region::verify_length (framecnt_t& len) { if (source() && (source()->destructive() || source()->length_mutable())) { return true; @@ -1565,12 +1697,60 @@ Region::apply (Filter& filter, Progress* progress) void -Region::invalidate_transients () +Region::maybe_invalidate_transients () +{ + bool changed = !_onsets.empty(); + _onsets.clear (); + + if (_valid_transients || changed) { + send_change (PropertyChange (Properties::valid_transients)); + return; + } +} + +void +Region::transients (AnalysisFeatureList& afl) { - _valid_transients = false; - _transients.clear (); + int cnt = afl.empty() ? 0 : 1; - send_change (PropertyChange (Properties::valid_transients)); + Region::merge_features (afl, _onsets, _position); + Region::merge_features (afl, _user_transients, _position + _transient_user_start - _start); + if (!_onsets.empty ()) { + ++cnt; + } + if (!_user_transients.empty ()) { + ++cnt; + } + if (cnt > 1 ) { + afl.sort (); + // remove exact duplicates + TransientDetector::cleanup_transients (afl, _session.frame_rate(), 0); + } +} + +bool +Region::has_transients () const +{ + if (!_user_transients.empty ()) { + assert (_valid_transients); + return true; + } + if (!_onsets.empty ()) { + return true; + } + return false; +} + +void +Region::merge_features (AnalysisFeatureList& result, const AnalysisFeatureList& src, const frameoffset_t off) const +{ + for (AnalysisFeatureList::const_iterator x = src.begin(); x != src.end(); ++x) { + const frameoffset_t p = (*x) + off; + if (p < first_frame() || p > last_frame()) { + continue; + } + result.push_back (p); + } } void @@ -1698,4 +1878,3 @@ Region::latest_possible_frame () const return _position + (minlen - _start) - 1; } -