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 (nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
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)
82 , _sync_position(_start)
84 , _first_edit(EditChangesNothing)
87 , _pending_changed(Change (0))
90 _sources.push_back (src);
91 _master_sources.push_back (src);
93 src->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), src));
95 assert(_sources.size() > 0);
98 /** Basic Region constructor (many sources) */
99 Region::Region (SourceList& srcs, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
106 , _sync_position(_start)
108 , _first_edit(EditChangesNothing)
110 , _read_data_count(0)
111 , _pending_changed(Change (0))
115 set<boost::shared_ptr<Source> > unique_srcs;
117 for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) {
118 _sources.push_back (*i);
119 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
120 unique_srcs.insert (*i);
123 for (SourceList::iterator i = srcs.begin(); i != srcs.end(); ++i) {
124 _master_sources.push_back (*i);
125 if (unique_srcs.find (*i) == unique_srcs.end()) {
126 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
130 assert(_sources.size() > 0);
133 /** Create a new Region from part of an existing one */
134 Region::Region (boost::shared_ptr<const Region> other, nframes_t offset, nframes_t length, const string& name, layer_t layer, Flag flags)
136 , _type(other->data_type())
137 , _flags(Flag(flags & ~(Locked|PositionLocked|WholeFile|Hidden)))
138 , _start(other->_start + offset)
141 , _sync_position(_start)
143 , _first_edit(EditChangesNothing)
145 , _read_data_count(0)
146 , _pending_changed(Change (0))
149 if (other->_sync_position < offset)
150 _sync_position = other->_sync_position;
152 set<boost::shared_ptr<Source> > unique_srcs;
154 for (SourceList::const_iterator i= other->_sources.begin(); i != other->_sources.end(); ++i) {
155 _sources.push_back (*i);
156 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
157 unique_srcs.insert (*i);
160 if (other->_sync_position < offset) {
161 _sync_position = other->_sync_position;
164 for (SourceList::const_iterator i = other->_master_sources.begin(); i != other->_master_sources.end(); ++i) {
165 if (unique_srcs.find (*i) == unique_srcs.end()) {
166 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
168 _master_sources.push_back (*i);
171 assert(_sources.size() > 0);
174 /** Pure copy constructor */
175 Region::Region (boost::shared_ptr<const Region> other)
176 : _name(other->_name)
177 , _type(other->data_type())
178 , _flags(Flag(other->_flags & ~(Locked|PositionLocked)))
179 , _start(other->_start)
180 , _length(other->_length)
181 , _position(other->_position)
182 , _sync_position(other->_sync_position)
183 , _layer(other->_layer)
184 , _first_edit(EditChangesID)
186 , _read_data_count(0)
187 , _pending_changed(Change(0))
188 , _last_layer_op(other->_last_layer_op)
190 other->_first_edit = EditChangesName;
192 if (other->_extra_xml) {
193 _extra_xml = new XMLNode (*other->_extra_xml);
198 set<boost::shared_ptr<Source> > unique_srcs;
200 for (SourceList::const_iterator i = other->_sources.begin(); i != other->_sources.end(); ++i) {
201 _sources.push_back (*i);
202 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
203 unique_srcs.insert (*i);
206 for (SourceList::const_iterator i = other->_master_sources.begin(); i != other->_master_sources.end(); ++i) {
207 _master_sources.push_back (*i);
208 if (unique_srcs.find (*i) == unique_srcs.end()) {
209 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
213 assert(_sources.size() > 0);
216 Region::Region (SourceList& srcs, const XMLNode& node)
217 : _name(X_("error: XML did not reset this"))
218 , _type(DataType::NIL) // to be loaded from XML
223 , _sync_position(_start)
225 , _first_edit(EditChangesNothing)
227 , _read_data_count(0)
228 , _pending_changed(Change(0))
231 set<boost::shared_ptr<Source> > unique_srcs;
233 for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) {
234 _sources.push_back (*i);
235 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
236 unique_srcs.insert (*i);
239 for (SourceList::iterator i = srcs.begin(); i != srcs.end(); ++i) {
240 _master_sources.push_back (*i);
241 if (unique_srcs.find (*i) == unique_srcs.end()) {
242 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
246 if (set_state (node)) {
247 throw failed_constructor();
250 assert(_type != DataType::NIL);
251 assert(_sources.size() > 0);
254 Region::Region (boost::shared_ptr<Source> src, const XMLNode& node)
255 : _name(X_("error: XML did not reset this"))
256 , _type(DataType::NIL)
261 , _sync_position(_start)
263 , _first_edit(EditChangesNothing)
265 , _read_data_count(0)
266 , _pending_changed(Change(0))
269 _sources.push_back (src);
271 if (set_state (node)) {
272 throw failed_constructor();
275 assert(_type != DataType::NIL);
276 assert(_sources.size() > 0);
281 boost::shared_ptr<Playlist> pl (playlist());
284 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
285 (*i)->remove_playlist (pl);
290 GoingAway (); /* EMIT SIGNAL */
294 Region::set_playlist (boost::weak_ptr<Playlist> wpl)
296 boost::shared_ptr<Playlist> old_playlist = (_playlist.lock());
298 boost::shared_ptr<Playlist> pl (wpl.lock());
300 if (old_playlist == pl) {
308 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
309 (*i)->remove_playlist (_playlist);
310 (*i)->add_playlist (pl);
313 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
314 (*i)->add_playlist (pl);
319 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
320 (*i)->remove_playlist (old_playlist);
327 Region::set_name (string str)
331 send_change (NameChanged);
336 Region::set_length (nframes_t len, void *src)
338 if (_flags & Locked) {
342 if (_length != len && len != 0) {
344 /* check that the current _position wouldn't make the new
348 if (max_frames - len < _position) {
352 if (!verify_length (len)) {
358 _flags = Region::Flag (_flags & ~WholeFile);
367 send_change (LengthChanged);
372 Region::maybe_uncopy ()
377 Region::first_edit ()
379 boost::shared_ptr<Playlist> pl (playlist());
381 if (_first_edit != EditChangesNothing && pl) {
383 _name = pl->session().new_region_name (_name);
384 _first_edit = EditChangesNothing;
386 send_change (NameChanged);
387 RegionFactory::CheckNewRegion (shared_from_this());
392 Region::at_natural_position () const
394 boost::shared_ptr<Playlist> pl (playlist());
400 boost::shared_ptr<Region> whole_file_region = get_parent();
402 if (whole_file_region) {
403 if (_position == whole_file_region->position() + _start) {
412 Region::move_to_natural_position (void *src)
414 boost::shared_ptr<Playlist> pl (playlist());
420 boost::shared_ptr<Region> whole_file_region = get_parent();
422 if (whole_file_region) {
423 set_position (whole_file_region->position() + _start, src);
428 Region::special_set_position (nframes_t pos)
430 /* this is used when creating a whole file region as
431 a way to store its "natural" or "captured" position.
438 Region::set_position (nframes_t pos, void *src)
444 if (_position != pos) {
447 /* check that the new _position wouldn't make the current
448 length impossible - if so, change the length.
450 XXX is this the right thing to do?
453 if (max_frames - _length < _position) {
454 _length = max_frames - _position;
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::set_position_on_top (nframes_t pos, void *src)
468 if (_flags & Locked) {
472 if (_position != pos) {
476 boost::shared_ptr<Playlist> pl (playlist());
479 pl->raise_region_to_top (shared_from_this ());
482 /* do this even if the position is the same. this helps out
483 a GUI that has moved its representation already.
486 send_change (PositionChanged);
490 Region::nudge_position (long n, void *src)
492 if (_flags & Locked) {
501 if (_position > max_frames - n) {
502 _position = max_frames;
507 if (_position < (nframes_t) -n) {
514 send_change (PositionChanged);
518 Region::set_start (nframes_t pos, void *src)
520 if (_flags & (Locked|PositionLocked)) {
523 /* This just sets the start, nothing else. It effectively shifts
524 the contents of the Region within the overall extent of the Source,
525 without changing the Region's position or length
530 if (!verify_start (pos)) {
535 _flags = Region::Flag (_flags & ~WholeFile);
538 send_change (StartChanged);
543 Region::trim_start (nframes_t new_position, void *src)
545 if (_flags & (Locked|PositionLocked)) {
551 if (new_position > _position) {
552 start_shift = new_position - _position;
554 start_shift = -(_position - new_position);
557 if (start_shift > 0) {
559 if (_start > max_frames - start_shift) {
560 new_start = max_frames;
562 new_start = _start + start_shift;
565 if (!verify_start (new_start)) {
569 } else if (start_shift < 0) {
571 if (_start < (nframes_t) -start_shift) {
574 new_start = _start + start_shift;
580 if (new_start == _start) {
585 _flags = Region::Flag (_flags & ~WholeFile);
588 send_change (StartChanged);
592 Region::trim_front (nframes_t new_position, void *src)
594 if (_flags & Locked) {
598 nframes_t end = last_frame();
599 nframes_t source_zero;
601 if (_position > _start) {
602 source_zero = _position - _start;
604 source_zero = 0; // its actually negative, but this will work for us
607 if (new_position < end) { /* can't trim it zero or negative length */
611 /* can't trim it back passed where source position zero is located */
613 new_position = max (new_position, source_zero);
616 if (new_position > _position) {
617 newlen = _length - (new_position - _position);
619 newlen = _length + (_position - new_position);
622 trim_to_internal (new_position, newlen, src);
624 recompute_at_start ();
630 Region::trim_end (nframes_t new_endpoint, void *src)
632 if (_flags & Locked) {
636 if (new_endpoint > _position) {
637 trim_to_internal (_position, new_endpoint - _position, this);
645 Region::trim_to (nframes_t position, nframes_t length, void *src)
647 if (_flags & Locked) {
651 trim_to_internal (position, length, src);
654 recompute_at_start ();
660 Region::trim_to_internal (nframes_t position, nframes_t length, void *src)
665 if (_flags & Locked) {
669 if (position > _position) {
670 start_shift = position - _position;
672 start_shift = -(_position - position);
675 if (start_shift > 0) {
677 if (_start > max_frames - start_shift) {
678 new_start = max_frames;
680 new_start = _start + start_shift;
684 } else if (start_shift < 0) {
686 if (_start < (nframes_t) -start_shift) {
689 new_start = _start + start_shift;
695 if (!verify_start_and_length (new_start, length)) {
699 Change what_changed = Change (0);
701 if (_start != new_start) {
703 what_changed = Change (what_changed|StartChanged);
705 if (_length != length) {
707 what_changed = Change (what_changed|LengthChanged);
709 if (_position != position) {
710 _position = position;
711 what_changed = Change (what_changed|PositionChanged);
714 _flags = Region::Flag (_flags & ~WholeFile);
716 if (what_changed & (StartChanged|LengthChanged)) {
721 send_change (what_changed);
726 Region::set_hidden (bool yn)
728 if (hidden() != yn) {
731 _flags = Flag (_flags|Hidden);
733 _flags = Flag (_flags & ~Hidden);
736 send_change (HiddenChanged);
741 Region::set_muted (bool yn)
746 _flags = Flag (_flags|Muted);
748 _flags = Flag (_flags & ~Muted);
751 send_change (MuteChanged);
756 Region::set_opaque (bool yn)
758 if (opaque() != yn) {
760 _flags = Flag (_flags|Opaque);
762 _flags = Flag (_flags & ~Opaque);
764 send_change (OpacityChanged);
769 Region::set_locked (bool yn)
771 if (locked() != yn) {
773 _flags = Flag (_flags|Locked);
775 _flags = Flag (_flags & ~Locked);
777 send_change (LockChanged);
782 Region::set_position_locked (bool yn)
784 if (position_locked() != yn) {
786 _flags = Flag (_flags|PositionLocked);
788 _flags = Flag (_flags & ~PositionLocked);
790 send_change (LockChanged);
795 Region::set_sync_position (nframes_t absolute_pos)
799 file_pos = _start + (absolute_pos - _position);
801 if (file_pos != _sync_position) {
803 _sync_position = file_pos;
804 _flags = Flag (_flags|SyncMarked);
809 send_change (SyncOffsetChanged);
814 Region::clear_sync_position ()
816 if (_flags & SyncMarked) {
817 _flags = Flag (_flags & ~SyncMarked);
822 send_change (SyncOffsetChanged);
827 Region::sync_offset (int& dir) const
829 /* returns the sync point relative the first frame of the region */
831 if (_flags & SyncMarked) {
832 if (_sync_position > _start) {
834 return _sync_position - _start;
837 return _start - _sync_position;
846 Region::adjust_to_sync (nframes_t pos)
849 nframes_t offset = sync_offset (sync_dir);
852 if (max_frames - pos > offset) {
867 Region::sync_position() const
869 if (_flags & SyncMarked) {
870 return _sync_position;
878 Region::raise_to_top ()
880 boost::shared_ptr<Playlist> pl (playlist());
882 pl->raise_region_to_top (shared_from_this());
887 Region::lower_to_bottom ()
889 boost::shared_ptr<Playlist> pl (playlist());
891 pl->lower_region_to_bottom (shared_from_this());
896 Region::set_layer (layer_t l)
901 send_change (LayerChanged);
906 Region::state (bool full_state)
908 XMLNode *node = new XMLNode ("Region");
912 _id.print (buf, sizeof (buf));
913 node->add_property ("id", buf);
914 node->add_property ("name", _name);
915 node->add_property ("type", _type.to_string());
916 snprintf (buf, sizeof (buf), "%u", _start);
917 node->add_property ("start", buf);
918 snprintf (buf, sizeof (buf), "%u", _length);
919 node->add_property ("length", buf);
920 snprintf (buf, sizeof (buf), "%u", _position);
921 node->add_property ("position", buf);
923 switch (_first_edit) {
924 case EditChangesNothing:
927 case EditChangesName:
933 default: /* should be unreachable but makes g++ happy */
938 node->add_property ("first_edit", fe);
940 /* note: flags are stored by derived classes */
942 snprintf (buf, sizeof (buf), "%d", (int) _layer);
943 node->add_property ("layer", buf);
944 snprintf (buf, sizeof (buf), "%" PRIu32, _sync_position);
945 node->add_property ("sync-position", buf);
957 Region::set_live_state (const XMLNode& node, Change& what_changed, bool send)
959 const XMLNodeList& nlist = node.children();
960 const XMLProperty *prop;
963 /* this is responsible for setting those aspects of Region state
964 that are mutable after construction.
967 if ((prop = node.property ("name")) == 0) {
968 error << _("XMLNode describing a Region is incomplete (no name)") << endmsg;
972 _name = prop->value();
974 if ((prop = node.property ("type")) == 0) {
975 _type = DataType::AUDIO;
977 _type = DataType(prop->value());
980 if ((prop = node.property ("start")) != 0) {
981 sscanf (prop->value().c_str(), "%" PRIu32, &val);
983 what_changed = Change (what_changed|StartChanged);
990 if ((prop = node.property ("length")) != 0) {
991 sscanf (prop->value().c_str(), "%" PRIu32, &val);
992 if (val != _length) {
993 what_changed = Change (what_changed|LengthChanged);
1000 if ((prop = node.property ("position")) != 0) {
1001 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1002 if (val != _position) {
1003 what_changed = Change (what_changed|PositionChanged);
1010 if ((prop = node.property ("layer")) != 0) {
1012 x = (layer_t) atoi (prop->value().c_str());
1014 what_changed = Change (what_changed|LayerChanged);
1021 if ((prop = node.property ("sync-position")) != 0) {
1022 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1023 if (val != _sync_position) {
1024 what_changed = Change (what_changed|SyncOffsetChanged);
1025 _sync_position = val;
1028 _sync_position = _start;
1031 /* XXX FIRST EDIT !!! */
1033 /* note: derived classes set flags */
1040 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1046 if (child->name () == "extra") {
1047 _extra_xml = new XMLNode (*child);
1053 send_change (what_changed);
1060 Region::set_state (const XMLNode& node)
1062 const XMLProperty *prop;
1063 Change what_changed = Change (0);
1065 /* ID is not allowed to change, ever */
1067 if ((prop = node.property ("id")) == 0) {
1068 error << _("Session: XMLNode describing a Region is incomplete (no id)") << endmsg;
1072 _id = prop->value();
1074 _first_edit = EditChangesNothing;
1076 set_live_state (node, what_changed, true);
1088 Region::thaw (const string& why)
1090 Change what_changed = Change (0);
1093 Glib::Mutex::Lock lm (_lock);
1095 if (_frozen && --_frozen > 0) {
1099 if (_pending_changed) {
1100 what_changed = _pending_changed;
1101 _pending_changed = Change (0);
1105 if (what_changed == Change (0)) {
1109 if (what_changed & LengthChanged) {
1110 if (what_changed & PositionChanged) {
1111 recompute_at_start ();
1113 recompute_at_end ();
1116 StateChanged (what_changed);
1120 Region::send_change (Change what_changed)
1123 Glib::Mutex::Lock lm (_lock);
1125 _pending_changed = Change (_pending_changed|what_changed);
1130 StateChanged (what_changed);
1134 Region::set_last_layer_op (uint64_t when)
1136 _last_layer_op = when;
1140 Region::overlap_equivalent (boost::shared_ptr<const Region> other) const
1142 return coverage (other->first_frame(), other->last_frame()) != OverlapNone;
1146 Region::equivalent (boost::shared_ptr<const Region> other) const
1148 return _start == other->_start &&
1149 _position == other->_position &&
1150 _length == other->_length;
1154 Region::size_equivalent (boost::shared_ptr<const Region> other) const
1156 return _start == other->_start &&
1157 _length == other->_length;
1161 Region::region_list_equivalent (boost::shared_ptr<const Region> other) const
1163 return size_equivalent (other) && source_equivalent (other) && _name == other->_name;
1167 Region::source_deleted (boost::shared_ptr<Source>)
1173 Region::master_source_names ()
1175 SourceList::iterator i;
1177 vector<string> names;
1178 for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1179 names.push_back((*i)->name());
1186 Region::source_equivalent (boost::shared_ptr<const Region> other) const
1191 SourceList::const_iterator i;
1192 SourceList::const_iterator io;
1194 for (i = _sources.begin(), io = other->_sources.begin(); i != _sources.end() && io != other->_sources.end(); ++i, ++io) {
1195 if ((*i)->id() != (*io)->id()) {
1200 for (i = _master_sources.begin(), io = other->_master_sources.begin(); i != _master_sources.end() && io != other->_master_sources.end(); ++i, ++io) {
1201 if ((*i)->id() != (*io)->id()) {
1210 Region::verify_length (nframes_t len)
1212 for (uint32_t n=0; n < _sources.size(); ++n) {
1213 if (_start > _sources[n]->length() - len) {
1221 Region::verify_start_and_length (nframes_t new_start, nframes_t new_length)
1223 for (uint32_t n=0; n < _sources.size(); ++n) {
1224 if (new_length > _sources[n]->length() - new_start) {
1231 Region::verify_start (nframes_t pos)
1233 for (uint32_t n=0; n < _sources.size(); ++n) {
1234 if (pos > _sources[n]->length() - _length) {
1242 Region::verify_start_mutable (nframes_t& new_start)
1244 for (uint32_t n=0; n < _sources.size(); ++n) {
1245 if (new_start > _sources[n]->length() - _length) {
1246 new_start = _sources[n]->length() - _length;
1252 boost::shared_ptr<Region>
1253 Region::get_parent() const
1255 boost::shared_ptr<Playlist> pl (playlist());
1258 boost::shared_ptr<Region> r;
1259 boost::shared_ptr<Region const> grrr2 = boost::dynamic_pointer_cast<Region const> (shared_from_this());
1261 if (grrr2 && (r = pl->session().find_whole_file_parent (grrr2))) {
1262 return boost::static_pointer_cast<Region> (r);
1266 return boost::shared_ptr<Region>();
1270 Region::apply (Filter& filter)
1272 return filter.run (shared_from_this());