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>
39 using namespace ARDOUR;
41 Change Region::FadeChanged = ARDOUR::new_change ();
42 Change Region::SyncOffsetChanged = ARDOUR::new_change ();
43 Change Region::MuteChanged = ARDOUR::new_change ();
44 Change Region::OpacityChanged = ARDOUR::new_change ();
45 Change Region::LockChanged = ARDOUR::new_change ();
46 Change Region::LayerChanged = ARDOUR::new_change ();
47 Change Region::HiddenChanged = ARDOUR::new_change ();
49 sigc::signal<void,Region *> Region::CheckNewRegion;
51 Region::Region (jack_nframes_t start, jack_nframes_t length, const string& name, layer_t layer, Region::Flag flags)
53 /* basic Region constructor */
55 _id = ARDOUR::new_id();
60 pending_changed = Change (0);
64 _sync_position = _start;
68 _current_state_id = 0;
70 _first_edit = EditChangesNothing;
74 Region::Region (const Region& other, jack_nframes_t offset, jack_nframes_t length, const string& name, layer_t layer, Flag flags)
76 /* create a new Region from part of an existing one */
78 _id = ARDOUR::new_id();
80 pending_changed = Change (0);
84 _start = other._start + offset;
85 if (other._sync_position < offset) {
86 _sync_position = other._sync_position;
88 _sync_position = _start;
94 _flags = Flag (flags & ~(Locked|WholeFile|Hidden));
95 _current_state_id = 0;
96 _first_edit = EditChangesNothing;
100 Region::Region (const Region &other)
102 /* Pure copy constructor */
104 _id = ARDOUR::new_id();
106 pending_changed = Change (0);
108 _read_data_count = 0;
110 _first_edit = EditChangesID;
111 other._first_edit = EditChangesName;
113 if (other._extra_xml) {
114 _extra_xml = new XMLNode (*other._extra_xml);
119 _start = other._start;
120 _sync_position = other._sync_position;
121 _length = other._length;
123 _position = other._position;
124 _layer = other._layer;
125 _flags = Flag (other._flags & ~Locked);
126 _current_state_id = 0;
127 _last_layer_op = other._last_layer_op;
130 Region::Region (const XMLNode& node)
134 pending_changed = Change (0);
136 _read_data_count = 0;
138 _sync_position = _start;
140 _name = X_("error: XML did not reset this");
144 _current_state_id = 0;
145 _first_edit = EditChangesNothing;
147 if (set_state (node)) {
148 throw failed_constructor();
157 Region::set_playlist (Playlist* pl)
163 Region::store_state (RegionState& state) const
165 state._start = _start;
166 state._length = _length;
167 state._position = _position;
168 state._flags = _flags;
169 state._sync_position = _sync_position;
170 state._layer = _layer;
172 state._first_edit = _first_edit;
176 Region::restore_and_return_flags (RegionState& state)
178 Change what_changed = Change (0);
181 Glib::Mutex::Lock lm (lock);
183 if (_start != state._start) {
184 what_changed = Change (what_changed|StartChanged);
185 _start = state._start;
187 if (_length != state._length) {
188 what_changed = Change (what_changed|LengthChanged);
189 _length = state._length;
191 if (_position != state._position) {
192 what_changed = Change (what_changed|PositionChanged);
193 _position = state._position;
195 if (_sync_position != state._sync_position) {
196 _sync_position = state._sync_position;
197 what_changed = Change (what_changed|SyncOffsetChanged);
199 if (_layer != state._layer) {
200 what_changed = Change (what_changed|LayerChanged);
201 _layer = state._layer;
204 uint32_t old_flags = _flags;
205 _flags = Flag (state._flags);
207 if ((old_flags ^ state._flags) & Muted) {
208 what_changed = Change (what_changed|MuteChanged);
210 if ((old_flags ^ state._flags) & Opaque) {
211 what_changed = Change (what_changed|OpacityChanged);
213 if ((old_flags ^ state._flags) & Locked) {
214 what_changed = Change (what_changed|LockChanged);
217 _first_edit = state._first_edit;
224 Region::set_name (string str)
229 send_change (NameChanged);
234 Region::set_length (jack_nframes_t len, void *src)
236 if (_flags & Locked) {
240 if (_length != len && len != 0) {
242 if (!verify_length (len)) {
248 _flags = Region::Flag (_flags & ~WholeFile);
257 snprintf (buf, sizeof (buf), "length set to %u", len);
261 send_change (LengthChanged);
266 Region::maybe_uncopy ()
271 Region::first_edit ()
273 if (_first_edit != EditChangesNothing && _playlist) {
275 _name = _playlist->session().new_region_name (_name);
276 _first_edit = EditChangesNothing;
278 send_change (NameChanged);
279 CheckNewRegion (this);
284 Region::move_to_natural_position (void *src)
290 Region* whole_file_region = get_parent();
292 if (whole_file_region) {
293 set_position (whole_file_region->position() + _start, src);
298 Region::special_set_position (jack_nframes_t pos)
300 /* this is used when creating a whole file region as
301 a way to store its "natural" or "captured" position.
308 Region::set_position (jack_nframes_t pos, void *src)
310 if (_flags & Locked) {
314 if (_position != pos) {
319 snprintf (buf, sizeof (buf), "position set to %u", pos);
324 /* do this even if the position is the same. this helps out
325 a GUI that has moved its representation already.
328 send_change (PositionChanged);
332 Region::set_position_on_top (jack_nframes_t pos, void *src)
334 if (_flags & Locked) {
338 if (_position != pos) {
343 snprintf (buf, sizeof (buf), "position set to %u", pos);
348 _playlist->raise_region_to_top (*this);
350 /* do this even if the position is the same. this helps out
351 a GUI that has moved its representation already.
354 send_change (PositionChanged);
358 Region::nudge_position (long n, void *src)
360 if (_flags & Locked) {
369 if (_position > max_frames - n) {
370 _position = max_frames;
375 if (_position < (jack_nframes_t) -n) {
384 snprintf (buf, sizeof (buf), "position set to %u", _position);
388 send_change (PositionChanged);
392 Region::set_start (jack_nframes_t pos, void *src)
394 if (_flags & Locked) {
397 /* This just sets the start, nothing else. It effectively shifts
398 the contents of the Region within the overall extent of the Source,
399 without changing the Region's position or length
404 if (!verify_start (pos)) {
409 _flags = Region::Flag (_flags & ~WholeFile);
414 snprintf (buf, sizeof (buf), "start set to %u", pos);
418 send_change (StartChanged);
423 Region::trim_start (jack_nframes_t new_position, void *src)
425 if (_flags & Locked) {
428 jack_nframes_t new_start;
431 if (new_position > _position) {
432 start_shift = new_position - _position;
434 start_shift = -(_position - new_position);
437 if (start_shift > 0) {
439 if (_start > max_frames - start_shift) {
440 new_start = max_frames;
442 new_start = _start + start_shift;
445 if (!verify_start (new_start)) {
449 } else if (start_shift < 0) {
451 if (_start < (jack_nframes_t) -start_shift) {
454 new_start = _start + start_shift;
460 if (new_start == _start) {
465 _flags = Region::Flag (_flags & ~WholeFile);
470 snprintf (buf, sizeof (buf), "slipped start to %u", _start);
474 send_change (StartChanged);
478 Region::trim_front (jack_nframes_t new_position, void *src)
480 if (_flags & Locked) {
484 jack_nframes_t end = _position + _length - 1;
485 jack_nframes_t source_zero;
487 if (_position > _start) {
488 source_zero = _position - _start;
490 source_zero = 0; // its actually negative, but this will work for us
493 if (new_position < end) { /* can't trim it zero or negative length */
495 jack_nframes_t newlen;
497 /* can't trim it back passed where source position zero is located */
499 new_position = max (new_position, source_zero);
502 if (new_position > _position) {
503 newlen = _length - (new_position - _position);
505 newlen = _length + (_position - new_position);
508 trim_to_internal (new_position, newlen, src);
510 recompute_at_start ();
516 Region::trim_end (jack_nframes_t new_endpoint, void *src)
518 if (_flags & Locked) {
522 if (new_endpoint > _position) {
523 trim_to_internal (_position, new_endpoint - _position, this);
531 Region::trim_to (jack_nframes_t position, jack_nframes_t length, void *src)
533 if (_flags & Locked) {
537 trim_to_internal (position, length, src);
540 recompute_at_start ();
546 Region::trim_to_internal (jack_nframes_t position, jack_nframes_t length, void *src)
549 jack_nframes_t new_start;
551 if (_flags & Locked) {
555 if (position > _position) {
556 start_shift = position - _position;
558 start_shift = -(_position - position);
561 if (start_shift > 0) {
563 if (_start > max_frames - start_shift) {
564 new_start = max_frames;
566 new_start = _start + start_shift;
570 } else if (start_shift < 0) {
572 if (_start < (jack_nframes_t) -start_shift) {
575 new_start = _start + start_shift;
581 if (!verify_start_and_length (new_start, length)) {
585 Change what_changed = Change (0);
587 if (_start != new_start) {
589 what_changed = Change (what_changed|StartChanged);
591 if (_length != length) {
593 what_changed = Change (what_changed|LengthChanged);
595 if (_position != position) {
596 _position = position;
597 what_changed = Change (what_changed|PositionChanged);
600 _flags = Region::Flag (_flags & ~WholeFile);
602 if (what_changed & (StartChanged|LengthChanged)) {
610 snprintf (buf, sizeof (buf), "trimmed to %u-%u", _position, _position+_length-1);
614 send_change (what_changed);
619 Region::set_hidden (bool yn)
621 if (hidden() != yn) {
624 _flags = Flag (_flags|Hidden);
626 _flags = Flag (_flags & ~Hidden);
629 send_change (HiddenChanged);
634 Region::set_muted (bool yn)
639 _flags = Flag (_flags|Muted);
641 _flags = Flag (_flags & ~Muted);
647 snprintf (buf, sizeof (buf), "muted");
649 snprintf (buf, sizeof (buf), "unmuted");
654 send_change (MuteChanged);
659 Region::set_opaque (bool yn)
661 if (opaque() != yn) {
665 snprintf (buf, sizeof (buf), "opaque");
666 _flags = Flag (_flags|Opaque);
668 snprintf (buf, sizeof (buf), "translucent");
669 _flags = Flag (_flags & ~Opaque);
673 send_change (OpacityChanged);
678 Region::set_locked (bool yn)
680 if (locked() != yn) {
684 snprintf (buf, sizeof (buf), "locked");
685 _flags = Flag (_flags|Locked);
687 snprintf (buf, sizeof (buf), "unlocked");
688 _flags = Flag (_flags & ~Locked);
692 send_change (LockChanged);
697 Region::set_sync_position (jack_nframes_t absolute_pos)
699 jack_nframes_t file_pos;
701 file_pos = _start + (absolute_pos - _position);
703 if (file_pos != _sync_position) {
705 _sync_position = file_pos;
706 _flags = Flag (_flags|SyncMarked);
711 snprintf (buf, sizeof (buf), "sync point set to %u", _sync_position);
714 send_change (SyncOffsetChanged);
719 Region::clear_sync_position ()
721 if (_flags & SyncMarked) {
722 _flags = Flag (_flags & ~SyncMarked);
726 save_state ("sync point removed");
728 send_change (SyncOffsetChanged);
733 Region::sync_offset (int& dir) const
735 /* returns the sync point relative the first frame of the region */
737 if (_flags & SyncMarked) {
738 if (_sync_position > _start) {
740 return _sync_position - _start;
743 return _start - _sync_position;
752 Region::adjust_to_sync (jack_nframes_t pos)
755 jack_nframes_t offset = sync_offset (sync_dir);
758 if (max_frames - pos > offset) {
773 Region::sync_position() const
775 if (_flags & SyncMarked) {
776 return _sync_position;
786 if (_playlist == 0) {
790 _playlist->raise_region (*this);
796 if (_playlist == 0) {
800 _playlist->lower_region (*this);
804 Region::raise_to_top ()
807 if (_playlist == 0) {
811 _playlist->raise_region_to_top (*this);
815 Region::lower_to_bottom ()
817 if (_playlist == 0) {
821 _playlist->lower_region_to_bottom (*this);
825 Region::set_layer (layer_t l)
832 snprintf (buf, sizeof (buf), "layer set to %" PRIu32, _layer);
836 send_change (LayerChanged);
841 Region::state (bool full_state)
843 XMLNode *node = new XMLNode ("Region");
846 snprintf (buf, sizeof (buf), "%" PRIu64, _id);
847 node->add_property ("id", buf);
848 node->add_property ("name", _name);
849 snprintf (buf, sizeof (buf), "%u", _start);
850 node->add_property ("start", buf);
851 snprintf (buf, sizeof (buf), "%u", _length);
852 node->add_property ("length", buf);
853 snprintf (buf, sizeof (buf), "%u", _position);
854 node->add_property ("position", buf);
856 /* note: flags are stored by derived classes */
858 snprintf (buf, sizeof (buf), "%d", (int) _layer);
859 node->add_property ("layer", buf);
860 snprintf (buf, sizeof (buf), "%u", _sync_position);
861 node->add_property ("sync-position", buf);
873 Region::set_state (const XMLNode& node)
875 const XMLNodeList& nlist = node.children();
876 const XMLProperty *prop;
883 if ((prop = node.property ("id")) == 0) {
884 error << _("Session: XMLNode describing a Region is incomplete (no id)") << endmsg;
888 sscanf (prop->value().c_str(), "%" PRIu64, &_id);
890 if ((prop = node.property ("name")) == 0) {
891 error << _("Session: XMLNode describing a Region is incomplete (no name)") << endmsg;
895 _name = prop->value();
897 if ((prop = node.property ("start")) != 0) {
898 _start = (jack_nframes_t) atoi (prop->value().c_str());
901 if ((prop = node.property ("length")) != 0) {
902 _length = (jack_nframes_t) atoi (prop->value().c_str());
905 if ((prop = node.property ("position")) != 0) {
906 _position = (jack_nframes_t) atoi (prop->value().c_str());
909 if ((prop = node.property ("layer")) != 0) {
910 _layer = (layer_t) atoi (prop->value().c_str());
913 /* note: derived classes set flags */
915 if ((prop = node.property ("sync-position")) != 0) {
916 _sync_position = (jack_nframes_t) atoi (prop->value().c_str());
918 _sync_position = _start;
921 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
927 if (child->name () == "extra") {
928 _extra_xml = new XMLNode (*child);
933 _first_edit = EditChangesNothing;
945 Region::thaw (const string& why)
947 Change what_changed = Change (0);
950 Glib::Mutex::Lock lm (lock);
952 if (_frozen && --_frozen > 0) {
956 if (pending_changed) {
957 what_changed = pending_changed;
958 pending_changed = Change (0);
962 if (what_changed == Change (0)) {
966 if (what_changed & LengthChanged) {
967 if (what_changed & PositionChanged) {
968 recompute_at_start ();
974 StateChanged (what_changed);
978 Region::send_change (Change what_changed)
981 Glib::Mutex::Lock lm (lock);
983 pending_changed = Change (pending_changed|what_changed);
988 StateManager::send_state_changed (what_changed);
992 Region::set_last_layer_op (uint64_t when)
994 _last_layer_op = when;