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>
41 using namespace ARDOUR;
44 Change Region::FadeChanged = ARDOUR::new_change ();
45 Change Region::SyncOffsetChanged = ARDOUR::new_change ();
46 Change Region::MuteChanged = ARDOUR::new_change ();
47 Change Region::OpacityChanged = ARDOUR::new_change ();
48 Change Region::LockChanged = ARDOUR::new_change ();
49 Change Region::LayerChanged = ARDOUR::new_change ();
50 Change Region::HiddenChanged = ARDOUR::new_change ();
53 /* derived-from-derived constructor (no sources in constructor) */
54 Region::Region (nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
61 , _sync_position(_start)
63 , _first_edit(EditChangesNothing)
66 , _pending_changed(Change (0))
69 /* no sources at this point */
73 /** Basic Region constructor (single source) */
74 Region::Region (boost::shared_ptr<Source> src, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
81 , _sync_position(_start)
83 , _first_edit(EditChangesNothing)
86 , _pending_changed(Change (0))
89 _sources.push_back (src);
90 _master_sources.push_back (src);
92 src->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), src));
94 assert(_sources.size() > 0);
97 /** Basic Region constructor (many sources) */
98 Region::Region (SourceList& srcs, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
105 , _sync_position(_start)
107 , _first_edit(EditChangesNothing)
109 , _read_data_count(0)
110 , _pending_changed(Change (0))
114 set<boost::shared_ptr<Source> > unique_srcs;
116 for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) {
117 _sources.push_back (*i);
118 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
119 unique_srcs.insert (*i);
122 for (SourceList::iterator i = srcs.begin(); i != srcs.end(); ++i) {
123 _master_sources.push_back (*i);
124 if (unique_srcs.find (*i) == unique_srcs.end()) {
125 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
129 assert(_sources.size() > 0);
132 /** Create a new Region from part of an existing one */
133 Region::Region (boost::shared_ptr<const Region> other, nframes_t offset, nframes_t length, const string& name, layer_t layer, Flag flags)
135 , _type(other->data_type())
136 , _flags(Flag(flags & ~(Locked|PositionLocked|WholeFile|Hidden)))
137 , _start(other->_start + offset)
140 , _sync_position(_start)
142 , _first_edit(EditChangesNothing)
144 , _read_data_count(0)
145 , _pending_changed(Change (0))
148 if (other->_sync_position < offset)
149 _sync_position = other->_sync_position;
151 set<boost::shared_ptr<Source> > unique_srcs;
153 for (SourceList::const_iterator i= other->_sources.begin(); i != other->_sources.end(); ++i) {
154 _sources.push_back (*i);
155 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
156 unique_srcs.insert (*i);
159 if (other->_sync_position < offset) {
160 _sync_position = other->_sync_position;
163 for (SourceList::const_iterator i = other->_master_sources.begin(); i != other->_master_sources.end(); ++i) {
164 if (unique_srcs.find (*i) == unique_srcs.end()) {
165 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
167 _master_sources.push_back (*i);
170 assert(_sources.size() > 0);
173 /** Pure copy constructor */
174 Region::Region (boost::shared_ptr<const Region> other)
175 : _name(other->_name)
176 , _type(other->data_type())
177 , _flags(Flag(other->_flags & ~(Locked|PositionLocked)))
178 , _start(other->_start)
179 , _length(other->_length)
180 , _position(other->_position)
181 , _sync_position(other->_sync_position)
182 , _layer(other->_layer)
183 , _first_edit(EditChangesID)
185 , _read_data_count(0)
186 , _pending_changed(Change(0))
187 , _last_layer_op(other->_last_layer_op)
189 other->_first_edit = EditChangesName;
191 if (other->_extra_xml) {
192 _extra_xml = new XMLNode (*other->_extra_xml);
197 set<boost::shared_ptr<Source> > unique_srcs;
199 for (SourceList::const_iterator i = other->_sources.begin(); i != other->_sources.end(); ++i) {
200 _sources.push_back (*i);
201 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
202 unique_srcs.insert (*i);
205 for (SourceList::const_iterator i = other->_master_sources.begin(); i != other->_master_sources.end(); ++i) {
206 _master_sources.push_back (*i);
207 if (unique_srcs.find (*i) == unique_srcs.end()) {
208 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
212 assert(_sources.size() > 0);
215 Region::Region (SourceList& srcs, const XMLNode& node)
216 : _name(X_("error: XML did not reset this"))
217 , _type(DataType::NIL) // to be loaded from XML
222 , _sync_position(_start)
224 , _first_edit(EditChangesNothing)
226 , _read_data_count(0)
227 , _pending_changed(Change(0))
230 set<boost::shared_ptr<Source> > unique_srcs;
232 for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) {
233 _sources.push_back (*i);
234 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
235 unique_srcs.insert (*i);
238 for (SourceList::iterator i = srcs.begin(); i != srcs.end(); ++i) {
239 _master_sources.push_back (*i);
240 if (unique_srcs.find (*i) == unique_srcs.end()) {
241 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
245 if (set_state (node)) {
246 throw failed_constructor();
249 assert(_type != DataType::NIL);
250 assert(_sources.size() > 0);
253 Region::Region (boost::shared_ptr<Source> src, const XMLNode& node)
254 : _name(X_("error: XML did not reset this"))
255 , _type(DataType::NIL)
260 , _sync_position(_start)
262 , _first_edit(EditChangesNothing)
264 , _read_data_count(0)
265 , _pending_changed(Change(0))
268 _sources.push_back (src);
270 if (set_state (node)) {
271 throw failed_constructor();
274 assert(_type != DataType::NIL);
275 assert(_sources.size() > 0);
280 boost::shared_ptr<Playlist> pl (playlist());
283 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
284 (*i)->remove_playlist (pl);
289 GoingAway (); /* EMIT SIGNAL */
293 Region::set_playlist (boost::weak_ptr<Playlist> wpl)
295 boost::shared_ptr<Playlist> old_playlist = (_playlist.lock());
297 boost::shared_ptr<Playlist> pl (wpl.lock());
299 if (old_playlist == pl) {
307 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
308 (*i)->remove_playlist (_playlist);
309 (*i)->add_playlist (pl);
312 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
313 (*i)->add_playlist (pl);
318 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
319 (*i)->remove_playlist (old_playlist);
326 Region::set_name (string str)
330 send_change (NameChanged);
335 Region::set_length (nframes_t len, void *src)
337 if (_flags & Locked) {
341 if (_length != len && len != 0) {
343 /* check that the current _position wouldn't make the new
347 if (max_frames - len < _position) {
351 if (!verify_length (len)) {
357 _flags = Region::Flag (_flags & ~WholeFile);
366 send_change (LengthChanged);
371 Region::maybe_uncopy ()
376 Region::first_edit ()
378 boost::shared_ptr<Playlist> pl (playlist());
380 if (_first_edit != EditChangesNothing && pl) {
382 _name = pl->session().new_region_name (_name);
383 _first_edit = EditChangesNothing;
385 send_change (NameChanged);
386 RegionFactory::CheckNewRegion (shared_from_this());
391 Region::at_natural_position () const
393 boost::shared_ptr<Playlist> pl (playlist());
399 boost::shared_ptr<Region> whole_file_region = get_parent();
401 if (whole_file_region) {
402 if (_position == whole_file_region->position() + _start) {
411 Region::move_to_natural_position (void *src)
413 boost::shared_ptr<Playlist> pl (playlist());
419 boost::shared_ptr<Region> whole_file_region = get_parent();
421 if (whole_file_region) {
422 set_position (whole_file_region->position() + _start, src);
427 Region::special_set_position (nframes_t pos)
429 /* this is used when creating a whole file region as
430 a way to store its "natural" or "captured" position.
437 Region::set_position (nframes_t pos, void *src)
443 if (_position != pos) {
446 /* check that the new _position wouldn't make the current
447 length impossible - if so, change the length.
449 XXX is this the right thing to do?
452 if (max_frames - _length < _position) {
453 _length = max_frames - _position;
457 /* do this even if the position is the same. this helps out
458 a GUI that has moved its representation already.
461 send_change (PositionChanged);
465 Region::set_position_on_top (nframes_t pos, void *src)
467 if (_flags & Locked) {
471 if (_position != pos) {
475 boost::shared_ptr<Playlist> pl (playlist());
478 pl->raise_region_to_top (shared_from_this ());
481 /* do this even if the position is the same. this helps out
482 a GUI that has moved its representation already.
485 send_change (PositionChanged);
489 Region::nudge_position (long n, void *src)
491 if (_flags & Locked) {
500 if (_position > max_frames - n) {
501 _position = max_frames;
506 if (_position < (nframes_t) -n) {
513 send_change (PositionChanged);
517 Region::set_start (nframes_t pos, void *src)
519 if (_flags & (Locked|PositionLocked)) {
522 /* This just sets the start, nothing else. It effectively shifts
523 the contents of the Region within the overall extent of the Source,
524 without changing the Region's position or length
529 if (!verify_start (pos)) {
534 _flags = Region::Flag (_flags & ~WholeFile);
537 send_change (StartChanged);
542 Region::trim_start (nframes_t new_position, void *src)
544 if (_flags & (Locked|PositionLocked)) {
550 if (new_position > _position) {
551 start_shift = new_position - _position;
553 start_shift = -(_position - new_position);
556 if (start_shift > 0) {
558 if (_start > max_frames - start_shift) {
559 new_start = max_frames;
561 new_start = _start + start_shift;
564 if (!verify_start (new_start)) {
568 } else if (start_shift < 0) {
570 if (_start < (nframes_t) -start_shift) {
573 new_start = _start + start_shift;
579 if (new_start == _start) {
584 _flags = Region::Flag (_flags & ~WholeFile);
587 send_change (StartChanged);
591 Region::trim_front (nframes_t new_position, void *src)
593 if (_flags & Locked) {
597 nframes_t end = last_frame();
598 nframes_t source_zero;
600 if (_position > _start) {
601 source_zero = _position - _start;
603 source_zero = 0; // its actually negative, but this will work for us
606 if (new_position < end) { /* can't trim it zero or negative length */
610 /* can't trim it back passed where source position zero is located */
612 new_position = max (new_position, source_zero);
615 if (new_position > _position) {
616 newlen = _length - (new_position - _position);
618 newlen = _length + (_position - new_position);
621 trim_to_internal (new_position, newlen, src);
623 recompute_at_start ();
629 Region::trim_end (nframes_t new_endpoint, void *src)
631 if (_flags & Locked) {
635 if (new_endpoint > _position) {
636 trim_to_internal (_position, new_endpoint - _position, this);
644 Region::trim_to (nframes_t position, nframes_t length, void *src)
646 if (_flags & Locked) {
650 trim_to_internal (position, length, src);
653 recompute_at_start ();
659 Region::trim_to_internal (nframes_t position, nframes_t length, void *src)
664 if (_flags & Locked) {
668 if (position > _position) {
669 start_shift = position - _position;
671 start_shift = -(_position - position);
674 if (start_shift > 0) {
676 if (_start > max_frames - start_shift) {
677 new_start = max_frames;
679 new_start = _start + start_shift;
683 } else if (start_shift < 0) {
685 if (_start < (nframes_t) -start_shift) {
688 new_start = _start + start_shift;
694 if (!verify_start_and_length (new_start, length)) {
698 Change what_changed = Change (0);
700 if (_start != new_start) {
702 what_changed = Change (what_changed|StartChanged);
704 if (_length != length) {
706 what_changed = Change (what_changed|LengthChanged);
708 if (_position != position) {
709 _position = position;
710 what_changed = Change (what_changed|PositionChanged);
713 _flags = Region::Flag (_flags & ~WholeFile);
715 if (what_changed & (StartChanged|LengthChanged)) {
720 send_change (what_changed);
725 Region::set_hidden (bool yn)
727 if (hidden() != yn) {
730 _flags = Flag (_flags|Hidden);
732 _flags = Flag (_flags & ~Hidden);
735 send_change (HiddenChanged);
740 Region::set_muted (bool yn)
745 _flags = Flag (_flags|Muted);
747 _flags = Flag (_flags & ~Muted);
750 send_change (MuteChanged);
755 Region::set_opaque (bool yn)
757 if (opaque() != yn) {
759 _flags = Flag (_flags|Opaque);
761 _flags = Flag (_flags & ~Opaque);
763 send_change (OpacityChanged);
768 Region::set_locked (bool yn)
770 if (locked() != yn) {
772 _flags = Flag (_flags|Locked);
774 _flags = Flag (_flags & ~Locked);
776 send_change (LockChanged);
781 Region::set_position_locked (bool yn)
783 if (position_locked() != yn) {
785 _flags = Flag (_flags|PositionLocked);
787 _flags = Flag (_flags & ~PositionLocked);
789 send_change (LockChanged);
794 Region::set_sync_position (nframes_t absolute_pos)
798 file_pos = _start + (absolute_pos - _position);
800 if (file_pos != _sync_position) {
802 _sync_position = file_pos;
803 _flags = Flag (_flags|SyncMarked);
808 send_change (SyncOffsetChanged);
813 Region::clear_sync_position ()
815 if (_flags & SyncMarked) {
816 _flags = Flag (_flags & ~SyncMarked);
821 send_change (SyncOffsetChanged);
826 Region::sync_offset (int& dir) const
828 /* returns the sync point relative the first frame of the region */
830 if (_flags & SyncMarked) {
831 if (_sync_position > _start) {
833 return _sync_position - _start;
836 return _start - _sync_position;
845 Region::adjust_to_sync (nframes_t pos)
848 nframes_t offset = sync_offset (sync_dir);
851 if (max_frames - pos > offset) {
866 Region::sync_position() const
868 if (_flags & SyncMarked) {
869 return _sync_position;
877 Region::raise_to_top ()
879 boost::shared_ptr<Playlist> pl (playlist());
881 pl->raise_region_to_top (shared_from_this());
886 Region::lower_to_bottom ()
888 boost::shared_ptr<Playlist> pl (playlist());
890 pl->lower_region_to_bottom (shared_from_this());
895 Region::set_layer (layer_t l)
900 send_change (LayerChanged);
905 Region::state (bool full_state)
907 XMLNode *node = new XMLNode ("Region");
911 _id.print (buf, sizeof (buf));
912 node->add_property ("id", buf);
913 node->add_property ("name", _name);
914 node->add_property ("type", _type.to_string());
915 snprintf (buf, sizeof (buf), "%u", _start);
916 node->add_property ("start", buf);
917 snprintf (buf, sizeof (buf), "%u", _length);
918 node->add_property ("length", buf);
919 snprintf (buf, sizeof (buf), "%u", _position);
920 node->add_property ("position", buf);
922 switch (_first_edit) {
923 case EditChangesNothing:
926 case EditChangesName:
932 default: /* should be unreachable but makes g++ happy */
937 node->add_property ("first_edit", fe);
939 /* note: flags are stored by derived classes */
941 snprintf (buf, sizeof (buf), "%d", (int) _layer);
942 node->add_property ("layer", buf);
943 snprintf (buf, sizeof (buf), "%" PRIu32, _sync_position);
944 node->add_property ("sync-position", buf);
956 Region::set_live_state (const XMLNode& node, Change& what_changed, bool send)
958 const XMLNodeList& nlist = node.children();
959 const XMLProperty *prop;
962 /* this is responsible for setting those aspects of Region state
963 that are mutable after construction.
966 if ((prop = node.property ("name")) == 0) {
967 error << _("XMLNode describing a Region is incomplete (no name)") << endmsg;
971 _name = prop->value();
973 if ((prop = node.property ("type")) == 0) {
974 _type = DataType::AUDIO;
976 _type = DataType(prop->value());
979 if ((prop = node.property ("start")) != 0) {
980 sscanf (prop->value().c_str(), "%" PRIu32, &val);
982 what_changed = Change (what_changed|StartChanged);
989 if ((prop = node.property ("length")) != 0) {
990 sscanf (prop->value().c_str(), "%" PRIu32, &val);
991 if (val != _length) {
992 what_changed = Change (what_changed|LengthChanged);
999 if ((prop = node.property ("position")) != 0) {
1000 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1001 if (val != _position) {
1002 what_changed = Change (what_changed|PositionChanged);
1009 if ((prop = node.property ("layer")) != 0) {
1011 x = (layer_t) atoi (prop->value().c_str());
1013 what_changed = Change (what_changed|LayerChanged);
1020 if ((prop = node.property ("sync-position")) != 0) {
1021 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1022 if (val != _sync_position) {
1023 what_changed = Change (what_changed|SyncOffsetChanged);
1024 _sync_position = val;
1027 _sync_position = _start;
1030 /* XXX FIRST EDIT !!! */
1032 /* note: derived classes set flags */
1039 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1045 if (child->name () == "extra") {
1046 _extra_xml = new XMLNode (*child);
1052 send_change (what_changed);
1059 Region::set_state (const XMLNode& node)
1061 const XMLProperty *prop;
1062 Change what_changed = Change (0);
1064 /* ID is not allowed to change, ever */
1066 if ((prop = node.property ("id")) == 0) {
1067 error << _("Session: XMLNode describing a Region is incomplete (no id)") << endmsg;
1071 _id = prop->value();
1073 _first_edit = EditChangesNothing;
1075 set_live_state (node, what_changed, true);
1087 Region::thaw (const string& why)
1089 Change what_changed = Change (0);
1092 Glib::Mutex::Lock lm (_lock);
1094 if (_frozen && --_frozen > 0) {
1098 if (_pending_changed) {
1099 what_changed = _pending_changed;
1100 _pending_changed = Change (0);
1104 if (what_changed == Change (0)) {
1108 if (what_changed & LengthChanged) {
1109 if (what_changed & PositionChanged) {
1110 recompute_at_start ();
1112 recompute_at_end ();
1115 StateChanged (what_changed);
1119 Region::send_change (Change what_changed)
1122 Glib::Mutex::Lock lm (_lock);
1124 _pending_changed = Change (_pending_changed|what_changed);
1129 StateChanged (what_changed);
1133 Region::set_last_layer_op (uint64_t when)
1135 _last_layer_op = when;
1139 Region::overlap_equivalent (boost::shared_ptr<const Region> other) const
1141 return coverage (other->first_frame(), other->last_frame()) != OverlapNone;
1145 Region::equivalent (boost::shared_ptr<const Region> other) const
1147 return _start == other->_start &&
1148 _position == other->_position &&
1149 _length == other->_length;
1153 Region::size_equivalent (boost::shared_ptr<const Region> other) const
1155 return _start == other->_start &&
1156 _length == other->_length;
1160 Region::region_list_equivalent (boost::shared_ptr<const Region> other) const
1162 return size_equivalent (other) && source_equivalent (other) && _name == other->_name;
1166 Region::source_deleted (boost::shared_ptr<Source>)
1172 Region::master_source_names ()
1174 SourceList::iterator i;
1176 vector<string> names;
1177 for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1178 names.push_back((*i)->name());
1185 Region::source_equivalent (boost::shared_ptr<const Region> other) const
1190 SourceList::const_iterator i;
1191 SourceList::const_iterator io;
1193 for (i = _sources.begin(), io = other->_sources.begin(); i != _sources.end() && io != other->_sources.end(); ++i, ++io) {
1194 if ((*i)->id() != (*io)->id()) {
1199 for (i = _master_sources.begin(), io = other->_master_sources.begin(); i != _master_sources.end() && io != other->_master_sources.end(); ++i, ++io) {
1200 if ((*i)->id() != (*io)->id()) {
1209 Region::verify_length (nframes_t len)
1211 for (uint32_t n=0; n < _sources.size(); ++n) {
1212 if (_start > _sources[n]->length() - len) {
1220 Region::verify_start_and_length (nframes_t new_start, nframes_t new_length)
1222 for (uint32_t n=0; n < _sources.size(); ++n) {
1223 if (new_length > _sources[n]->length() - new_start) {
1230 Region::verify_start (nframes_t pos)
1232 for (uint32_t n=0; n < _sources.size(); ++n) {
1233 if (pos > _sources[n]->length() - _length) {
1241 Region::verify_start_mutable (nframes_t& new_start)
1243 for (uint32_t n=0; n < _sources.size(); ++n) {
1244 if (new_start > _sources[n]->length() - _length) {
1245 new_start = _sources[n]->length() - _length;
1251 boost::shared_ptr<Region>
1252 Region::get_parent() const
1254 boost::shared_ptr<Playlist> pl (playlist());
1257 boost::shared_ptr<Region> r;
1258 boost::shared_ptr<Region const> grrr2 = boost::dynamic_pointer_cast<Region const> (shared_from_this());
1260 if (grrr2 && (r = pl->session().find_whole_file_parent (grrr2))) {
1261 return boost::static_pointer_cast<Region> (r);
1265 return boost::shared_ptr<Region>();
1269 Region::node_name ()
1271 return X_("Region");