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, DataType type, layer_t layer, Region::Flag flags)
61 , _sync_position(_start)
63 , _first_edit(EditChangesNothing)
66 , _pending_changed(Change (0))
70 _current_state_id = 0;
72 _sources.push_back (&src);
73 _master_sources.push_back (&src);
74 src.GoingAway.connect (mem_fun (*this, &Region::source_deleted));
76 assert(_sources.size() > 0);
79 /** Basic Region constructor (many sources) */
80 Region::Region (SourceList& srcs, jack_nframes_t start, jack_nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
87 , _sync_position(_start)
89 , _first_edit(EditChangesNothing)
92 , _pending_changed(Change (0))
96 _current_state_id = 0;
98 set<Source*> unique_srcs;
100 for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) {
101 _sources.push_back (*i);
102 (*i)->GoingAway.connect (mem_fun (*this, &Region::source_deleted));
103 unique_srcs.insert (*i);
106 for (SourceList::iterator i = srcs.begin(); i != srcs.end(); ++i) {
107 _master_sources.push_back (*i);
108 if (unique_srcs.find (*i) == unique_srcs.end()) {
109 (*i)->GoingAway.connect (mem_fun (*this, &Region::source_deleted));
113 assert(_sources.size() > 0);
116 /** Create a new Region from part of an existing one */
117 Region::Region (const Region& other, jack_nframes_t offset, jack_nframes_t length, const string& name, layer_t layer, Flag flags)
119 , _type(other.data_type())
120 , _flags(Flag(flags & ~(Locked|WholeFile|Hidden)))
121 , _start(other._start + offset)
124 , _sync_position(_start)
126 , _first_edit(EditChangesNothing)
128 , _read_data_count(0)
129 , _pending_changed(Change (0))
133 _current_state_id = 0;
135 if (other._sync_position < offset)
136 _sync_position = other._sync_position;
138 set<Source*> unique_srcs;
140 for (SourceList::const_iterator i= other._sources.begin(); i != other._sources.end(); ++i) {
141 _sources.push_back (*i);
142 (*i)->GoingAway.connect (mem_fun (*this, &Region::source_deleted));
143 unique_srcs.insert (*i);
146 for (SourceList::const_iterator i = other._master_sources.begin(); i != other._master_sources.end(); ++i) {
147 if (unique_srcs.find (*i) == unique_srcs.end()) {
148 (*i)->GoingAway.connect (mem_fun (*this, &Region::source_deleted));
150 _master_sources.push_back (*i);
153 assert(_sources.size() > 0);
156 /** Pure copy constructor */
157 Region::Region (const Region &other)
159 , _type(other.data_type())
160 , _flags(Flag(other._flags & ~Locked))
161 , _start(other._start)
162 , _length(other._length)
163 , _position(other._position)
164 , _sync_position(other._sync_position)
165 , _layer(other._layer)
166 , _first_edit(EditChangesID)
168 , _read_data_count(0)
169 , _pending_changed(Change(0))
170 , _last_layer_op(other._last_layer_op)
173 _current_state_id = 0;
175 other._first_edit = EditChangesName;
177 if (other._extra_xml) {
178 _extra_xml = new XMLNode (*other._extra_xml);
183 set<Source*> unique_srcs;
185 for (SourceList::const_iterator i = other._sources.begin(); i != other._sources.end(); ++i) {
186 _sources.push_back (*i);
187 (*i)->GoingAway.connect (mem_fun (*this, &Region::source_deleted));
188 unique_srcs.insert (*i);
191 for (SourceList::const_iterator i = other._master_sources.begin(); i != other._master_sources.end(); ++i) {
192 _master_sources.push_back (*i);
193 if (unique_srcs.find (*i) == unique_srcs.end()) {
194 (*i)->GoingAway.connect (mem_fun (*this, &Region::source_deleted));
198 assert(_sources.size() > 0);
201 Region::Region (SourceList& srcs, const XMLNode& node)
202 : _name(X_("error: XML did not reset this"))
203 , _type(DataType::NIL) // to be loaded from XML
208 , _sync_position(_start)
210 , _first_edit(EditChangesNothing)
212 , _read_data_count(0)
213 , _pending_changed(Change(0))
218 set<Source*> unique_srcs;
220 for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) {
221 _sources.push_back (*i);
222 (*i)->GoingAway.connect (mem_fun (*this, &Region::source_deleted));
223 unique_srcs.insert (*i);
226 for (SourceList::iterator i = srcs.begin(); i != srcs.end(); ++i) {
227 _master_sources.push_back (*i);
228 if (unique_srcs.find (*i) == unique_srcs.end()) {
229 (*i)->GoingAway.connect (mem_fun (*this, &Region::source_deleted));
233 _current_state_id = 0;
235 if (set_state (node)) {
236 throw failed_constructor();
239 assert(_type != DataType::NIL);
240 assert(_sources.size() > 0);
243 Region::Region (Source& src, const XMLNode& node)
244 : _name(X_("error: XML did not reset this"))
245 , _type(DataType::NIL)
250 , _sync_position(_start)
252 , _first_edit(EditChangesNothing)
254 , _read_data_count(0)
255 , _pending_changed(Change(0))
259 _sources.push_back (&src);
261 _current_state_id = 0;
263 if (set_state (node)) {
264 throw failed_constructor();
267 assert(_type != DataType::NIL);
268 assert(_sources.size() > 0);
276 Region::set_playlist (Playlist* pl)
282 Region::store_state (RegionState& state) const
284 state._start = _start;
285 state._length = _length;
286 state._position = _position;
287 state._flags = _flags;
288 state._sync_position = _sync_position;
289 state._layer = _layer;
291 state._first_edit = _first_edit;
295 Region::restore_and_return_flags (RegionState& state)
297 Change what_changed = Change (0);
300 Glib::Mutex::Lock lm (_lock);
302 if (_start != state._start) {
303 what_changed = Change (what_changed|StartChanged);
304 _start = state._start;
306 if (_length != state._length) {
307 what_changed = Change (what_changed|LengthChanged);
308 _length = state._length;
310 if (_position != state._position) {
311 what_changed = Change (what_changed|PositionChanged);
312 _position = state._position;
314 if (_sync_position != state._sync_position) {
315 _sync_position = state._sync_position;
316 what_changed = Change (what_changed|SyncOffsetChanged);
318 if (_layer != state._layer) {
319 what_changed = Change (what_changed|LayerChanged);
320 _layer = state._layer;
323 uint32_t old_flags = _flags;
324 _flags = Flag (state._flags);
326 if ((old_flags ^ state._flags) & Muted) {
327 what_changed = Change (what_changed|MuteChanged);
329 if ((old_flags ^ state._flags) & Opaque) {
330 what_changed = Change (what_changed|OpacityChanged);
332 if ((old_flags ^ state._flags) & Locked) {
333 what_changed = Change (what_changed|LockChanged);
336 _first_edit = state._first_edit;
343 Region::set_name (string str)
348 send_change (NameChanged);
353 Region::set_length (jack_nframes_t len, void *src)
355 if (_flags & Locked) {
359 if (_length != len && len != 0) {
361 if (!verify_length (len)) {
367 _flags = Region::Flag (_flags & ~WholeFile);
376 snprintf (buf, sizeof (buf), "length set to %u", len);
380 send_change (LengthChanged);
385 Region::maybe_uncopy ()
390 Region::first_edit ()
392 if (_first_edit != EditChangesNothing && _playlist) {
394 _name = _playlist->session().new_region_name (_name);
395 _first_edit = EditChangesNothing;
397 send_change (NameChanged);
398 CheckNewRegion (this);
403 Region::move_to_natural_position (void *src)
409 Region* whole_file_region = get_parent();
411 if (whole_file_region) {
412 set_position (whole_file_region->position() + _start, src);
417 Region::special_set_position (jack_nframes_t pos)
419 /* this is used when creating a whole file region as
420 a way to store its "natural" or "captured" position.
427 Region::set_position (jack_nframes_t pos, void *src)
429 if (_flags & Locked) {
433 if (_position != pos) {
438 snprintf (buf, sizeof (buf), "position set to %u", pos);
443 /* do this even if the position is the same. this helps out
444 a GUI that has moved its representation already.
447 send_change (PositionChanged);
451 Region::set_position_on_top (jack_nframes_t pos, void *src)
453 if (_flags & Locked) {
457 if (_position != pos) {
462 snprintf (buf, sizeof (buf), "position set to %u", pos);
467 _playlist->raise_region_to_top (*this);
469 /* do this even if the position is the same. this helps out
470 a GUI that has moved its representation already.
473 send_change (PositionChanged);
477 Region::nudge_position (long n, void *src)
479 if (_flags & Locked) {
488 if (_position > max_frames - n) {
489 _position = max_frames;
494 if (_position < (jack_nframes_t) -n) {
503 snprintf (buf, sizeof (buf), "position set to %u", _position);
507 send_change (PositionChanged);
511 Region::set_start (jack_nframes_t pos, void *src)
513 if (_flags & Locked) {
516 /* This just sets the start, nothing else. It effectively shifts
517 the contents of the Region within the overall extent of the Source,
518 without changing the Region's position or length
523 if (!verify_start (pos)) {
528 _flags = Region::Flag (_flags & ~WholeFile);
533 snprintf (buf, sizeof (buf), "start set to %u", pos);
537 send_change (StartChanged);
542 Region::trim_start (jack_nframes_t new_position, void *src)
544 if (_flags & Locked) {
547 jack_nframes_t new_start;
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 < (jack_nframes_t) -start_shift) {
573 new_start = _start + start_shift;
579 if (new_start == _start) {
584 _flags = Region::Flag (_flags & ~WholeFile);
589 snprintf (buf, sizeof (buf), "slipped start to %u", _start);
593 send_change (StartChanged);
597 Region::trim_front (jack_nframes_t new_position, void *src)
599 if (_flags & Locked) {
603 jack_nframes_t end = _position + _length - 1;
604 jack_nframes_t source_zero;
606 if (_position > _start) {
607 source_zero = _position - _start;
609 source_zero = 0; // its actually negative, but this will work for us
612 if (new_position < end) { /* can't trim it zero or negative length */
614 jack_nframes_t newlen;
616 /* can't trim it back passed where source position zero is located */
618 new_position = max (new_position, source_zero);
621 if (new_position > _position) {
622 newlen = _length - (new_position - _position);
624 newlen = _length + (_position - new_position);
627 trim_to_internal (new_position, newlen, src);
629 recompute_at_start ();
635 Region::trim_end (jack_nframes_t new_endpoint, void *src)
637 if (_flags & Locked) {
641 if (new_endpoint > _position) {
642 trim_to_internal (_position, new_endpoint - _position, this);
650 Region::trim_to (jack_nframes_t position, jack_nframes_t length, void *src)
652 if (_flags & Locked) {
656 trim_to_internal (position, length, src);
659 recompute_at_start ();
665 Region::trim_to_internal (jack_nframes_t position, jack_nframes_t length, void *src)
668 jack_nframes_t new_start;
670 if (_flags & Locked) {
674 if (position > _position) {
675 start_shift = position - _position;
677 start_shift = -(_position - position);
680 if (start_shift > 0) {
682 if (_start > max_frames - start_shift) {
683 new_start = max_frames;
685 new_start = _start + start_shift;
689 } else if (start_shift < 0) {
691 if (_start < (jack_nframes_t) -start_shift) {
694 new_start = _start + start_shift;
700 if (!verify_start_and_length (new_start, length)) {
704 Change what_changed = Change (0);
706 if (_start != new_start) {
708 what_changed = Change (what_changed|StartChanged);
710 if (_length != length) {
712 what_changed = Change (what_changed|LengthChanged);
714 if (_position != position) {
715 _position = position;
716 what_changed = Change (what_changed|PositionChanged);
719 _flags = Region::Flag (_flags & ~WholeFile);
721 if (what_changed & (StartChanged|LengthChanged)) {
729 snprintf (buf, sizeof (buf), "trimmed to %u-%u", _position, _position+_length-1);
733 send_change (what_changed);
738 Region::set_hidden (bool yn)
740 if (hidden() != yn) {
743 _flags = Flag (_flags|Hidden);
745 _flags = Flag (_flags & ~Hidden);
748 send_change (HiddenChanged);
753 Region::set_muted (bool yn)
758 _flags = Flag (_flags|Muted);
760 _flags = Flag (_flags & ~Muted);
766 snprintf (buf, sizeof (buf), "muted");
768 snprintf (buf, sizeof (buf), "unmuted");
773 send_change (MuteChanged);
778 Region::set_opaque (bool yn)
780 if (opaque() != yn) {
784 snprintf (buf, sizeof (buf), "opaque");
785 _flags = Flag (_flags|Opaque);
787 snprintf (buf, sizeof (buf), "translucent");
788 _flags = Flag (_flags & ~Opaque);
792 send_change (OpacityChanged);
797 Region::set_locked (bool yn)
799 if (locked() != yn) {
803 snprintf (buf, sizeof (buf), "locked");
804 _flags = Flag (_flags|Locked);
806 snprintf (buf, sizeof (buf), "unlocked");
807 _flags = Flag (_flags & ~Locked);
811 send_change (LockChanged);
816 Region::set_sync_position (jack_nframes_t absolute_pos)
818 jack_nframes_t file_pos;
820 file_pos = _start + (absolute_pos - _position);
822 if (file_pos != _sync_position) {
824 _sync_position = file_pos;
825 _flags = Flag (_flags|SyncMarked);
830 snprintf (buf, sizeof (buf), "sync point set to %u", _sync_position);
833 send_change (SyncOffsetChanged);
838 Region::clear_sync_position ()
840 if (_flags & SyncMarked) {
841 _flags = Flag (_flags & ~SyncMarked);
845 save_state ("sync point removed");
847 send_change (SyncOffsetChanged);
852 Region::sync_offset (int& dir) const
854 /* returns the sync point relative the first frame of the region */
856 if (_flags & SyncMarked) {
857 if (_sync_position > _start) {
859 return _sync_position - _start;
862 return _start - _sync_position;
871 Region::adjust_to_sync (jack_nframes_t pos)
874 jack_nframes_t offset = sync_offset (sync_dir);
877 if (max_frames - pos > offset) {
892 Region::sync_position() const
894 if (_flags & SyncMarked) {
895 return _sync_position;
905 if (_playlist == 0) {
909 _playlist->raise_region (*this);
915 if (_playlist == 0) {
919 _playlist->lower_region (*this);
923 Region::raise_to_top ()
926 if (_playlist == 0) {
930 _playlist->raise_region_to_top (*this);
934 Region::lower_to_bottom ()
936 if (_playlist == 0) {
940 _playlist->lower_region_to_bottom (*this);
944 Region::set_layer (layer_t l)
951 snprintf (buf, sizeof (buf), "layer set to %" PRIu32, _layer);
955 send_change (LayerChanged);
960 Region::state (bool full_state)
962 XMLNode *node = new XMLNode ("Region");
966 node->add_property ("id", buf);
967 node->add_property ("name", _name);
968 node->add_property ("type", _type.to_string());
969 snprintf (buf, sizeof (buf), "%u", _start);
970 node->add_property ("start", buf);
971 snprintf (buf, sizeof (buf), "%u", _length);
972 node->add_property ("length", buf);
973 snprintf (buf, sizeof (buf), "%u", _position);
974 node->add_property ("position", buf);
976 /* note: flags are stored by derived classes */
978 snprintf (buf, sizeof (buf), "%d", (int) _layer);
979 node->add_property ("layer", buf);
980 snprintf (buf, sizeof (buf), "%u", _sync_position);
981 node->add_property ("sync-position", buf);
993 Region::set_state (const XMLNode& node)
995 const XMLNodeList& nlist = node.children();
996 const XMLProperty *prop;
1003 if ((prop = node.property ("id")) == 0) {
1004 error << _("Session: XMLNode describing a Region is incomplete (no id)") << endmsg;
1008 _id = prop->value();
1010 if ((prop = node.property ("name")) == 0) {
1011 error << _("Session: XMLNode describing a Region is incomplete (no name)") << endmsg;
1015 _name = prop->value();
1017 if ((prop = node.property ("type")) == 0) {
1018 _type = DataType::AUDIO;
1020 _type = DataType(prop->value());
1023 if ((prop = node.property ("start")) != 0) {
1024 _start = (jack_nframes_t) atoi (prop->value().c_str());
1027 if ((prop = node.property ("length")) != 0) {
1028 _length = (jack_nframes_t) atoi (prop->value().c_str());
1031 if ((prop = node.property ("position")) != 0) {
1032 _position = (jack_nframes_t) atoi (prop->value().c_str());
1035 if ((prop = node.property ("layer")) != 0) {
1036 _layer = (layer_t) atoi (prop->value().c_str());
1039 /* note: derived classes set flags */
1041 if ((prop = node.property ("sync-position")) != 0) {
1042 _sync_position = (jack_nframes_t) atoi (prop->value().c_str());
1044 _sync_position = _start;
1047 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1053 if (child->name () == "extra") {
1054 _extra_xml = new XMLNode (*child);
1059 _first_edit = EditChangesNothing;
1071 Region::thaw (const string& why)
1073 Change what_changed = Change (0);
1076 Glib::Mutex::Lock lm (_lock);
1078 if (_frozen && --_frozen > 0) {
1082 if (_pending_changed) {
1083 what_changed = _pending_changed;
1084 _pending_changed = Change (0);
1088 if (what_changed == Change (0)) {
1092 if (what_changed & LengthChanged) {
1093 if (what_changed & PositionChanged) {
1094 recompute_at_start ();
1096 recompute_at_end ();
1100 StateChanged (what_changed);
1104 Region::send_change (Change what_changed)
1107 Glib::Mutex::Lock lm (_lock);
1109 _pending_changed = Change (_pending_changed|what_changed);
1114 StateManager::send_state_changed (what_changed);
1118 Region::set_last_layer_op (uint64_t when)
1120 _last_layer_op = when;
1124 Region::overlap_equivalent (const Region& other) const
1126 return coverage (other.first_frame(), other.last_frame()) != OverlapNone;
1130 Region::equivalent (const Region& other) const
1132 return _start == other._start &&
1133 _position == other._position &&
1134 _length == other._length;
1138 Region::size_equivalent (const Region& other) const
1140 return _start == other._start &&
1141 _length == other._length;
1145 Region::region_list_equivalent (const Region& other) const
1147 return size_equivalent (other) && source_equivalent (other) && _name == other._name;
1151 Region::source_deleted (Source* ignored)
1157 Region::lock_sources ()
1159 SourceList::iterator i;
1160 set<Source*> unique_srcs;
1162 for (i = _sources.begin(); i != _sources.end(); ++i) {
1163 unique_srcs.insert (*i);
1167 for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1168 if (unique_srcs.find (*i) == unique_srcs.end()) {
1175 Region::unlock_sources ()
1177 SourceList::iterator i;
1178 set<Source*> unique_srcs;
1180 for (i = _sources.begin(); i != _sources.end(); ++i) {
1181 unique_srcs.insert (*i);
1185 for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1186 if (unique_srcs.find (*i) == unique_srcs.end()) {
1193 Region::master_source_names ()
1195 SourceList::iterator i;
1197 vector<string> names;
1198 for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1199 names.push_back((*i)->name());
1206 Region::source_equivalent (const Region& other) const
1208 SourceList::const_iterator i;
1209 SourceList::const_iterator io;
1211 for (i = _sources.begin(), io = other._sources.begin(); i != _sources.end() && io != other._sources.end(); ++i, ++io) {
1212 if ((*i)->id() != (*io)->id()) {
1217 for (i = _master_sources.begin(), io = other._master_sources.begin(); i != _master_sources.end() && io != other._master_sources.end(); ++i, ++io) {
1218 if ((*i)->id() != (*io)->id()) {
1227 Region::verify_length (jack_nframes_t len)
1229 for (uint32_t n=0; n < _sources.size(); ++n) {
1230 if (_start > _sources[n]->length() - len) {
1238 Region::verify_start_and_length (jack_nframes_t new_start, jack_nframes_t new_length)
1240 for (uint32_t n=0; n < _sources.size(); ++n) {
1241 if (new_length > _sources[n]->length() - new_start) {
1248 Region::verify_start (jack_nframes_t pos)
1250 for (uint32_t n=0; n < _sources.size(); ++n) {
1251 if (pos > _sources[n]->length() - _length) {
1259 Region::verify_start_mutable (jack_nframes_t& new_start)
1261 for (uint32_t n=0; n < _sources.size(); ++n) {
1262 if (new_start > _sources[n]->length() - _length) {
1263 new_start = _sources[n]->length() - _length;
1270 Region::get_parent()
1275 r = _playlist->session().find_whole_file_parent (*this);