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>
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 ();
52 /** Basic Region constructor (single source) */
53 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)
60 , _sync_position(_start)
62 , _first_edit(EditChangesNothing)
65 , _pending_changed(Change (0))
69 _current_state_id = 0;
71 _sources.push_back (src);
72 _master_sources.push_back (src);
73 src->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), src));
75 assert(_sources.size() > 0);
78 /** Basic Region constructor (many sources) */
79 Region::Region (SourceList& srcs, jack_nframes_t start, jack_nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
86 , _sync_position(_start)
88 , _first_edit(EditChangesNothing)
91 , _pending_changed(Change (0))
95 _current_state_id = 0;
97 set<boost::shared_ptr<Source> > unique_srcs;
99 for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) {
100 _sources.push_back (*i);
101 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
102 unique_srcs.insert (*i);
105 for (SourceList::iterator i = srcs.begin(); i != srcs.end(); ++i) {
106 _master_sources.push_back (*i);
107 if (unique_srcs.find (*i) == unique_srcs.end()) {
108 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
112 assert(_sources.size() > 0);
115 /** Create a new Region from part of an existing one */
116 Region::Region (boost::shared_ptr<const Region> other, jack_nframes_t offset, jack_nframes_t length, const string& name, layer_t layer, Flag flags)
118 , _type(other->data_type())
119 , _flags(Flag(flags & ~(Locked|WholeFile|Hidden)))
120 , _start(other->_start + offset)
123 , _sync_position(_start)
125 , _first_edit(EditChangesNothing)
127 , _read_data_count(0)
128 , _pending_changed(Change (0))
132 _current_state_id = 0;
134 if (other->_sync_position < offset)
135 _sync_position = other->_sync_position;
137 set<boost::shared_ptr<Source> > unique_srcs;
139 for (SourceList::const_iterator i= other->_sources.begin(); i != other->_sources.end(); ++i) {
140 _sources.push_back (*i);
141 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
142 unique_srcs.insert (*i);
145 if (other->_sync_position < offset) {
146 _sync_position = other->_sync_position;
149 for (SourceList::const_iterator i = other->_master_sources.begin(); i != other->_master_sources.end(); ++i) {
150 if (unique_srcs.find (*i) == unique_srcs.end()) {
151 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
153 _master_sources.push_back (*i);
156 assert(_sources.size() > 0);
159 /** Pure copy constructor */
160 Region::Region (boost::shared_ptr<const Region> other)
161 : _name(other->_name)
162 , _type(other->data_type())
163 , _flags(Flag(other->_flags & ~Locked))
164 , _start(other->_start)
165 , _length(other->_length)
166 , _position(other->_position)
167 , _sync_position(other->_sync_position)
168 , _layer(other->_layer)
169 , _first_edit(EditChangesID)
171 , _read_data_count(0)
172 , _pending_changed(Change(0))
173 , _last_layer_op(other->_last_layer_op)
176 _current_state_id = 0;
178 other->_first_edit = EditChangesName;
180 if (other->_extra_xml) {
181 _extra_xml = new XMLNode (*other->_extra_xml);
186 set<boost::shared_ptr<Source> > unique_srcs;
188 for (SourceList::const_iterator i = other->_sources.begin(); i != other->_sources.end(); ++i) {
189 _sources.push_back (*i);
190 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
191 unique_srcs.insert (*i);
194 for (SourceList::const_iterator i = other->_master_sources.begin(); i != other->_master_sources.end(); ++i) {
195 _master_sources.push_back (*i);
196 if (unique_srcs.find (*i) == unique_srcs.end()) {
197 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
201 assert(_sources.size() > 0);
204 Region::Region (SourceList& srcs, const XMLNode& node)
205 : _name(X_("error: XML did not reset this"))
206 , _type(DataType::NIL) // to be loaded from XML
211 , _sync_position(_start)
213 , _first_edit(EditChangesNothing)
215 , _read_data_count(0)
216 , _pending_changed(Change(0))
221 _current_state_id = 0;
223 set<boost::shared_ptr<Source> > unique_srcs;
225 for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) {
226 _sources.push_back (*i);
227 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
228 unique_srcs.insert (*i);
231 for (SourceList::iterator i = srcs.begin(); i != srcs.end(); ++i) {
232 _master_sources.push_back (*i);
233 if (unique_srcs.find (*i) == unique_srcs.end()) {
234 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
238 if (set_state (node)) {
239 throw failed_constructor();
242 assert(_type != DataType::NIL);
243 assert(_sources.size() > 0);
246 Region::Region (boost::shared_ptr<Source> src, const XMLNode& node)
247 : _name(X_("error: XML did not reset this"))
248 , _type(DataType::NIL)
253 , _sync_position(_start)
255 , _first_edit(EditChangesNothing)
257 , _read_data_count(0)
258 , _pending_changed(Change(0))
262 _sources.push_back (src);
264 _current_state_id = 0;
266 if (set_state (node)) {
267 throw failed_constructor();
270 assert(_type != DataType::NIL);
271 assert(_sources.size() > 0);
278 /* derived classes must emit GoingAway */
282 Region::set_playlist (Playlist* pl)
288 Region::store_state (RegionState& state) const
290 state._start = _start;
291 state._length = _length;
292 state._position = _position;
293 state._flags = _flags;
294 state._sync_position = _sync_position;
295 state._layer = _layer;
297 state._first_edit = _first_edit;
301 Region::restore_and_return_flags (RegionState& state)
303 Change what_changed = Change (0);
306 Glib::Mutex::Lock lm (_lock);
308 if (_start != state._start) {
309 what_changed = Change (what_changed|StartChanged);
310 _start = state._start;
312 if (_length != state._length) {
313 what_changed = Change (what_changed|LengthChanged);
314 _length = state._length;
316 if (_position != state._position) {
317 what_changed = Change (what_changed|PositionChanged);
318 _position = state._position;
320 if (_sync_position != state._sync_position) {
321 _sync_position = state._sync_position;
322 what_changed = Change (what_changed|SyncOffsetChanged);
324 if (_layer != state._layer) {
325 what_changed = Change (what_changed|LayerChanged);
326 _layer = state._layer;
329 uint32_t old_flags = _flags;
330 _flags = Flag (state._flags);
332 if ((old_flags ^ state._flags) & Muted) {
333 what_changed = Change (what_changed|MuteChanged);
335 if ((old_flags ^ state._flags) & Opaque) {
336 what_changed = Change (what_changed|OpacityChanged);
338 if ((old_flags ^ state._flags) & Locked) {
339 what_changed = Change (what_changed|LockChanged);
342 _first_edit = state._first_edit;
349 Region::set_name (string str)
354 send_change (NameChanged);
359 Region::set_length (jack_nframes_t len, void *src)
361 if (_flags & Locked) {
365 if (_length != len && len != 0) {
367 if (!verify_length (len)) {
373 _flags = Region::Flag (_flags & ~WholeFile);
382 snprintf (buf, sizeof (buf), "length set to %u", len);
386 send_change (LengthChanged);
391 Region::maybe_uncopy ()
396 Region::first_edit ()
398 if (_first_edit != EditChangesNothing && _playlist) {
400 _name = _playlist->session().new_region_name (_name);
401 _first_edit = EditChangesNothing;
403 send_change (NameChanged);
404 RegionFactory::CheckNewRegion (shared_from_this());
409 Region::move_to_natural_position (void *src)
415 boost::shared_ptr<Region> whole_file_region = get_parent();
417 if (whole_file_region) {
418 set_position (whole_file_region->position() + _start, src);
423 Region::special_set_position (jack_nframes_t pos)
425 /* this is used when creating a whole file region as
426 a way to store its "natural" or "captured" position.
433 Region::set_position (jack_nframes_t pos, void *src)
435 if (_flags & Locked) {
439 if (_position != pos) {
444 snprintf (buf, sizeof (buf), "position set to %u", pos);
449 /* do this even if the position is the same. this helps out
450 a GUI that has moved its representation already.
453 send_change (PositionChanged);
457 Region::set_position_on_top (jack_nframes_t pos, void *src)
459 if (_flags & Locked) {
463 if (_position != pos) {
468 snprintf (buf, sizeof (buf), "position set to %u", pos);
473 _playlist->raise_region_to_top (boost::shared_ptr<Region>(this));
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::nudge_position (long n, void *src)
485 if (_flags & Locked) {
494 if (_position > max_frames - n) {
495 _position = max_frames;
500 if (_position < (jack_nframes_t) -n) {
509 snprintf (buf, sizeof (buf), "position set to %u", _position);
513 send_change (PositionChanged);
517 Region::set_start (jack_nframes_t pos, void *src)
519 if (_flags & Locked) {
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);
539 snprintf (buf, sizeof (buf), "start set to %u", pos);
543 send_change (StartChanged);
548 Region::trim_start (jack_nframes_t new_position, void *src)
550 if (_flags & Locked) {
553 jack_nframes_t new_start;
556 if (new_position > _position) {
557 start_shift = new_position - _position;
559 start_shift = -(_position - new_position);
562 if (start_shift > 0) {
564 if (_start > max_frames - start_shift) {
565 new_start = max_frames;
567 new_start = _start + start_shift;
570 if (!verify_start (new_start)) {
574 } else if (start_shift < 0) {
576 if (_start < (jack_nframes_t) -start_shift) {
579 new_start = _start + start_shift;
585 if (new_start == _start) {
590 _flags = Region::Flag (_flags & ~WholeFile);
595 snprintf (buf, sizeof (buf), "slipped start to %u", _start);
599 send_change (StartChanged);
603 Region::trim_front (jack_nframes_t new_position, void *src)
605 if (_flags & Locked) {
609 jack_nframes_t end = _position + _length - 1;
610 jack_nframes_t source_zero;
612 if (_position > _start) {
613 source_zero = _position - _start;
615 source_zero = 0; // its actually negative, but this will work for us
618 if (new_position < end) { /* can't trim it zero or negative length */
620 jack_nframes_t newlen;
622 /* can't trim it back passed where source position zero is located */
624 new_position = max (new_position, source_zero);
627 if (new_position > _position) {
628 newlen = _length - (new_position - _position);
630 newlen = _length + (_position - new_position);
633 trim_to_internal (new_position, newlen, src);
635 recompute_at_start ();
641 Region::trim_end (jack_nframes_t new_endpoint, void *src)
643 if (_flags & Locked) {
647 if (new_endpoint > _position) {
648 trim_to_internal (_position, new_endpoint - _position, this);
656 Region::trim_to (jack_nframes_t position, jack_nframes_t length, void *src)
658 if (_flags & Locked) {
662 trim_to_internal (position, length, src);
665 recompute_at_start ();
671 Region::trim_to_internal (jack_nframes_t position, jack_nframes_t length, void *src)
674 jack_nframes_t new_start;
676 if (_flags & Locked) {
680 if (position > _position) {
681 start_shift = position - _position;
683 start_shift = -(_position - position);
686 if (start_shift > 0) {
688 if (_start > max_frames - start_shift) {
689 new_start = max_frames;
691 new_start = _start + start_shift;
695 } else if (start_shift < 0) {
697 if (_start < (jack_nframes_t) -start_shift) {
700 new_start = _start + start_shift;
706 if (!verify_start_and_length (new_start, length)) {
710 Change what_changed = Change (0);
712 if (_start != new_start) {
714 what_changed = Change (what_changed|StartChanged);
716 if (_length != length) {
718 what_changed = Change (what_changed|LengthChanged);
720 if (_position != position) {
721 _position = position;
722 what_changed = Change (what_changed|PositionChanged);
725 _flags = Region::Flag (_flags & ~WholeFile);
727 if (what_changed & (StartChanged|LengthChanged)) {
735 snprintf (buf, sizeof (buf), "trimmed to %u-%u", _position, _position+_length-1);
739 send_change (what_changed);
744 Region::set_hidden (bool yn)
746 if (hidden() != yn) {
749 _flags = Flag (_flags|Hidden);
751 _flags = Flag (_flags & ~Hidden);
754 send_change (HiddenChanged);
759 Region::set_muted (bool yn)
764 _flags = Flag (_flags|Muted);
766 _flags = Flag (_flags & ~Muted);
772 snprintf (buf, sizeof (buf), "muted");
774 snprintf (buf, sizeof (buf), "unmuted");
779 send_change (MuteChanged);
784 Region::set_opaque (bool yn)
786 if (opaque() != yn) {
790 snprintf (buf, sizeof (buf), "opaque");
791 _flags = Flag (_flags|Opaque);
793 snprintf (buf, sizeof (buf), "translucent");
794 _flags = Flag (_flags & ~Opaque);
798 send_change (OpacityChanged);
803 Region::set_locked (bool yn)
805 if (locked() != yn) {
809 snprintf (buf, sizeof (buf), "locked");
810 _flags = Flag (_flags|Locked);
812 snprintf (buf, sizeof (buf), "unlocked");
813 _flags = Flag (_flags & ~Locked);
817 send_change (LockChanged);
822 Region::set_sync_position (jack_nframes_t absolute_pos)
824 jack_nframes_t file_pos;
826 file_pos = _start + (absolute_pos - _position);
828 if (file_pos != _sync_position) {
830 _sync_position = file_pos;
831 _flags = Flag (_flags|SyncMarked);
836 snprintf (buf, sizeof (buf), "sync point set to %u", _sync_position);
839 send_change (SyncOffsetChanged);
844 Region::clear_sync_position ()
846 if (_flags & SyncMarked) {
847 _flags = Flag (_flags & ~SyncMarked);
851 save_state ("sync point removed");
853 send_change (SyncOffsetChanged);
858 Region::sync_offset (int& dir) const
860 /* returns the sync point relative the first frame of the region */
862 if (_flags & SyncMarked) {
863 if (_sync_position > _start) {
865 return _sync_position - _start;
868 return _start - _sync_position;
877 Region::adjust_to_sync (jack_nframes_t pos)
880 jack_nframes_t offset = sync_offset (sync_dir);
883 if (max_frames - pos > offset) {
898 Region::sync_position() const
900 if (_flags & SyncMarked) {
901 return _sync_position;
911 if (_playlist == 0) {
915 _playlist->raise_region (boost::shared_ptr<Region>(this));
921 if (_playlist == 0) {
925 _playlist->lower_region (boost::shared_ptr<Region>(this));
929 Region::raise_to_top ()
932 if (_playlist == 0) {
936 _playlist->raise_region_to_top (boost::shared_ptr<Region>(this));
940 Region::lower_to_bottom ()
942 if (_playlist == 0) {
946 _playlist->lower_region_to_bottom (boost::shared_ptr<Region>(this));
950 Region::set_layer (layer_t l)
957 snprintf (buf, sizeof (buf), "layer set to %" PRIu32, _layer);
961 send_change (LayerChanged);
966 Region::state (bool full_state)
968 XMLNode *node = new XMLNode ("Region");
972 node->add_property ("id", buf);
973 node->add_property ("name", _name);
974 node->add_property ("type", _type.to_string());
975 snprintf (buf, sizeof (buf), "%u", _start);
976 node->add_property ("start", buf);
977 snprintf (buf, sizeof (buf), "%u", _length);
978 node->add_property ("length", buf);
979 snprintf (buf, sizeof (buf), "%u", _position);
980 node->add_property ("position", buf);
982 /* note: flags are stored by derived classes */
984 snprintf (buf, sizeof (buf), "%d", (int) _layer);
985 node->add_property ("layer", buf);
986 snprintf (buf, sizeof (buf), "%u", _sync_position);
987 node->add_property ("sync-position", buf);
999 Region::set_state (const XMLNode& node)
1001 const XMLNodeList& nlist = node.children();
1002 const XMLProperty *prop;
1009 if ((prop = node.property ("id")) == 0) {
1010 error << _("Session: XMLNode describing a Region is incomplete (no id)") << endmsg;
1014 _id = prop->value();
1016 if ((prop = node.property ("name")) == 0) {
1017 error << _("Session: XMLNode describing a Region is incomplete (no name)") << endmsg;
1021 _name = prop->value();
1023 if ((prop = node.property ("type")) == 0) {
1024 _type = DataType::AUDIO;
1026 _type = DataType(prop->value());
1029 if ((prop = node.property ("start")) != 0) {
1030 _start = (jack_nframes_t) atoi (prop->value().c_str());
1033 if ((prop = node.property ("length")) != 0) {
1034 _length = (jack_nframes_t) atoi (prop->value().c_str());
1037 if ((prop = node.property ("position")) != 0) {
1038 _position = (jack_nframes_t) atoi (prop->value().c_str());
1041 if ((prop = node.property ("layer")) != 0) {
1042 _layer = (layer_t) atoi (prop->value().c_str());
1045 /* note: derived classes set flags */
1047 if ((prop = node.property ("sync-position")) != 0) {
1048 _sync_position = (jack_nframes_t) atoi (prop->value().c_str());
1050 _sync_position = _start;
1053 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1059 if (child->name () == "extra") {
1060 _extra_xml = new XMLNode (*child);
1065 _first_edit = EditChangesNothing;
1077 Region::thaw (const string& why)
1079 Change what_changed = Change (0);
1082 Glib::Mutex::Lock lm (_lock);
1084 if (_frozen && --_frozen > 0) {
1088 if (_pending_changed) {
1089 what_changed = _pending_changed;
1090 _pending_changed = Change (0);
1094 if (what_changed == Change (0)) {
1098 if (what_changed & LengthChanged) {
1099 if (what_changed & PositionChanged) {
1100 recompute_at_start ();
1102 recompute_at_end ();
1106 StateChanged (what_changed);
1110 Region::send_change (Change what_changed)
1113 Glib::Mutex::Lock lm (_lock);
1115 _pending_changed = Change (_pending_changed|what_changed);
1120 StateManager::send_state_changed (what_changed);
1124 Region::set_last_layer_op (uint64_t when)
1126 _last_layer_op = when;
1130 Region::overlap_equivalent (boost::shared_ptr<const Region> other) const
1132 return coverage (other->first_frame(), other->last_frame()) != OverlapNone;
1136 Region::equivalent (boost::shared_ptr<const Region> other) const
1138 return _start == other->_start &&
1139 _position == other->_position &&
1140 _length == other->_length;
1144 Region::size_equivalent (boost::shared_ptr<const Region> other) const
1146 return _start == other->_start &&
1147 _length == other->_length;
1151 Region::region_list_equivalent (boost::shared_ptr<const Region> other) const
1153 return size_equivalent (other) && source_equivalent (other) && _name == other->_name;
1157 Region::source_deleted (boost::shared_ptr<Source>)
1163 Region::master_source_names ()
1165 SourceList::iterator i;
1167 vector<string> names;
1168 for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1169 names.push_back((*i)->name());
1176 Region::source_equivalent (boost::shared_ptr<const Region> other) const
1181 SourceList::const_iterator i;
1182 SourceList::const_iterator io;
1184 for (i = _sources.begin(), io = other->_sources.begin(); i != _sources.end() && io != other->_sources.end(); ++i, ++io) {
1185 if ((*i)->id() != (*io)->id()) {
1190 for (i = _master_sources.begin(), io = other->_master_sources.begin(); i != _master_sources.end() && io != other->_master_sources.end(); ++i, ++io) {
1191 if ((*i)->id() != (*io)->id()) {
1200 Region::verify_length (jack_nframes_t len)
1202 for (uint32_t n=0; n < _sources.size(); ++n) {
1203 if (_start > _sources[n]->length() - len) {
1211 Region::verify_start_and_length (jack_nframes_t new_start, jack_nframes_t new_length)
1213 for (uint32_t n=0; n < _sources.size(); ++n) {
1214 if (new_length > _sources[n]->length() - new_start) {
1221 Region::verify_start (jack_nframes_t pos)
1223 for (uint32_t n=0; n < _sources.size(); ++n) {
1224 if (pos > _sources[n]->length() - _length) {
1232 Region::verify_start_mutable (jack_nframes_t& new_start)
1234 for (uint32_t n=0; n < _sources.size(); ++n) {
1235 if (new_start > _sources[n]->length() - _length) {
1236 new_start = _sources[n]->length() - _length;
1242 boost::shared_ptr<Region>
1243 Region::get_parent()
1245 boost::shared_ptr<Region> r;
1248 r = _playlist->session().find_whole_file_parent (*this);