2 Copyright (C) 2000-2003 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include <sigc++/bind.h>
26 #include <sigc++/class_slot.h>
28 #include <glibmm/thread.h>
29 #include <pbd/xml++.h>
30 #include <pbd/stacktrace.h>
32 #include <ardour/region.h>
33 #include <ardour/playlist.h>
34 #include <ardour/session.h>
35 #include <ardour/source.h>
36 #include <ardour/region_factory.h>
37 #include <ardour/filter.h>
42 using namespace ARDOUR;
45 Change Region::FadeChanged = ARDOUR::new_change ();
46 Change Region::SyncOffsetChanged = ARDOUR::new_change ();
47 Change Region::MuteChanged = ARDOUR::new_change ();
48 Change Region::OpacityChanged = ARDOUR::new_change ();
49 Change Region::LockChanged = ARDOUR::new_change ();
50 Change Region::LayerChanged = ARDOUR::new_change ();
51 Change Region::HiddenChanged = ARDOUR::new_change ();
54 /* derived-from-derived constructor (no sources in constructor) */
55 Region::Region (Session& s, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
56 : Automatable(s, name)
62 , _sync_position(_start)
64 , _first_edit(EditChangesNothing)
67 , _pending_changed(Change (0))
70 /* no sources at this point */
74 /** Basic Region constructor (single source) */
75 Region::Region (boost::shared_ptr<Source> src, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
76 : Automatable(src->session(), name)
82 , _sync_position(_start)
84 , _first_edit(EditChangesNothing)
86 , _ancestral_start (start)
87 , _ancestral_length (length)
90 , _pending_changed(Change (0))
93 _sources.push_back (src);
94 _master_sources.push_back (src);
96 src->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), src));
98 assert(_sources.size() > 0);
101 /** Basic Region constructor (many sources) */
102 Region::Region (SourceList& srcs, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
103 : Automatable(srcs.front()->session(), name)
109 , _sync_position(_start)
111 , _first_edit(EditChangesNothing)
113 , _read_data_count(0)
114 , _pending_changed(Change (0))
118 set<boost::shared_ptr<Source> > unique_srcs;
120 for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) {
121 _sources.push_back (*i);
122 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
123 unique_srcs.insert (*i);
126 for (SourceList::iterator i = srcs.begin(); i != srcs.end(); ++i) {
127 _master_sources.push_back (*i);
128 if (unique_srcs.find (*i) == unique_srcs.end()) {
129 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
133 assert(_sources.size() > 0);
136 /** Create a new Region from part of an existing one */
137 Region::Region (boost::shared_ptr<const Region> other, nframes_t offset, nframes_t length, const string& name, layer_t layer, Flag flags)
138 : Automatable(other->session(), name)
139 , _type(other->data_type())
140 , _flags(Flag(flags & ~(Locked|PositionLocked|WholeFile|Hidden)))
141 , _start(other->_start + offset)
144 , _sync_position(_start)
146 , _first_edit(EditChangesNothing)
148 , _ancestral_start (other->_ancestral_start + offset)
149 , _ancestral_length (length)
151 , _read_data_count(0)
152 , _pending_changed(Change (0))
155 if (other->_sync_position < offset)
156 _sync_position = other->_sync_position;
158 set<boost::shared_ptr<Source> > unique_srcs;
160 for (SourceList::const_iterator i= other->_sources.begin(); i != other->_sources.end(); ++i) {
161 _sources.push_back (*i);
162 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
163 unique_srcs.insert (*i);
166 if (other->_sync_position < offset) {
167 _sync_position = other->_sync_position;
170 for (SourceList::const_iterator i = other->_master_sources.begin(); i != other->_master_sources.end(); ++i) {
171 if (unique_srcs.find (*i) == unique_srcs.end()) {
172 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
174 _master_sources.push_back (*i);
177 assert(_sources.size() > 0);
180 /** Pure copy constructor */
181 Region::Region (boost::shared_ptr<const Region> other)
182 : Automatable(other->session(), other->name())
183 , _type(other->data_type())
184 , _flags(Flag(other->_flags & ~(Locked|PositionLocked)))
185 , _start(other->_start)
186 , _length(other->_length)
187 , _position(other->_position)
188 , _sync_position(other->_sync_position)
189 , _layer(other->_layer)
190 , _first_edit(EditChangesID)
192 , _ancestral_start (_start)
193 , _ancestral_length (_length)
195 , _read_data_count(0)
196 , _pending_changed(Change(0))
197 , _last_layer_op(other->_last_layer_op)
199 other->_first_edit = EditChangesName;
201 if (other->_extra_xml) {
202 _extra_xml = new XMLNode (*other->_extra_xml);
207 set<boost::shared_ptr<Source> > unique_srcs;
209 for (SourceList::const_iterator i = other->_sources.begin(); i != other->_sources.end(); ++i) {
210 _sources.push_back (*i);
211 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
212 unique_srcs.insert (*i);
215 for (SourceList::const_iterator i = other->_master_sources.begin(); i != other->_master_sources.end(); ++i) {
216 _master_sources.push_back (*i);
217 if (unique_srcs.find (*i) == unique_srcs.end()) {
218 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
222 assert(_sources.size() > 0);
225 Region::Region (SourceList& srcs, const XMLNode& node)
226 : Automatable(srcs.front()->session(), X_("error: XML did not reset this"))
227 , _type(DataType::NIL) // to be loaded from XML
232 , _sync_position(_start)
234 , _first_edit(EditChangesNothing)
236 , _read_data_count(0)
237 , _pending_changed(Change(0))
240 set<boost::shared_ptr<Source> > unique_srcs;
242 for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) {
243 _sources.push_back (*i);
244 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
245 unique_srcs.insert (*i);
248 for (SourceList::iterator i = srcs.begin(); i != srcs.end(); ++i) {
249 _master_sources.push_back (*i);
250 if (unique_srcs.find (*i) == unique_srcs.end()) {
251 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
255 if (set_state (node)) {
256 throw failed_constructor();
259 assert(_type != DataType::NIL);
260 assert(_sources.size() > 0);
263 Region::Region (boost::shared_ptr<Source> src, const XMLNode& node)
264 : Automatable(src->session(), X_("error: XML did not reset this"))
265 , _type(DataType::NIL)
270 , _sync_position(_start)
272 , _first_edit(EditChangesNothing)
274 , _read_data_count(0)
275 , _pending_changed(Change(0))
278 _sources.push_back (src);
280 if (set_state (node)) {
281 throw failed_constructor();
284 assert(_type != DataType::NIL);
285 assert(_sources.size() > 0);
290 boost::shared_ptr<Playlist> pl (playlist());
293 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
294 (*i)->remove_playlist (pl);
299 GoingAway (); /* EMIT SIGNAL */
303 Region::set_playlist (boost::weak_ptr<Playlist> wpl)
305 boost::shared_ptr<Playlist> old_playlist = (_playlist.lock());
307 boost::shared_ptr<Playlist> pl (wpl.lock());
309 if (old_playlist == pl) {
317 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
318 (*i)->remove_playlist (_playlist);
319 (*i)->add_playlist (pl);
322 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
323 (*i)->add_playlist (pl);
328 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
329 (*i)->remove_playlist (old_playlist);
336 Region::set_name (const std::string& str)
339 SessionObject::set_name(str); // EMIT SIGNAL NameChanged()
340 assert(_name == str);
341 send_change (ARDOUR::NameChanged);
348 Region::set_length (nframes_t len, void *src)
350 if (_flags & Locked) {
354 if (_length != len && len != 0) {
356 /* check that the current _position wouldn't make the new
360 if (max_frames - len < _position) {
364 if (!verify_length (len)) {
369 _last_length = _length;
372 _flags = Region::Flag (_flags & ~WholeFile);
381 send_change (LengthChanged);
386 Region::maybe_uncopy ()
391 Region::first_edit ()
393 boost::shared_ptr<Playlist> pl (playlist());
395 if (_first_edit != EditChangesNothing && pl) {
397 _name = pl->session().new_region_name (_name);
398 _first_edit = EditChangesNothing;
400 send_change (ARDOUR::NameChanged);
401 RegionFactory::CheckNewRegion (shared_from_this());
406 Region::at_natural_position () const
408 boost::shared_ptr<Playlist> pl (playlist());
414 boost::shared_ptr<Region> whole_file_region = get_parent();
416 if (whole_file_region) {
417 if (_position == whole_file_region->position() + _start) {
426 Region::move_to_natural_position (void *src)
428 boost::shared_ptr<Playlist> pl (playlist());
434 boost::shared_ptr<Region> whole_file_region = get_parent();
436 if (whole_file_region) {
437 set_position (whole_file_region->position() + _start, src);
442 Region::special_set_position (nframes_t pos)
444 /* this is used when creating a whole file region as
445 a way to store its "natural" or "captured" position.
448 _position = _position;
453 Region::set_position (nframes_t pos, void *src)
459 if (_position != pos) {
460 _last_position = _position;
463 /* check that the new _position wouldn't make the current
464 length impossible - if so, change the length.
466 XXX is this the right thing to do?
469 if (max_frames - _length < _position) {
470 _last_length = _length;
471 _length = max_frames - _position;
475 /* do this even if the position is the same. this helps out
476 a GUI that has moved its representation already.
479 send_change (PositionChanged);
483 Region::set_position_on_top (nframes_t pos, void *src)
485 if (_flags & Locked) {
489 if (_position != pos) {
490 _last_position = _position;
494 boost::shared_ptr<Playlist> pl (playlist());
497 pl->raise_region_to_top (shared_from_this ());
500 /* do this even if the position is the same. this helps out
501 a GUI that has moved its representation already.
504 send_change (PositionChanged);
508 Region::nudge_position (nframes64_t n, void *src)
510 if (_flags & Locked) {
518 _last_position = _position;
521 if (_position > max_frames - n) {
522 _position = max_frames;
527 if (_position < (nframes_t) -n) {
534 send_change (PositionChanged);
538 Region::set_ancestral_data (nframes64_t s, nframes64_t l, float st, float sh)
540 _ancestral_length = l;
541 _ancestral_start = s;
547 Region::set_start (nframes_t pos, void *src)
549 if (_flags & (Locked|PositionLocked)) {
552 /* This just sets the start, nothing else. It effectively shifts
553 the contents of the Region within the overall extent of the Source,
554 without changing the Region's position or length
559 if (!verify_start (pos)) {
564 _flags = Region::Flag (_flags & ~WholeFile);
567 send_change (StartChanged);
572 Region::trim_start (nframes_t new_position, void *src)
574 if (_flags & (Locked|PositionLocked)) {
580 if (new_position > _position) {
581 start_shift = new_position - _position;
583 start_shift = -(_position - new_position);
586 if (start_shift > 0) {
588 if (_start > max_frames - start_shift) {
589 new_start = max_frames;
591 new_start = _start + start_shift;
594 if (!verify_start (new_start)) {
598 } else if (start_shift < 0) {
600 if (_start < (nframes_t) -start_shift) {
603 new_start = _start + start_shift;
609 if (new_start == _start) {
614 _flags = Region::Flag (_flags & ~WholeFile);
617 send_change (StartChanged);
621 Region::trim_front (nframes_t new_position, void *src)
623 if (_flags & Locked) {
627 nframes_t end = last_frame();
628 nframes_t source_zero;
630 if (_position > _start) {
631 source_zero = _position - _start;
633 source_zero = 0; // its actually negative, but this will work for us
636 if (new_position < end) { /* can't trim it zero or negative length */
640 /* can't trim it back passed where source position zero is located */
642 new_position = max (new_position, source_zero);
645 if (new_position > _position) {
646 newlen = _length - (new_position - _position);
648 newlen = _length + (_position - new_position);
651 trim_to_internal (new_position, newlen, src);
653 recompute_at_start ();
659 Region::trim_end (nframes_t new_endpoint, void *src)
661 if (_flags & Locked) {
665 if (new_endpoint > _position) {
666 trim_to_internal (_position, new_endpoint - _position, this);
674 Region::trim_to (nframes_t position, nframes_t length, void *src)
676 if (_flags & Locked) {
680 trim_to_internal (position, length, src);
683 recompute_at_start ();
689 Region::trim_to_internal (nframes_t position, nframes_t length, void *src)
694 if (_flags & Locked) {
698 if (position > _position) {
699 start_shift = position - _position;
701 start_shift = -(_position - position);
704 if (start_shift > 0) {
706 if (_start > max_frames - start_shift) {
707 new_start = max_frames;
709 new_start = _start + start_shift;
713 } else if (start_shift < 0) {
715 if (_start < (nframes_t) -start_shift) {
718 new_start = _start + start_shift;
724 if (!verify_start_and_length (new_start, length)) {
728 Change what_changed = Change (0);
730 if (_start != new_start) {
732 what_changed = Change (what_changed|StartChanged);
734 if (_length != length) {
736 _last_length = _length;
739 what_changed = Change (what_changed|LengthChanged);
741 if (_position != position) {
743 _last_position = _position;
745 _position = position;
746 what_changed = Change (what_changed|PositionChanged);
749 _flags = Region::Flag (_flags & ~WholeFile);
751 if (what_changed & (StartChanged|LengthChanged)) {
756 send_change (what_changed);
761 Region::set_hidden (bool yn)
763 if (hidden() != yn) {
766 _flags = Flag (_flags|Hidden);
768 _flags = Flag (_flags & ~Hidden);
771 send_change (HiddenChanged);
776 Region::set_muted (bool yn)
781 _flags = Flag (_flags|Muted);
783 _flags = Flag (_flags & ~Muted);
786 send_change (MuteChanged);
791 Region::set_opaque (bool yn)
793 if (opaque() != yn) {
795 _flags = Flag (_flags|Opaque);
797 _flags = Flag (_flags & ~Opaque);
799 send_change (OpacityChanged);
804 Region::set_locked (bool yn)
806 if (locked() != yn) {
808 _flags = Flag (_flags|Locked);
810 _flags = Flag (_flags & ~Locked);
812 send_change (LockChanged);
817 Region::set_position_locked (bool yn)
819 if (position_locked() != yn) {
821 _flags = Flag (_flags|PositionLocked);
823 _flags = Flag (_flags & ~PositionLocked);
825 send_change (LockChanged);
830 Region::set_sync_position (nframes_t absolute_pos)
834 file_pos = _start + (absolute_pos - _position);
836 if (file_pos != _sync_position) {
838 _sync_position = file_pos;
839 _flags = Flag (_flags|SyncMarked);
844 send_change (SyncOffsetChanged);
849 Region::clear_sync_position ()
851 if (_flags & SyncMarked) {
852 _flags = Flag (_flags & ~SyncMarked);
857 send_change (SyncOffsetChanged);
862 Region::sync_offset (int& dir) const
864 /* returns the sync point relative the first frame of the region */
866 if (_flags & SyncMarked) {
867 if (_sync_position > _start) {
869 return _sync_position - _start;
872 return _start - _sync_position;
881 Region::adjust_to_sync (nframes_t pos)
884 nframes_t offset = sync_offset (sync_dir);
886 // cerr << "adjusting pos = " << pos << " to sync at " << _sync_position << " offset = " << offset << " with dir = " << sync_dir << endl;
889 if (max_frames - pos > offset) {
904 Region::sync_position() const
906 if (_flags & SyncMarked) {
907 return _sync_position;
916 boost::shared_ptr<Playlist> pl (playlist());
918 pl->raise_region (shared_from_this ());
925 boost::shared_ptr<Playlist> pl (playlist());
927 pl->lower_region (shared_from_this ());
933 Region::raise_to_top ()
935 boost::shared_ptr<Playlist> pl (playlist());
937 pl->raise_region_to_top (shared_from_this());
942 Region::lower_to_bottom ()
944 boost::shared_ptr<Playlist> pl (playlist());
946 pl->lower_region_to_bottom (shared_from_this());
951 Region::set_layer (layer_t l)
956 send_change (LayerChanged);
961 Region::state (bool full_state)
963 XMLNode *node = new XMLNode ("Region");
965 const char* fe = NULL;
967 _id.print (buf, sizeof (buf));
968 node->add_property ("id", buf);
969 node->add_property ("name", _name);
970 node->add_property ("type", _type.to_string());
971 snprintf (buf, sizeof (buf), "%u", _start);
972 node->add_property ("start", buf);
973 snprintf (buf, sizeof (buf), "%u", _length);
974 node->add_property ("length", buf);
975 snprintf (buf, sizeof (buf), "%u", _position);
976 node->add_property ("position", buf);
977 snprintf (buf, sizeof (buf), "%lu", _ancestral_start);
978 node->add_property ("ancestral-start", buf);
979 snprintf (buf, sizeof (buf), "%lu", _ancestral_length);
980 node->add_property ("ancestral-length", buf);
981 snprintf (buf, sizeof (buf), "%.12g", _stretch);
982 node->add_property ("stretch", buf);
983 snprintf (buf, sizeof (buf), "%.12g", _shift);
984 node->add_property ("shift", buf);
986 switch (_first_edit) {
987 case EditChangesNothing:
990 case EditChangesName:
996 default: /* should be unreachable but makes g++ happy */
1001 node->add_property ("first_edit", fe);
1003 /* note: flags are stored by derived classes */
1005 snprintf (buf, sizeof (buf), "%d", (int) _layer);
1006 node->add_property ("layer", buf);
1007 snprintf (buf, sizeof (buf), "%" PRIu32, _sync_position);
1008 node->add_property ("sync-position", buf);
1014 Region::get_state ()
1016 return state (true);
1020 Region::set_live_state (const XMLNode& node, Change& what_changed, bool send)
1022 const XMLNodeList& nlist = node.children();
1023 const XMLProperty *prop;
1026 /* this is responsible for setting those aspects of Region state
1027 that are mutable after construction.
1030 if ((prop = node.property ("name")) == 0) {
1031 error << _("XMLNode describing a Region is incomplete (no name)") << endmsg;
1035 _name = prop->value();
1037 if ((prop = node.property ("type")) == 0) {
1038 _type = DataType::AUDIO;
1040 _type = DataType(prop->value());
1043 if ((prop = node.property ("start")) != 0) {
1044 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1045 if (val != _start) {
1046 what_changed = Change (what_changed|StartChanged);
1053 if ((prop = node.property ("length")) != 0) {
1054 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1055 if (val != _length) {
1056 what_changed = Change (what_changed|LengthChanged);
1057 _last_length = _length;
1061 _last_length = _length;
1065 if ((prop = node.property ("position")) != 0) {
1066 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1067 if (val != _position) {
1068 what_changed = Change (what_changed|PositionChanged);
1069 _last_position = _position;
1073 _last_position = _position;
1077 if ((prop = node.property ("layer")) != 0) {
1079 x = (layer_t) atoi (prop->value().c_str());
1081 what_changed = Change (what_changed|LayerChanged);
1088 if ((prop = node.property ("sync-position")) != 0) {
1089 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1090 if (val != _sync_position) {
1091 what_changed = Change (what_changed|SyncOffsetChanged);
1092 _sync_position = val;
1095 _sync_position = _start;
1098 /* XXX FIRST EDIT !!! */
1100 /* these 3 properties never change as a result of any editing */
1102 if ((prop = node.property ("ancestral-start")) != 0) {
1103 _ancestral_start = atoi (prop->value());
1105 _ancestral_start = _start;
1108 if ((prop = node.property ("ancestral-length")) != 0) {
1109 _ancestral_length = atoi (prop->value());
1111 _ancestral_length = _length;
1114 if ((prop = node.property ("stretch")) != 0) {
1115 _stretch = atof (prop->value());
1120 if ((prop = node.property ("shift")) != 0) {
1121 _shift = atof (prop->value());
1126 /* note: derived classes set flags */
1133 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1139 if (child->name () == "extra") {
1140 _extra_xml = new XMLNode (*child);
1146 send_change (what_changed);
1153 Region::set_state (const XMLNode& node)
1155 const XMLProperty *prop;
1156 Change what_changed = Change (0);
1158 /* ID is not allowed to change, ever */
1160 if ((prop = node.property ("id")) == 0) {
1161 error << _("Session: XMLNode describing a Region is incomplete (no id)") << endmsg;
1165 _id = prop->value();
1167 _first_edit = EditChangesNothing;
1169 set_live_state (node, what_changed, true);
1178 _last_length = _length;
1179 _last_position = _position;
1183 Region::thaw (const string& why)
1185 Change what_changed = Change (0);
1188 Glib::Mutex::Lock lm (_lock);
1190 if (_frozen && --_frozen > 0) {
1194 if (_pending_changed) {
1195 what_changed = _pending_changed;
1196 _pending_changed = Change (0);
1200 if (what_changed == Change (0)) {
1204 if (what_changed & LengthChanged) {
1205 if (what_changed & PositionChanged) {
1206 recompute_at_start ();
1208 recompute_at_end ();
1211 StateChanged (what_changed);
1215 Region::send_change (Change what_changed)
1218 Glib::Mutex::Lock lm (_lock);
1220 _pending_changed = Change (_pending_changed|what_changed);
1225 StateChanged (what_changed);
1229 Region::set_last_layer_op (uint64_t when)
1231 _last_layer_op = when;
1235 Region::overlap_equivalent (boost::shared_ptr<const Region> other) const
1237 return coverage (other->first_frame(), other->last_frame()) != OverlapNone;
1241 Region::equivalent (boost::shared_ptr<const Region> other) const
1243 return _start == other->_start &&
1244 _position == other->_position &&
1245 _length == other->_length;
1249 Region::size_equivalent (boost::shared_ptr<const Region> other) const
1251 return _start == other->_start &&
1252 _length == other->_length;
1256 Region::region_list_equivalent (boost::shared_ptr<const Region> other) const
1258 return size_equivalent (other) && source_equivalent (other) && _name == other->_name;
1262 Region::source_deleted (boost::shared_ptr<Source>)
1268 Region::master_source_names ()
1270 SourceList::iterator i;
1272 vector<string> names;
1273 for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1274 names.push_back((*i)->name());
1281 Region::set_master_sources (SourceList& srcs)
1283 _master_sources = srcs;
1287 Region::source_equivalent (boost::shared_ptr<const Region> other) const
1292 SourceList::const_iterator i;
1293 SourceList::const_iterator io;
1295 for (i = _sources.begin(), io = other->_sources.begin(); i != _sources.end() && io != other->_sources.end(); ++i, ++io) {
1296 if ((*i)->id() != (*io)->id()) {
1301 for (i = _master_sources.begin(), io = other->_master_sources.begin(); i != _master_sources.end() && io != other->_master_sources.end(); ++i, ++io) {
1302 if ((*i)->id() != (*io)->id()) {
1311 Region::verify_length (nframes_t len)
1313 if (source() && (source()->destructive() || source()->length_mutable())) {
1317 nframes_t maxlen = 0;
1319 for (uint32_t n=0; n < _sources.size(); ++n) {
1320 maxlen = max (maxlen, _sources[n]->length() - _start);
1323 len = min (len, maxlen);
1329 Region::verify_start_and_length (nframes_t new_start, nframes_t& new_length)
1331 if (source() && (source()->destructive() || source()->length_mutable())) {
1335 nframes_t maxlen = 0;
1337 for (uint32_t n=0; n < _sources.size(); ++n) {
1338 maxlen = max (maxlen, _sources[n]->length() - new_start);
1341 new_length = min (new_length, maxlen);
1347 Region::verify_start (nframes_t pos)
1349 if (source() && (source()->destructive() || source()->length_mutable())) {
1353 for (uint32_t n=0; n < _sources.size(); ++n) {
1354 if (pos > _sources[n]->length() - _length) {
1362 Region::verify_start_mutable (nframes_t& new_start)
1364 if (source() && (source()->destructive() || source()->length_mutable())) {
1368 for (uint32_t n=0; n < _sources.size(); ++n) {
1369 if (new_start > _sources[n]->length() - _length) {
1370 new_start = _sources[n]->length() - _length;
1376 boost::shared_ptr<Region>
1377 Region::get_parent() const
1379 boost::shared_ptr<Playlist> pl (playlist());
1382 boost::shared_ptr<Region> r;
1383 boost::shared_ptr<Region const> grrr2 = boost::dynamic_pointer_cast<Region const> (shared_from_this());
1385 if (grrr2 && (r = pl->session().find_whole_file_parent (grrr2))) {
1386 return boost::static_pointer_cast<Region> (r);
1390 return boost::shared_ptr<Region>();
1394 Region::apply (Filter& filter)
1396 return filter.run (shared_from_this());