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.
26 #include <sigc++/bind.h>
27 #include <sigc++/class_slot.h>
29 #include <glibmm/thread.h>
30 #include <pbd/xml++.h>
31 #include <pbd/stacktrace.h>
33 #include <ardour/region.h>
34 #include <ardour/playlist.h>
35 #include <ardour/session.h>
36 #include <ardour/source.h>
37 #include <ardour/region_factory.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 ();
53 /** Basic Region constructor (single source) */
54 Region::Region (boost::shared_ptr<Source> src, jack_nframes_t start, jack_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 _sources.push_back (src);
70 _master_sources.push_back (src);
71 src->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), src));
73 assert(_sources.size() > 0);
76 /** Basic Region constructor (many sources) */
77 Region::Region (SourceList& srcs, jack_nframes_t start, jack_nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
84 , _sync_position(_start)
86 , _first_edit(EditChangesNothing)
89 , _pending_changed(Change (0))
93 set<boost::shared_ptr<Source> > unique_srcs;
95 for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) {
96 _sources.push_back (*i);
97 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
98 unique_srcs.insert (*i);
101 for (SourceList::iterator i = srcs.begin(); i != srcs.end(); ++i) {
102 _master_sources.push_back (*i);
103 if (unique_srcs.find (*i) == unique_srcs.end()) {
104 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
108 assert(_sources.size() > 0);
111 /** Create a new Region from part of an existing one */
112 Region::Region (boost::shared_ptr<const Region> other, nframes_t offset, nframes_t length, const string& name, layer_t layer, Flag flags)
114 , _type(other->data_type())
115 , _flags(Flag(flags & ~(Locked|WholeFile|Hidden)))
116 , _start(other->_start + offset)
119 , _sync_position(_start)
121 , _first_edit(EditChangesNothing)
123 , _read_data_count(0)
124 , _pending_changed(Change (0))
127 if (other->_sync_position < offset)
128 _sync_position = other->_sync_position;
130 set<boost::shared_ptr<Source> > unique_srcs;
132 for (SourceList::const_iterator i= other->_sources.begin(); i != other->_sources.end(); ++i) {
133 _sources.push_back (*i);
134 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
135 unique_srcs.insert (*i);
138 if (other->_sync_position < offset) {
139 _sync_position = other->_sync_position;
142 for (SourceList::const_iterator i = other->_master_sources.begin(); i != other->_master_sources.end(); ++i) {
143 if (unique_srcs.find (*i) == unique_srcs.end()) {
144 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
146 _master_sources.push_back (*i);
149 assert(_sources.size() > 0);
152 /** Pure copy constructor */
153 Region::Region (boost::shared_ptr<const Region> other)
154 : _name(other->_name)
155 , _type(other->data_type())
156 , _flags(Flag(other->_flags & ~Locked))
157 , _start(other->_start)
158 , _length(other->_length)
159 , _position(other->_position)
160 , _sync_position(other->_sync_position)
161 , _layer(other->_layer)
162 , _first_edit(EditChangesID)
164 , _read_data_count(0)
165 , _pending_changed(Change(0))
166 , _last_layer_op(other->_last_layer_op)
168 other->_first_edit = EditChangesName;
170 if (other->_extra_xml) {
171 _extra_xml = new XMLNode (*other->_extra_xml);
176 set<boost::shared_ptr<Source> > unique_srcs;
178 for (SourceList::const_iterator i = other->_sources.begin(); i != other->_sources.end(); ++i) {
179 _sources.push_back (*i);
180 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
181 unique_srcs.insert (*i);
184 for (SourceList::const_iterator i = other->_master_sources.begin(); i != other->_master_sources.end(); ++i) {
185 _master_sources.push_back (*i);
186 if (unique_srcs.find (*i) == unique_srcs.end()) {
187 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
191 assert(_sources.size() > 0);
194 Region::Region (SourceList& srcs, const XMLNode& node)
195 : _name(X_("error: XML did not reset this"))
196 , _type(DataType::NIL) // to be loaded from XML
201 , _sync_position(_start)
203 , _first_edit(EditChangesNothing)
205 , _read_data_count(0)
206 , _pending_changed(Change(0))
209 set<boost::shared_ptr<Source> > unique_srcs;
211 for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) {
212 _sources.push_back (*i);
213 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
214 unique_srcs.insert (*i);
217 for (SourceList::iterator i = srcs.begin(); i != srcs.end(); ++i) {
218 _master_sources.push_back (*i);
219 if (unique_srcs.find (*i) == unique_srcs.end()) {
220 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
224 if (set_state (node)) {
225 throw failed_constructor();
228 assert(_type != DataType::NIL);
229 assert(_sources.size() > 0);
232 Region::Region (boost::shared_ptr<Source> src, const XMLNode& node)
233 : _name(X_("error: XML did not reset this"))
234 , _type(DataType::NIL)
239 , _sync_position(_start)
241 , _first_edit(EditChangesNothing)
243 , _read_data_count(0)
244 , _pending_changed(Change(0))
247 _sources.push_back (src);
250 if (set_state (node)) {
251 throw failed_constructor();
254 assert(_type != DataType::NIL);
255 assert(_sources.size() > 0);
260 boost::shared_ptr<Playlist> pl (playlist());
263 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
264 (*i)->remove_playlist (pl);
269 GoingAway (); /* EMIT SIGNAL */
273 Region::set_playlist (boost::weak_ptr<Playlist> wpl)
275 boost::shared_ptr<Playlist> old_playlist = (_playlist.lock());
276 boost::shared_ptr<Playlist> pl (wpl.lock());
278 if (old_playlist == pl) {
284 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
285 (*i)->remove_playlist (_playlist);
286 (*i)->add_playlist (pl);
289 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
290 (*i)->add_playlist (pl);
295 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
296 (*i)->remove_playlist (_playlist);
303 Region::set_name (string str)
307 send_change (NameChanged);
312 Region::set_length (nframes_t len, void *src)
314 if (_flags & Locked) {
318 if (_length != len && len != 0) {
320 /* check that the current _position wouldn't make the new
324 if (max_frames - len < _position) {
328 if (!verify_length (len)) {
334 _flags = Region::Flag (_flags & ~WholeFile);
343 send_change (LengthChanged);
348 Region::maybe_uncopy ()
353 Region::first_edit ()
355 boost::shared_ptr<Playlist> pl (playlist());
357 if (_first_edit != EditChangesNothing && pl) {
359 _name = pl->session().new_region_name (_name);
360 _first_edit = EditChangesNothing;
362 send_change (NameChanged);
363 RegionFactory::CheckNewRegion (shared_from_this());
368 Region::at_natural_position () const
370 boost::shared_ptr<Playlist> pl (playlist());
376 boost::shared_ptr<Region> whole_file_region = get_parent();
378 if (whole_file_region) {
379 if (_position == whole_file_region->position() + _start) {
388 Region::move_to_natural_position (void *src)
390 boost::shared_ptr<Playlist> pl (playlist());
396 boost::shared_ptr<Region> whole_file_region = get_parent();
398 if (whole_file_region) {
399 set_position (whole_file_region->position() + _start, src);
404 Region::special_set_position (nframes_t pos)
406 /* this is used when creating a whole file region as
407 a way to store its "natural" or "captured" position.
414 Region::set_position (nframes_t pos, void *src)
416 if (_flags & Locked) {
420 if (_position != pos) {
423 /* check that the new _position wouldn't make the current
424 length impossible - if so, change the length.
426 XXX is this the right thing to do?
429 if (max_frames - _length < _position) {
430 _length = max_frames - _position;
434 /* do this even if the position is the same. this helps out
435 a GUI that has moved its representation already.
438 send_change (PositionChanged);
442 Region::set_position_on_top (nframes_t pos, void *src)
444 if (_flags & Locked) {
448 if (_position != pos) {
452 boost::shared_ptr<Playlist> pl (playlist());
455 pl->raise_region_to_top (shared_from_this ());
458 /* do this even if the position is the same. this helps out
459 a GUI that has moved its representation already.
462 send_change (PositionChanged);
466 Region::nudge_position (long n, void *src)
468 if (_flags & Locked) {
477 if (_position > max_frames - n) {
478 _position = max_frames;
483 if (_position < (nframes_t) -n) {
490 send_change (PositionChanged);
494 Region::set_start (nframes_t pos, void *src)
496 if (_flags & Locked) {
499 /* This just sets the start, nothing else. It effectively shifts
500 the contents of the Region within the overall extent of the Source,
501 without changing the Region's position or length
506 if (!verify_start (pos)) {
511 _flags = Region::Flag (_flags & ~WholeFile);
514 send_change (StartChanged);
519 Region::trim_start (nframes_t new_position, void *src)
521 if (_flags & Locked) {
527 if (new_position > _position) {
528 start_shift = new_position - _position;
530 start_shift = -(_position - new_position);
533 if (start_shift > 0) {
535 if (_start > max_frames - start_shift) {
536 new_start = max_frames;
538 new_start = _start + start_shift;
541 if (!verify_start (new_start)) {
545 } else if (start_shift < 0) {
547 if (_start < (nframes_t) -start_shift) {
550 new_start = _start + start_shift;
556 if (new_start == _start) {
561 _flags = Region::Flag (_flags & ~WholeFile);
564 send_change (StartChanged);
568 Region::trim_front (nframes_t new_position, void *src)
570 if (_flags & Locked) {
574 nframes_t end = last_frame();
575 nframes_t source_zero;
577 if (_position > _start) {
578 source_zero = _position - _start;
580 source_zero = 0; // its actually negative, but this will work for us
583 if (new_position < end) { /* can't trim it zero or negative length */
587 /* can't trim it back passed where source position zero is located */
589 new_position = max (new_position, source_zero);
592 if (new_position > _position) {
593 newlen = _length - (new_position - _position);
595 newlen = _length + (_position - new_position);
598 trim_to_internal (new_position, newlen, src);
600 recompute_at_start ();
606 Region::trim_end (nframes_t new_endpoint, void *src)
608 if (_flags & Locked) {
612 if (new_endpoint > _position) {
613 trim_to_internal (_position, new_endpoint - _position, this);
621 Region::trim_to (nframes_t position, nframes_t length, void *src)
623 if (_flags & Locked) {
627 trim_to_internal (position, length, src);
630 recompute_at_start ();
636 Region::trim_to_internal (nframes_t position, nframes_t length, void *src)
641 if (_flags & Locked) {
645 if (position > _position) {
646 start_shift = position - _position;
648 start_shift = -(_position - position);
651 if (start_shift > 0) {
653 if (_start > max_frames - start_shift) {
654 new_start = max_frames;
656 new_start = _start + start_shift;
660 } else if (start_shift < 0) {
662 if (_start < (nframes_t) -start_shift) {
665 new_start = _start + start_shift;
671 if (!verify_start_and_length (new_start, length)) {
675 Change what_changed = Change (0);
677 if (_start != new_start) {
679 what_changed = Change (what_changed|StartChanged);
681 if (_length != length) {
683 what_changed = Change (what_changed|LengthChanged);
685 if (_position != position) {
686 _position = position;
687 what_changed = Change (what_changed|PositionChanged);
690 _flags = Region::Flag (_flags & ~WholeFile);
692 if (what_changed & (StartChanged|LengthChanged)) {
697 send_change (what_changed);
702 Region::set_hidden (bool yn)
704 if (hidden() != yn) {
707 _flags = Flag (_flags|Hidden);
709 _flags = Flag (_flags & ~Hidden);
712 send_change (HiddenChanged);
717 Region::set_muted (bool yn)
722 _flags = Flag (_flags|Muted);
724 _flags = Flag (_flags & ~Muted);
727 send_change (MuteChanged);
732 Region::set_opaque (bool yn)
734 if (opaque() != yn) {
736 _flags = Flag (_flags|Opaque);
738 _flags = Flag (_flags & ~Opaque);
740 send_change (OpacityChanged);
745 Region::set_locked (bool yn)
747 if (locked() != yn) {
749 _flags = Flag (_flags|Locked);
751 _flags = Flag (_flags & ~Locked);
753 send_change (LockChanged);
758 Region::set_sync_position (nframes_t absolute_pos)
762 file_pos = _start + (absolute_pos - _position);
764 if (file_pos != _sync_position) {
766 _sync_position = file_pos;
767 _flags = Flag (_flags|SyncMarked);
772 send_change (SyncOffsetChanged);
777 Region::clear_sync_position ()
779 if (_flags & SyncMarked) {
780 _flags = Flag (_flags & ~SyncMarked);
785 send_change (SyncOffsetChanged);
790 Region::sync_offset (int& dir) const
792 /* returns the sync point relative the first frame of the region */
794 if (_flags & SyncMarked) {
795 if (_sync_position > _start) {
797 return _sync_position - _start;
800 return _start - _sync_position;
809 Region::adjust_to_sync (nframes_t pos)
812 nframes_t offset = sync_offset (sync_dir);
815 if (max_frames - pos > offset) {
830 Region::sync_position() const
832 if (_flags & SyncMarked) {
833 return _sync_position;
843 boost::shared_ptr<Playlist> pl (playlist());
845 pl->raise_region (shared_from_this ());
852 boost::shared_ptr<Playlist> pl (playlist());
854 pl->lower_region (shared_from_this ());
859 Region::raise_to_top ()
861 boost::shared_ptr<Playlist> pl (playlist());
863 pl->raise_region_to_top (shared_from_this());
868 Region::lower_to_bottom ()
870 boost::shared_ptr<Playlist> pl (playlist());
872 pl->lower_region_to_bottom (shared_from_this());
877 Region::set_layer (layer_t l)
882 send_change (LayerChanged);
887 Region::state (bool full_state)
889 XMLNode *node = new XMLNode ("Region");
893 _id.print (buf, sizeof (buf));
894 node->add_property ("id", buf);
895 node->add_property ("name", _name);
896 node->add_property ("type", _type.to_string());
897 snprintf (buf, sizeof (buf), "%u", _start);
898 node->add_property ("start", buf);
899 snprintf (buf, sizeof (buf), "%u", _length);
900 node->add_property ("length", buf);
901 snprintf (buf, sizeof (buf), "%u", _position);
902 node->add_property ("position", buf);
904 switch (_first_edit) {
905 case EditChangesNothing:
908 case EditChangesName:
916 node->add_property ("first_edit", fe);
918 /* note: flags are stored by derived classes */
920 snprintf (buf, sizeof (buf), "%d", (int) _layer);
921 node->add_property ("layer", buf);
922 snprintf (buf, sizeof (buf), "%" PRIu32, _sync_position);
923 node->add_property ("sync-position", buf);
935 Region::set_live_state (const XMLNode& node, Change& what_changed, bool send)
937 const XMLNodeList& nlist = node.children();
938 const XMLProperty *prop;
941 /* this is responsible for setting those aspects of Region state
942 that are mutable after construction.
945 if ((prop = node.property ("name")) == 0) {
946 error << _("XMLNode describing a Region is incomplete (no name)") << endmsg;
950 _name = prop->value();
952 if ((prop = node.property ("type")) == 0) {
953 _type = DataType::AUDIO;
955 _type = DataType(prop->value());
958 if ((prop = node.property ("start")) != 0) {
959 sscanf (prop->value().c_str(), "%" PRIu32, &val);
961 what_changed = Change (what_changed|StartChanged);
968 if ((prop = node.property ("length")) != 0) {
969 sscanf (prop->value().c_str(), "%" PRIu32, &val);
970 if (val != _length) {
971 what_changed = Change (what_changed|LengthChanged);
978 if ((prop = node.property ("position")) != 0) {
979 sscanf (prop->value().c_str(), "%" PRIu32, &val);
980 if (val != _position) {
981 what_changed = Change (what_changed|PositionChanged);
988 if ((prop = node.property ("layer")) != 0) {
990 x = (layer_t) atoi (prop->value().c_str());
992 what_changed = Change (what_changed|LayerChanged);
999 if ((prop = node.property ("sync-position")) != 0) {
1000 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1001 if (val != _sync_position) {
1002 what_changed = Change (what_changed|SyncOffsetChanged);
1003 _sync_position = val;
1006 _sync_position = _start;
1009 /* XXX FIRST EDIT !!! */
1011 /* note: derived classes set flags */
1018 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1024 if (child->name () == "extra") {
1025 _extra_xml = new XMLNode (*child);
1031 send_change (what_changed);
1038 Region::set_state (const XMLNode& node)
1040 const XMLProperty *prop;
1041 Change what_changed = Change (0);
1043 /* ID is not allowed to change, ever */
1045 if ((prop = node.property ("id")) == 0) {
1046 error << _("Session: XMLNode describing a Region is incomplete (no id)") << endmsg;
1050 _id = prop->value();
1052 _first_edit = EditChangesNothing;
1054 set_live_state (node, what_changed, true);
1066 Region::thaw (const string& why)
1068 Change what_changed = Change (0);
1071 Glib::Mutex::Lock lm (_lock);
1073 if (_frozen && --_frozen > 0) {
1077 if (_pending_changed) {
1078 what_changed = _pending_changed;
1079 _pending_changed = Change (0);
1083 if (what_changed == Change (0)) {
1087 if (what_changed & LengthChanged) {
1088 if (what_changed & PositionChanged) {
1089 recompute_at_start ();
1091 recompute_at_end ();
1094 StateChanged (what_changed);
1098 Region::send_change (Change what_changed)
1101 Glib::Mutex::Lock lm (_lock);
1103 _pending_changed = Change (_pending_changed|what_changed);
1108 StateChanged (what_changed);
1112 Region::set_last_layer_op (uint64_t when)
1114 _last_layer_op = when;
1118 Region::overlap_equivalent (boost::shared_ptr<const Region> other) const
1120 return coverage (other->first_frame(), other->last_frame()) != OverlapNone;
1124 Region::equivalent (boost::shared_ptr<const Region> other) const
1126 return _start == other->_start &&
1127 _position == other->_position &&
1128 _length == other->_length;
1132 Region::size_equivalent (boost::shared_ptr<const Region> other) const
1134 return _start == other->_start &&
1135 _length == other->_length;
1139 Region::region_list_equivalent (boost::shared_ptr<const Region> other) const
1141 return size_equivalent (other) && source_equivalent (other) && _name == other->_name;
1145 Region::source_deleted (boost::shared_ptr<Source>)
1151 Region::master_source_names ()
1153 SourceList::iterator i;
1155 vector<string> names;
1156 for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1157 names.push_back((*i)->name());
1164 Region::source_equivalent (boost::shared_ptr<const Region> other) const
1169 SourceList::const_iterator i;
1170 SourceList::const_iterator io;
1172 for (i = _sources.begin(), io = other->_sources.begin(); i != _sources.end() && io != other->_sources.end(); ++i, ++io) {
1173 if ((*i)->id() != (*io)->id()) {
1178 for (i = _master_sources.begin(), io = other->_master_sources.begin(); i != _master_sources.end() && io != other->_master_sources.end(); ++i, ++io) {
1179 if ((*i)->id() != (*io)->id()) {
1188 Region::verify_length (jack_nframes_t len)
1190 for (uint32_t n=0; n < _sources.size(); ++n) {
1191 if (_start > _sources[n]->length() - len) {
1199 Region::verify_start_and_length (jack_nframes_t new_start, jack_nframes_t new_length)
1201 for (uint32_t n=0; n < _sources.size(); ++n) {
1202 if (new_length > _sources[n]->length() - new_start) {
1209 Region::verify_start (jack_nframes_t pos)
1211 for (uint32_t n=0; n < _sources.size(); ++n) {
1212 if (pos > _sources[n]->length() - _length) {
1220 Region::verify_start_mutable (jack_nframes_t& new_start)
1222 for (uint32_t n=0; n < _sources.size(); ++n) {
1223 if (new_start > _sources[n]->length() - _length) {
1224 new_start = _sources[n]->length() - _length;
1230 boost::shared_ptr<Region>
1231 Region::get_parent() const
1233 boost::shared_ptr<Playlist> pl (playlist());
1236 boost::shared_ptr<Region> r;
1237 boost::shared_ptr<Region const> grrr2 = boost::dynamic_pointer_cast<Region const> (shared_from_this());
1239 if (grrr2 && (r = pl->session().find_whole_file_parent (grrr2))) {
1240 return boost::static_pointer_cast<Region> (r);
1244 return boost::shared_ptr<Region>();