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>
40 using namespace ARDOUR;
43 Change Region::FadeChanged = ARDOUR::new_change ();
44 Change Region::SyncOffsetChanged = ARDOUR::new_change ();
45 Change Region::MuteChanged = ARDOUR::new_change ();
46 Change Region::OpacityChanged = ARDOUR::new_change ();
47 Change Region::LockChanged = ARDOUR::new_change ();
48 Change Region::LayerChanged = ARDOUR::new_change ();
49 Change Region::HiddenChanged = ARDOUR::new_change ();
51 sigc::signal<void,Region *> Region::CheckNewRegion;
53 /** Basic Region constructor (single source) */
54 Region::Region (Source& src, jack_nframes_t start, jack_nframes_t length, const string& name, 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 (mem_fun (*this, &Region::source_deleted));
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, layer_t layer, Region::Flag flags)
85 , _sync_position(_start)
87 , _first_edit(EditChangesNothing)
90 , _pending_changed(Change (0))
94 _current_state_id = 0;
96 set<Source*> unique_srcs;
98 for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) {
99 _sources.push_back (*i);
100 (*i)->GoingAway.connect (mem_fun (*this, &Region::source_deleted));
101 unique_srcs.insert (*i);
104 for (SourceList::iterator i = srcs.begin(); i != srcs.end(); ++i) {
105 _master_sources.push_back (*i);
106 if (unique_srcs.find (*i) == unique_srcs.end()) {
107 (*i)->GoingAway.connect (mem_fun (*this, &Region::source_deleted));
111 assert(_sources.size() > 0);
114 /** Create a new Region from part of an existing one */
115 Region::Region (const Region& other, jack_nframes_t offset, jack_nframes_t length, const string& name, layer_t layer, Flag flags)
117 , _flags(Flag(flags & ~(Locked|WholeFile|Hidden)))
118 , _start(other._start + offset)
121 , _sync_position(_start)
123 , _first_edit(EditChangesNothing)
125 , _read_data_count(0)
126 , _pending_changed(Change (0))
130 _current_state_id = 0;
132 if (other._sync_position < offset)
133 _sync_position = other._sync_position;
135 set<Source*> unique_srcs;
137 for (SourceList::const_iterator i= other._sources.begin(); i != other._sources.end(); ++i) {
138 _sources.push_back (*i);
139 (*i)->GoingAway.connect (mem_fun (*this, &Region::source_deleted));
140 unique_srcs.insert (*i);
143 for (SourceList::const_iterator i = other._master_sources.begin(); i != other._master_sources.end(); ++i) {
144 if (unique_srcs.find (*i) == unique_srcs.end()) {
145 (*i)->GoingAway.connect (mem_fun (*this, &Region::source_deleted));
147 _master_sources.push_back (*i);
150 assert(_sources.size() > 0);
153 /** Pure copy constructor */
154 Region::Region (const Region &other)
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)
169 _current_state_id = 0;
171 other._first_edit = EditChangesName;
173 if (other._extra_xml) {
174 _extra_xml = new XMLNode (*other._extra_xml);
179 set<Source*> unique_srcs;
181 for (SourceList::const_iterator i = other._sources.begin(); i != other._sources.end(); ++i) {
182 _sources.push_back (*i);
183 (*i)->GoingAway.connect (mem_fun (*this, &Region::source_deleted));
184 unique_srcs.insert (*i);
187 for (SourceList::const_iterator i = other._master_sources.begin(); i != other._master_sources.end(); ++i) {
188 _master_sources.push_back (*i);
189 if (unique_srcs.find (*i) == unique_srcs.end()) {
190 (*i)->GoingAway.connect (mem_fun (*this, &Region::source_deleted));
194 assert(_sources.size() > 0);
197 Region::Region (SourceList& srcs, const XMLNode& node)
198 : _name(X_("error: XML did not reset this"))
203 , _sync_position(_start)
205 , _first_edit(EditChangesNothing)
207 , _read_data_count(0)
208 , _pending_changed(Change(0))
213 set<Source*> unique_srcs;
215 for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) {
216 _sources.push_back (*i);
217 (*i)->GoingAway.connect (mem_fun (*this, &Region::source_deleted));
218 unique_srcs.insert (*i);
221 for (SourceList::iterator i = srcs.begin(); i != srcs.end(); ++i) {
222 _master_sources.push_back (*i);
223 if (unique_srcs.find (*i) == unique_srcs.end()) {
224 (*i)->GoingAway.connect (mem_fun (*this, &Region::source_deleted));
228 _current_state_id = 0;
230 if (set_state (node)) {
231 throw failed_constructor();
234 assert(_sources.size() > 0);
237 Region::Region (Source& src, const XMLNode& node)
238 : _name(X_("error: XML did not reset this"))
243 , _sync_position(_start)
245 , _first_edit(EditChangesNothing)
247 , _read_data_count(0)
248 , _pending_changed(Change(0))
252 _sources.push_back (&src);
254 _current_state_id = 0;
256 if (set_state (node)) {
257 throw failed_constructor();
260 assert(_sources.size() > 0);
268 Region::set_playlist (Playlist* pl)
274 Region::store_state (RegionState& state) const
276 state._start = _start;
277 state._length = _length;
278 state._position = _position;
279 state._flags = _flags;
280 state._sync_position = _sync_position;
281 state._layer = _layer;
283 state._first_edit = _first_edit;
287 Region::restore_and_return_flags (RegionState& state)
289 Change what_changed = Change (0);
292 Glib::Mutex::Lock lm (_lock);
294 if (_start != state._start) {
295 what_changed = Change (what_changed|StartChanged);
296 _start = state._start;
298 if (_length != state._length) {
299 what_changed = Change (what_changed|LengthChanged);
300 _length = state._length;
302 if (_position != state._position) {
303 what_changed = Change (what_changed|PositionChanged);
304 _position = state._position;
306 if (_sync_position != state._sync_position) {
307 _sync_position = state._sync_position;
308 what_changed = Change (what_changed|SyncOffsetChanged);
310 if (_layer != state._layer) {
311 what_changed = Change (what_changed|LayerChanged);
312 _layer = state._layer;
315 uint32_t old_flags = _flags;
316 _flags = Flag (state._flags);
318 if ((old_flags ^ state._flags) & Muted) {
319 what_changed = Change (what_changed|MuteChanged);
321 if ((old_flags ^ state._flags) & Opaque) {
322 what_changed = Change (what_changed|OpacityChanged);
324 if ((old_flags ^ state._flags) & Locked) {
325 what_changed = Change (what_changed|LockChanged);
328 _first_edit = state._first_edit;
335 Region::set_name (string str)
340 send_change (NameChanged);
345 Region::set_length (jack_nframes_t len, void *src)
347 if (_flags & Locked) {
351 if (_length != len && len != 0) {
353 if (!verify_length (len)) {
359 _flags = Region::Flag (_flags & ~WholeFile);
368 snprintf (buf, sizeof (buf), "length set to %u", len);
372 send_change (LengthChanged);
377 Region::maybe_uncopy ()
382 Region::first_edit ()
384 if (_first_edit != EditChangesNothing && _playlist) {
386 _name = _playlist->session().new_region_name (_name);
387 _first_edit = EditChangesNothing;
389 send_change (NameChanged);
390 CheckNewRegion (this);
395 Region::move_to_natural_position (void *src)
401 Region* whole_file_region = get_parent();
403 if (whole_file_region) {
404 set_position (whole_file_region->position() + _start, src);
409 Region::special_set_position (jack_nframes_t pos)
411 /* this is used when creating a whole file region as
412 a way to store its "natural" or "captured" position.
419 Region::set_position (jack_nframes_t pos, void *src)
421 if (_flags & Locked) {
425 if (_position != pos) {
430 snprintf (buf, sizeof (buf), "position set to %u", pos);
435 /* do this even if the position is the same. this helps out
436 a GUI that has moved its representation already.
439 send_change (PositionChanged);
443 Region::set_position_on_top (jack_nframes_t pos, void *src)
445 if (_flags & Locked) {
449 if (_position != pos) {
454 snprintf (buf, sizeof (buf), "position set to %u", pos);
459 _playlist->raise_region_to_top (*this);
461 /* do this even if the position is the same. this helps out
462 a GUI that has moved its representation already.
465 send_change (PositionChanged);
469 Region::nudge_position (long n, void *src)
471 if (_flags & Locked) {
480 if (_position > max_frames - n) {
481 _position = max_frames;
486 if (_position < (jack_nframes_t) -n) {
495 snprintf (buf, sizeof (buf), "position set to %u", _position);
499 send_change (PositionChanged);
503 Region::set_start (jack_nframes_t pos, void *src)
505 if (_flags & Locked) {
508 /* This just sets the start, nothing else. It effectively shifts
509 the contents of the Region within the overall extent of the Source,
510 without changing the Region's position or length
515 if (!verify_start (pos)) {
520 _flags = Region::Flag (_flags & ~WholeFile);
525 snprintf (buf, sizeof (buf), "start set to %u", pos);
529 send_change (StartChanged);
534 Region::trim_start (jack_nframes_t new_position, void *src)
536 if (_flags & Locked) {
539 jack_nframes_t new_start;
542 if (new_position > _position) {
543 start_shift = new_position - _position;
545 start_shift = -(_position - new_position);
548 if (start_shift > 0) {
550 if (_start > max_frames - start_shift) {
551 new_start = max_frames;
553 new_start = _start + start_shift;
556 if (!verify_start (new_start)) {
560 } else if (start_shift < 0) {
562 if (_start < (jack_nframes_t) -start_shift) {
565 new_start = _start + start_shift;
571 if (new_start == _start) {
576 _flags = Region::Flag (_flags & ~WholeFile);
581 snprintf (buf, sizeof (buf), "slipped start to %u", _start);
585 send_change (StartChanged);
589 Region::trim_front (jack_nframes_t new_position, void *src)
591 if (_flags & Locked) {
595 jack_nframes_t end = _position + _length - 1;
596 jack_nframes_t source_zero;
598 if (_position > _start) {
599 source_zero = _position - _start;
601 source_zero = 0; // its actually negative, but this will work for us
604 if (new_position < end) { /* can't trim it zero or negative length */
606 jack_nframes_t newlen;
608 /* can't trim it back passed where source position zero is located */
610 new_position = max (new_position, source_zero);
613 if (new_position > _position) {
614 newlen = _length - (new_position - _position);
616 newlen = _length + (_position - new_position);
619 trim_to_internal (new_position, newlen, src);
621 recompute_at_start ();
627 Region::trim_end (jack_nframes_t new_endpoint, void *src)
629 if (_flags & Locked) {
633 if (new_endpoint > _position) {
634 trim_to_internal (_position, new_endpoint - _position, this);
642 Region::trim_to (jack_nframes_t position, jack_nframes_t length, void *src)
644 if (_flags & Locked) {
648 trim_to_internal (position, length, src);
651 recompute_at_start ();
657 Region::trim_to_internal (jack_nframes_t position, jack_nframes_t length, void *src)
660 jack_nframes_t new_start;
662 if (_flags & Locked) {
666 if (position > _position) {
667 start_shift = position - _position;
669 start_shift = -(_position - position);
672 if (start_shift > 0) {
674 if (_start > max_frames - start_shift) {
675 new_start = max_frames;
677 new_start = _start + start_shift;
681 } else if (start_shift < 0) {
683 if (_start < (jack_nframes_t) -start_shift) {
686 new_start = _start + start_shift;
692 if (!verify_start_and_length (new_start, length)) {
696 Change what_changed = Change (0);
698 if (_start != new_start) {
700 what_changed = Change (what_changed|StartChanged);
702 if (_length != length) {
704 what_changed = Change (what_changed|LengthChanged);
706 if (_position != position) {
707 _position = position;
708 what_changed = Change (what_changed|PositionChanged);
711 _flags = Region::Flag (_flags & ~WholeFile);
713 if (what_changed & (StartChanged|LengthChanged)) {
721 snprintf (buf, sizeof (buf), "trimmed to %u-%u", _position, _position+_length-1);
725 send_change (what_changed);
730 Region::set_hidden (bool yn)
732 if (hidden() != yn) {
735 _flags = Flag (_flags|Hidden);
737 _flags = Flag (_flags & ~Hidden);
740 send_change (HiddenChanged);
745 Region::set_muted (bool yn)
750 _flags = Flag (_flags|Muted);
752 _flags = Flag (_flags & ~Muted);
758 snprintf (buf, sizeof (buf), "muted");
760 snprintf (buf, sizeof (buf), "unmuted");
765 send_change (MuteChanged);
770 Region::set_opaque (bool yn)
772 if (opaque() != yn) {
776 snprintf (buf, sizeof (buf), "opaque");
777 _flags = Flag (_flags|Opaque);
779 snprintf (buf, sizeof (buf), "translucent");
780 _flags = Flag (_flags & ~Opaque);
784 send_change (OpacityChanged);
789 Region::set_locked (bool yn)
791 if (locked() != yn) {
795 snprintf (buf, sizeof (buf), "locked");
796 _flags = Flag (_flags|Locked);
798 snprintf (buf, sizeof (buf), "unlocked");
799 _flags = Flag (_flags & ~Locked);
803 send_change (LockChanged);
808 Region::set_sync_position (jack_nframes_t absolute_pos)
810 jack_nframes_t file_pos;
812 file_pos = _start + (absolute_pos - _position);
814 if (file_pos != _sync_position) {
816 _sync_position = file_pos;
817 _flags = Flag (_flags|SyncMarked);
822 snprintf (buf, sizeof (buf), "sync point set to %u", _sync_position);
825 send_change (SyncOffsetChanged);
830 Region::clear_sync_position ()
832 if (_flags & SyncMarked) {
833 _flags = Flag (_flags & ~SyncMarked);
837 save_state ("sync point removed");
839 send_change (SyncOffsetChanged);
844 Region::sync_offset (int& dir) const
846 /* returns the sync point relative the first frame of the region */
848 if (_flags & SyncMarked) {
849 if (_sync_position > _start) {
851 return _sync_position - _start;
854 return _start - _sync_position;
863 Region::adjust_to_sync (jack_nframes_t pos)
866 jack_nframes_t offset = sync_offset (sync_dir);
869 if (max_frames - pos > offset) {
884 Region::sync_position() const
886 if (_flags & SyncMarked) {
887 return _sync_position;
897 if (_playlist == 0) {
901 _playlist->raise_region (*this);
907 if (_playlist == 0) {
911 _playlist->lower_region (*this);
915 Region::raise_to_top ()
918 if (_playlist == 0) {
922 _playlist->raise_region_to_top (*this);
926 Region::lower_to_bottom ()
928 if (_playlist == 0) {
932 _playlist->lower_region_to_bottom (*this);
936 Region::set_layer (layer_t l)
943 snprintf (buf, sizeof (buf), "layer set to %" PRIu32, _layer);
947 send_change (LayerChanged);
952 Region::state (bool full_state)
954 XMLNode *node = new XMLNode ("Region");
958 node->add_property ("id", buf);
959 node->add_property ("name", _name);
960 snprintf (buf, sizeof (buf), "%u", _start);
961 node->add_property ("start", buf);
962 snprintf (buf, sizeof (buf), "%u", _length);
963 node->add_property ("length", buf);
964 snprintf (buf, sizeof (buf), "%u", _position);
965 node->add_property ("position", buf);
967 /* note: flags are stored by derived classes */
969 snprintf (buf, sizeof (buf), "%d", (int) _layer);
970 node->add_property ("layer", buf);
971 snprintf (buf, sizeof (buf), "%u", _sync_position);
972 node->add_property ("sync-position", buf);
984 Region::set_state (const XMLNode& node)
986 const XMLNodeList& nlist = node.children();
987 const XMLProperty *prop;
994 if ((prop = node.property ("id")) == 0) {
995 error << _("Session: XMLNode describing a Region is incomplete (no id)") << endmsg;
1001 if ((prop = node.property ("name")) == 0) {
1002 error << _("Session: XMLNode describing a Region is incomplete (no name)") << endmsg;
1006 _name = prop->value();
1008 if ((prop = node.property ("start")) != 0) {
1009 _start = (jack_nframes_t) atoi (prop->value().c_str());
1012 if ((prop = node.property ("length")) != 0) {
1013 _length = (jack_nframes_t) atoi (prop->value().c_str());
1016 if ((prop = node.property ("position")) != 0) {
1017 _position = (jack_nframes_t) atoi (prop->value().c_str());
1020 if ((prop = node.property ("layer")) != 0) {
1021 _layer = (layer_t) atoi (prop->value().c_str());
1024 /* note: derived classes set flags */
1026 if ((prop = node.property ("sync-position")) != 0) {
1027 _sync_position = (jack_nframes_t) atoi (prop->value().c_str());
1029 _sync_position = _start;
1032 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1038 if (child->name () == "extra") {
1039 _extra_xml = new XMLNode (*child);
1044 _first_edit = EditChangesNothing;
1056 Region::thaw (const string& why)
1058 Change what_changed = Change (0);
1061 Glib::Mutex::Lock lm (_lock);
1063 if (_frozen && --_frozen > 0) {
1067 if (_pending_changed) {
1068 what_changed = _pending_changed;
1069 _pending_changed = Change (0);
1073 if (what_changed == Change (0)) {
1077 if (what_changed & LengthChanged) {
1078 if (what_changed & PositionChanged) {
1079 recompute_at_start ();
1081 recompute_at_end ();
1085 StateChanged (what_changed);
1089 Region::send_change (Change what_changed)
1092 Glib::Mutex::Lock lm (_lock);
1094 _pending_changed = Change (_pending_changed|what_changed);
1099 StateManager::send_state_changed (what_changed);
1103 Region::set_last_layer_op (uint64_t when)
1105 _last_layer_op = when;
1109 Region::overlap_equivalent (const Region& other) const
1111 return coverage (other.first_frame(), other.last_frame()) != OverlapNone;
1115 Region::equivalent (const Region& other) const
1117 return _start == other._start &&
1118 _position == other._position &&
1119 _length == other._length;
1123 Region::size_equivalent (const Region& other) const
1125 return _start == other._start &&
1126 _length == other._length;
1130 Region::region_list_equivalent (const Region& other) const
1132 return size_equivalent (other) && source_equivalent (other) && _name == other._name;
1136 Region::source_deleted (Source* ignored)
1142 Region::lock_sources ()
1144 SourceList::iterator i;
1145 set<Source*> unique_srcs;
1147 for (i = _sources.begin(); i != _sources.end(); ++i) {
1148 unique_srcs.insert (*i);
1152 for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1153 if (unique_srcs.find (*i) == unique_srcs.end()) {
1160 Region::unlock_sources ()
1162 SourceList::iterator i;
1163 set<Source*> unique_srcs;
1165 for (i = _sources.begin(); i != _sources.end(); ++i) {
1166 unique_srcs.insert (*i);
1170 for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1171 if (unique_srcs.find (*i) == unique_srcs.end()) {
1178 Region::master_source_names ()
1180 SourceList::iterator i;
1182 vector<string> names;
1183 for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1184 names.push_back((*i)->name());
1191 Region::source_equivalent (const Region& other) const
1193 SourceList::const_iterator i;
1194 SourceList::const_iterator io;
1196 for (i = _sources.begin(), io = other._sources.begin(); i != _sources.end() && io != other._sources.end(); ++i, ++io) {
1197 if ((*i)->id() != (*io)->id()) {
1202 for (i = _master_sources.begin(), io = other._master_sources.begin(); i != _master_sources.end() && io != other._master_sources.end(); ++i, ++io) {
1203 if ((*i)->id() != (*io)->id()) {
1212 Region::verify_length (jack_nframes_t len)
1214 for (uint32_t n=0; n < _sources.size(); ++n) {
1215 if (_start > _sources[n]->length() - len) {
1223 Region::verify_start_and_length (jack_nframes_t new_start, jack_nframes_t new_length)
1225 for (uint32_t n=0; n < _sources.size(); ++n) {
1226 if (new_length > _sources[n]->length() - new_start) {
1233 Region::verify_start (jack_nframes_t pos)
1235 for (uint32_t n=0; n < _sources.size(); ++n) {
1236 if (pos > _sources[n]->length() - _length) {
1244 Region::verify_start_mutable (jack_nframes_t& new_start)
1246 for (uint32_t n=0; n < _sources.size(); ++n) {
1247 if (new_start > _sources[n]->length() - _length) {
1248 new_start = _sources[n]->length() - _length;
1255 Region::get_parent()
1260 r = _playlist->session().find_whole_file_parent (*this);