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;
42 Change Region::FadeChanged = ARDOUR::new_change ();
43 Change Region::SyncOffsetChanged = ARDOUR::new_change ();
44 Change Region::MuteChanged = ARDOUR::new_change ();
45 Change Region::OpacityChanged = ARDOUR::new_change ();
46 Change Region::LockChanged = ARDOUR::new_change ();
47 Change Region::LayerChanged = ARDOUR::new_change ();
48 Change Region::HiddenChanged = ARDOUR::new_change ();
50 sigc::signal<void,Region *> Region::CheckNewRegion;
52 Region::Region (jack_nframes_t start, jack_nframes_t length, const string& name, layer_t layer, Region::Flag flags)
54 /* basic Region constructor */
56 _id = ARDOUR::new_id();
61 pending_changed = Change (0);
65 _sync_position = _start;
69 _current_state_id = 0;
71 _first_edit = EditChangesNothing;
75 Region::Region (const Region& other, jack_nframes_t offset, jack_nframes_t length, const string& name, layer_t layer, Flag flags)
77 /* create a new Region from part of an existing one */
79 _id = ARDOUR::new_id();
81 pending_changed = Change (0);
85 _start = other._start + offset;
86 if (other._sync_position < offset) {
87 _sync_position = other._sync_position;
89 _sync_position = _start;
95 _flags = Flag (flags & ~(Locked|WholeFile|Hidden));
96 _current_state_id = 0;
97 _first_edit = EditChangesNothing;
101 Region::Region (const Region &other)
103 /* Pure copy constructor */
105 _id = ARDOUR::new_id();
107 pending_changed = Change (0);
109 _read_data_count = 0;
111 _first_edit = EditChangesID;
112 other._first_edit = EditChangesName;
114 if (other._extra_xml) {
115 _extra_xml = new XMLNode (*other._extra_xml);
120 _start = other._start;
121 _sync_position = other._sync_position;
122 _length = other._length;
124 _position = other._position;
125 _layer = other._layer;
126 _flags = Flag (other._flags & ~Locked);
127 _current_state_id = 0;
128 _last_layer_op = other._last_layer_op;
131 Region::Region (const XMLNode& node)
135 pending_changed = Change (0);
137 _read_data_count = 0;
139 _sync_position = _start;
141 _name = X_("error: XML did not reset this");
145 _current_state_id = 0;
146 _first_edit = EditChangesNothing;
148 if (set_state (node)) {
149 throw failed_constructor();
158 Region::set_playlist (Playlist* pl)
164 Region::store_state (RegionState& state) const
166 state._start = _start;
167 state._length = _length;
168 state._position = _position;
169 state._flags = _flags;
170 state._sync_position = _sync_position;
171 state._layer = _layer;
173 state._first_edit = _first_edit;
177 Region::restore_and_return_flags (RegionState& state)
179 Change what_changed = Change (0);
182 Glib::Mutex::Lock lm (lock);
184 if (_start != state._start) {
185 what_changed = Change (what_changed|StartChanged);
186 _start = state._start;
188 if (_length != state._length) {
189 what_changed = Change (what_changed|LengthChanged);
190 _length = state._length;
192 if (_position != state._position) {
193 what_changed = Change (what_changed|PositionChanged);
194 _position = state._position;
196 if (_sync_position != state._sync_position) {
197 _sync_position = state._sync_position;
198 what_changed = Change (what_changed|SyncOffsetChanged);
200 if (_layer != state._layer) {
201 what_changed = Change (what_changed|LayerChanged);
202 _layer = state._layer;
205 uint32_t old_flags = _flags;
206 _flags = Flag (state._flags);
208 if ((old_flags ^ state._flags) & Muted) {
209 what_changed = Change (what_changed|MuteChanged);
211 if ((old_flags ^ state._flags) & Opaque) {
212 what_changed = Change (what_changed|OpacityChanged);
214 if ((old_flags ^ state._flags) & Locked) {
215 what_changed = Change (what_changed|LockChanged);
218 _first_edit = state._first_edit;
225 Region::set_name (string str)
230 send_change (NameChanged);
235 Region::set_length (jack_nframes_t len, void *src)
237 if (_flags & Locked) {
241 if (_length != len && len != 0) {
243 if (!verify_length (len)) {
249 _flags = Region::Flag (_flags & ~WholeFile);
258 snprintf (buf, sizeof (buf), "length set to %u", len);
262 send_change (LengthChanged);
267 Region::maybe_uncopy ()
272 Region::first_edit ()
274 if (_first_edit != EditChangesNothing && _playlist) {
276 _name = _playlist->session().new_region_name (_name);
277 _first_edit = EditChangesNothing;
279 send_change (NameChanged);
280 CheckNewRegion (this);
285 Region::move_to_natural_position (void *src)
291 Region* whole_file_region = get_parent();
293 if (whole_file_region) {
294 set_position (whole_file_region->position() + _start, src);
299 Region::special_set_position (jack_nframes_t pos)
301 /* this is used when creating a whole file region as
302 a way to store its "natural" or "captured" position.
309 Region::set_position (jack_nframes_t pos, void *src)
311 if (_flags & Locked) {
315 if (_position != pos) {
320 snprintf (buf, sizeof (buf), "position set to %u", pos);
325 /* do this even if the position is the same. this helps out
326 a GUI that has moved its representation already.
329 send_change (PositionChanged);
333 Region::set_position_on_top (jack_nframes_t pos, void *src)
335 if (_flags & Locked) {
339 if (_position != pos) {
344 snprintf (buf, sizeof (buf), "position set to %u", pos);
349 _playlist->raise_region_to_top (*this);
351 /* do this even if the position is the same. this helps out
352 a GUI that has moved its representation already.
355 send_change (PositionChanged);
359 Region::nudge_position (long n, void *src)
361 if (_flags & Locked) {
370 if (_position > max_frames - n) {
371 _position = max_frames;
376 if (_position < (jack_nframes_t) -n) {
385 snprintf (buf, sizeof (buf), "position set to %u", _position);
389 send_change (PositionChanged);
393 Region::set_start (jack_nframes_t pos, void *src)
395 if (_flags & Locked) {
398 /* This just sets the start, nothing else. It effectively shifts
399 the contents of the Region within the overall extent of the Source,
400 without changing the Region's position or length
405 if (!verify_start (pos)) {
410 _flags = Region::Flag (_flags & ~WholeFile);
415 snprintf (buf, sizeof (buf), "start set to %u", pos);
419 send_change (StartChanged);
424 Region::trim_start (jack_nframes_t new_position, void *src)
426 if (_flags & Locked) {
429 jack_nframes_t new_start;
432 if (new_position > _position) {
433 start_shift = new_position - _position;
435 start_shift = -(_position - new_position);
438 if (start_shift > 0) {
440 if (_start > max_frames - start_shift) {
441 new_start = max_frames;
443 new_start = _start + start_shift;
446 if (!verify_start (new_start)) {
450 } else if (start_shift < 0) {
452 if (_start < (jack_nframes_t) -start_shift) {
455 new_start = _start + start_shift;
461 if (new_start == _start) {
466 _flags = Region::Flag (_flags & ~WholeFile);
471 snprintf (buf, sizeof (buf), "slipped start to %u", _start);
475 send_change (StartChanged);
479 Region::trim_front (jack_nframes_t new_position, void *src)
481 if (_flags & Locked) {
485 jack_nframes_t end = _position + _length - 1;
486 jack_nframes_t source_zero;
488 if (_position > _start) {
489 source_zero = _position - _start;
491 source_zero = 0; // its actually negative, but this will work for us
494 if (new_position < end) { /* can't trim it zero or negative length */
496 jack_nframes_t newlen;
498 /* can't trim it back passed where source position zero is located */
500 new_position = max (new_position, source_zero);
503 if (new_position > _position) {
504 newlen = _length - (new_position - _position);
506 newlen = _length + (_position - new_position);
509 trim_to_internal (new_position, newlen, src);
511 recompute_at_start ();
517 Region::trim_end (jack_nframes_t new_endpoint, void *src)
519 if (_flags & Locked) {
523 if (new_endpoint > _position) {
524 trim_to_internal (_position, new_endpoint - _position, this);
532 Region::trim_to (jack_nframes_t position, jack_nframes_t length, void *src)
534 if (_flags & Locked) {
538 trim_to_internal (position, length, src);
541 recompute_at_start ();
547 Region::trim_to_internal (jack_nframes_t position, jack_nframes_t length, void *src)
550 jack_nframes_t new_start;
552 if (_flags & Locked) {
556 if (position > _position) {
557 start_shift = position - _position;
559 start_shift = -(_position - position);
562 if (start_shift > 0) {
564 if (_start > max_frames - start_shift) {
565 new_start = max_frames;
567 new_start = _start + start_shift;
571 } else if (start_shift < 0) {
573 if (_start < (jack_nframes_t) -start_shift) {
576 new_start = _start + start_shift;
582 if (!verify_start_and_length (new_start, length)) {
586 Change what_changed = Change (0);
588 if (_start != new_start) {
590 what_changed = Change (what_changed|StartChanged);
592 if (_length != length) {
594 what_changed = Change (what_changed|LengthChanged);
596 if (_position != position) {
597 _position = position;
598 what_changed = Change (what_changed|PositionChanged);
601 _flags = Region::Flag (_flags & ~WholeFile);
603 if (what_changed & (StartChanged|LengthChanged)) {
611 snprintf (buf, sizeof (buf), "trimmed to %u-%u", _position, _position+_length-1);
615 send_change (what_changed);
620 Region::set_hidden (bool yn)
622 if (hidden() != yn) {
625 _flags = Flag (_flags|Hidden);
627 _flags = Flag (_flags & ~Hidden);
630 send_change (HiddenChanged);
635 Region::set_muted (bool yn)
640 _flags = Flag (_flags|Muted);
642 _flags = Flag (_flags & ~Muted);
648 snprintf (buf, sizeof (buf), "muted");
650 snprintf (buf, sizeof (buf), "unmuted");
655 send_change (MuteChanged);
660 Region::set_opaque (bool yn)
662 if (opaque() != yn) {
666 snprintf (buf, sizeof (buf), "opaque");
667 _flags = Flag (_flags|Opaque);
669 snprintf (buf, sizeof (buf), "translucent");
670 _flags = Flag (_flags & ~Opaque);
674 send_change (OpacityChanged);
679 Region::set_locked (bool yn)
681 if (locked() != yn) {
685 snprintf (buf, sizeof (buf), "locked");
686 _flags = Flag (_flags|Locked);
688 snprintf (buf, sizeof (buf), "unlocked");
689 _flags = Flag (_flags & ~Locked);
693 send_change (LockChanged);
698 Region::set_sync_position (jack_nframes_t absolute_pos)
700 jack_nframes_t file_pos;
702 file_pos = _start + (absolute_pos - _position);
704 if (file_pos != _sync_position) {
706 _sync_position = file_pos;
707 _flags = Flag (_flags|SyncMarked);
712 snprintf (buf, sizeof (buf), "sync point set to %u", _sync_position);
715 send_change (SyncOffsetChanged);
720 Region::clear_sync_position ()
722 if (_flags & SyncMarked) {
723 _flags = Flag (_flags & ~SyncMarked);
727 save_state ("sync point removed");
729 send_change (SyncOffsetChanged);
734 Region::sync_offset (int& dir) const
736 /* returns the sync point relative the first frame of the region */
738 if (_flags & SyncMarked) {
739 if (_sync_position > _start) {
741 return _sync_position - _start;
744 return _start - _sync_position;
753 Region::adjust_to_sync (jack_nframes_t pos)
756 jack_nframes_t offset = sync_offset (sync_dir);
759 if (max_frames - pos > offset) {
774 Region::sync_position() const
776 if (_flags & SyncMarked) {
777 return _sync_position;
787 if (_playlist == 0) {
791 _playlist->raise_region (*this);
797 if (_playlist == 0) {
801 _playlist->lower_region (*this);
805 Region::raise_to_top ()
808 if (_playlist == 0) {
812 _playlist->raise_region_to_top (*this);
816 Region::lower_to_bottom ()
818 if (_playlist == 0) {
822 _playlist->lower_region_to_bottom (*this);
826 Region::set_layer (layer_t l)
833 snprintf (buf, sizeof (buf), "layer set to %" PRIu32, _layer);
837 send_change (LayerChanged);
842 Region::state (bool full_state)
844 XMLNode *node = new XMLNode ("Region");
847 snprintf (buf, sizeof (buf), "%" PRIu64, _id);
848 node->add_property ("id", buf);
849 node->add_property ("name", _name);
850 snprintf (buf, sizeof (buf), "%u", _start);
851 node->add_property ("start", buf);
852 snprintf (buf, sizeof (buf), "%u", _length);
853 node->add_property ("length", buf);
854 snprintf (buf, sizeof (buf), "%u", _position);
855 node->add_property ("position", buf);
857 /* note: flags are stored by derived classes */
859 snprintf (buf, sizeof (buf), "%d", (int) _layer);
860 node->add_property ("layer", buf);
861 snprintf (buf, sizeof (buf), "%u", _sync_position);
862 node->add_property ("sync-position", buf);
874 Region::set_state (const XMLNode& node)
876 const XMLNodeList& nlist = node.children();
877 const XMLProperty *prop;
884 if ((prop = node.property ("id")) == 0) {
885 error << _("Session: XMLNode describing a Region is incomplete (no id)") << endmsg;
889 sscanf (prop->value().c_str(), "%" PRIu64, &_id);
891 if ((prop = node.property ("name")) == 0) {
892 error << _("Session: XMLNode describing a Region is incomplete (no name)") << endmsg;
896 _name = prop->value();
898 if ((prop = node.property ("start")) != 0) {
899 _start = (jack_nframes_t) atoi (prop->value().c_str());
902 if ((prop = node.property ("length")) != 0) {
903 _length = (jack_nframes_t) atoi (prop->value().c_str());
906 if ((prop = node.property ("position")) != 0) {
907 _position = (jack_nframes_t) atoi (prop->value().c_str());
910 if ((prop = node.property ("layer")) != 0) {
911 _layer = (layer_t) atoi (prop->value().c_str());
914 /* note: derived classes set flags */
916 if ((prop = node.property ("sync-position")) != 0) {
917 _sync_position = (jack_nframes_t) atoi (prop->value().c_str());
919 _sync_position = _start;
922 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
928 if (child->name () == "extra") {
929 _extra_xml = new XMLNode (*child);
934 _first_edit = EditChangesNothing;
946 Region::thaw (const string& why)
948 Change what_changed = Change (0);
951 Glib::Mutex::Lock lm (lock);
953 if (_frozen && --_frozen > 0) {
957 if (pending_changed) {
958 what_changed = pending_changed;
959 pending_changed = Change (0);
963 if (what_changed == Change (0)) {
967 if (what_changed & LengthChanged) {
968 if (what_changed & PositionChanged) {
969 recompute_at_start ();
975 StateChanged (what_changed);
979 Region::send_change (Change what_changed)
982 Glib::Mutex::Lock lm (lock);
984 pending_changed = Change (pending_changed|what_changed);
989 StateManager::send_state_changed (what_changed);
993 Region::set_last_layer_op (uint64_t when)
995 _last_layer_op = when;