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 */
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 */
79 pending_changed = Change (0);
83 _start = other._start + offset;
84 if (other._sync_position < offset) {
85 _sync_position = other._sync_position;
87 _sync_position = _start;
93 _flags = Flag (flags & ~(Locked|WholeFile|Hidden));
94 _current_state_id = 0;
95 _first_edit = EditChangesNothing;
99 Region::Region (const Region &other)
101 /* Pure copy constructor */
104 pending_changed = Change (0);
106 _read_data_count = 0;
108 _first_edit = EditChangesID;
109 other._first_edit = EditChangesName;
111 if (other._extra_xml) {
112 _extra_xml = new XMLNode (*other._extra_xml);
117 _start = other._start;
118 _sync_position = other._sync_position;
119 _length = other._length;
121 _position = other._position;
122 _layer = other._layer;
123 _flags = Flag (other._flags & ~Locked);
124 _current_state_id = 0;
125 _last_layer_op = other._last_layer_op;
128 Region::Region (const XMLNode& node)
131 pending_changed = Change (0);
133 _read_data_count = 0;
135 _sync_position = _start;
137 _name = X_("error: XML did not reset this");
141 _current_state_id = 0;
142 _first_edit = EditChangesNothing;
144 if (set_state (node)) {
145 throw failed_constructor();
154 Region::set_playlist (Playlist* pl)
160 Region::store_state (RegionState& state) const
162 state._start = _start;
163 state._length = _length;
164 state._position = _position;
165 state._flags = _flags;
166 state._sync_position = _sync_position;
167 state._layer = _layer;
169 state._first_edit = _first_edit;
173 Region::restore_and_return_flags (RegionState& state)
175 Change what_changed = Change (0);
178 Glib::Mutex::Lock lm (lock);
180 if (_start != state._start) {
181 what_changed = Change (what_changed|StartChanged);
182 _start = state._start;
184 if (_length != state._length) {
185 what_changed = Change (what_changed|LengthChanged);
186 _length = state._length;
188 if (_position != state._position) {
189 what_changed = Change (what_changed|PositionChanged);
190 _position = state._position;
192 if (_sync_position != state._sync_position) {
193 _sync_position = state._sync_position;
194 what_changed = Change (what_changed|SyncOffsetChanged);
196 if (_layer != state._layer) {
197 what_changed = Change (what_changed|LayerChanged);
198 _layer = state._layer;
201 uint32_t old_flags = _flags;
202 _flags = Flag (state._flags);
204 if ((old_flags ^ state._flags) & Muted) {
205 what_changed = Change (what_changed|MuteChanged);
207 if ((old_flags ^ state._flags) & Opaque) {
208 what_changed = Change (what_changed|OpacityChanged);
210 if ((old_flags ^ state._flags) & Locked) {
211 what_changed = Change (what_changed|LockChanged);
214 _first_edit = state._first_edit;
221 Region::set_name (string str)
226 send_change (NameChanged);
231 Region::set_length (jack_nframes_t len, void *src)
233 if (_flags & Locked) {
237 if (_length != len && len != 0) {
239 if (!verify_length (len)) {
245 _flags = Region::Flag (_flags & ~WholeFile);
254 snprintf (buf, sizeof (buf), "length set to %u", len);
258 send_change (LengthChanged);
263 Region::maybe_uncopy ()
268 Region::first_edit ()
270 if (_first_edit != EditChangesNothing && _playlist) {
272 _name = _playlist->session().new_region_name (_name);
273 _first_edit = EditChangesNothing;
275 send_change (NameChanged);
276 CheckNewRegion (this);
281 Region::move_to_natural_position (void *src)
287 Region* whole_file_region = get_parent();
289 if (whole_file_region) {
290 set_position (whole_file_region->position() + _start, src);
295 Region::special_set_position (jack_nframes_t pos)
297 /* this is used when creating a whole file region as
298 a way to store its "natural" or "captured" position.
305 Region::set_position (jack_nframes_t pos, void *src)
307 if (_flags & Locked) {
311 if (_position != pos) {
316 snprintf (buf, sizeof (buf), "position set to %u", pos);
321 /* do this even if the position is the same. this helps out
322 a GUI that has moved its representation already.
325 send_change (PositionChanged);
329 Region::set_position_on_top (jack_nframes_t pos, void *src)
331 if (_flags & Locked) {
335 if (_position != pos) {
340 snprintf (buf, sizeof (buf), "position set to %u", pos);
345 _playlist->raise_region_to_top (*this);
347 /* do this even if the position is the same. this helps out
348 a GUI that has moved its representation already.
351 send_change (PositionChanged);
355 Region::nudge_position (long n, void *src)
357 if (_flags & Locked) {
366 if (_position > max_frames - n) {
367 _position = max_frames;
372 if (_position < (jack_nframes_t) -n) {
381 snprintf (buf, sizeof (buf), "position set to %u", _position);
385 send_change (PositionChanged);
389 Region::set_start (jack_nframes_t pos, void *src)
391 if (_flags & Locked) {
394 /* This just sets the start, nothing else. It effectively shifts
395 the contents of the Region within the overall extent of the Source,
396 without changing the Region's position or length
401 if (!verify_start (pos)) {
406 _flags = Region::Flag (_flags & ~WholeFile);
411 snprintf (buf, sizeof (buf), "start set to %u", pos);
415 send_change (StartChanged);
420 Region::trim_start (jack_nframes_t new_position, void *src)
422 if (_flags & Locked) {
425 jack_nframes_t new_start;
428 if (new_position > _position) {
429 start_shift = new_position - _position;
431 start_shift = -(_position - new_position);
434 if (start_shift > 0) {
436 if (_start > max_frames - start_shift) {
437 new_start = max_frames;
439 new_start = _start + start_shift;
442 if (!verify_start (new_start)) {
446 } else if (start_shift < 0) {
448 if (_start < (jack_nframes_t) -start_shift) {
451 new_start = _start + start_shift;
457 if (new_start == _start) {
462 _flags = Region::Flag (_flags & ~WholeFile);
467 snprintf (buf, sizeof (buf), "slipped start to %u", _start);
471 send_change (StartChanged);
475 Region::trim_front (jack_nframes_t new_position, void *src)
477 if (_flags & Locked) {
481 jack_nframes_t end = _position + _length - 1;
482 jack_nframes_t source_zero;
484 if (_position > _start) {
485 source_zero = _position - _start;
487 source_zero = 0; // its actually negative, but this will work for us
490 if (new_position < end) { /* can't trim it zero or negative length */
492 jack_nframes_t newlen;
494 /* can't trim it back passed where source position zero is located */
496 new_position = max (new_position, source_zero);
499 if (new_position > _position) {
500 newlen = _length - (new_position - _position);
502 newlen = _length + (_position - new_position);
505 trim_to_internal (new_position, newlen, src);
507 recompute_at_start ();
513 Region::trim_end (jack_nframes_t new_endpoint, void *src)
515 if (_flags & Locked) {
519 if (new_endpoint > _position) {
520 trim_to_internal (_position, new_endpoint - _position, this);
528 Region::trim_to (jack_nframes_t position, jack_nframes_t length, void *src)
530 if (_flags & Locked) {
534 trim_to_internal (position, length, src);
537 recompute_at_start ();
543 Region::trim_to_internal (jack_nframes_t position, jack_nframes_t length, void *src)
546 jack_nframes_t new_start;
548 if (_flags & Locked) {
552 if (position > _position) {
553 start_shift = position - _position;
555 start_shift = -(_position - position);
558 if (start_shift > 0) {
560 if (_start > max_frames - start_shift) {
561 new_start = max_frames;
563 new_start = _start + start_shift;
567 } else if (start_shift < 0) {
569 if (_start < (jack_nframes_t) -start_shift) {
572 new_start = _start + start_shift;
578 if (!verify_start_and_length (new_start, length)) {
582 Change what_changed = Change (0);
584 if (_start != new_start) {
586 what_changed = Change (what_changed|StartChanged);
588 if (_length != length) {
590 what_changed = Change (what_changed|LengthChanged);
592 if (_position != position) {
593 _position = position;
594 what_changed = Change (what_changed|PositionChanged);
597 _flags = Region::Flag (_flags & ~WholeFile);
599 if (what_changed & (StartChanged|LengthChanged)) {
607 snprintf (buf, sizeof (buf), "trimmed to %u-%u", _position, _position+_length-1);
611 send_change (what_changed);
616 Region::set_hidden (bool yn)
618 if (hidden() != yn) {
621 _flags = Flag (_flags|Hidden);
623 _flags = Flag (_flags & ~Hidden);
626 send_change (HiddenChanged);
631 Region::set_muted (bool yn)
636 _flags = Flag (_flags|Muted);
638 _flags = Flag (_flags & ~Muted);
644 snprintf (buf, sizeof (buf), "muted");
646 snprintf (buf, sizeof (buf), "unmuted");
651 send_change (MuteChanged);
656 Region::set_opaque (bool yn)
658 if (opaque() != yn) {
662 snprintf (buf, sizeof (buf), "opaque");
663 _flags = Flag (_flags|Opaque);
665 snprintf (buf, sizeof (buf), "translucent");
666 _flags = Flag (_flags & ~Opaque);
670 send_change (OpacityChanged);
675 Region::set_locked (bool yn)
677 if (locked() != yn) {
681 snprintf (buf, sizeof (buf), "locked");
682 _flags = Flag (_flags|Locked);
684 snprintf (buf, sizeof (buf), "unlocked");
685 _flags = Flag (_flags & ~Locked);
689 send_change (LockChanged);
694 Region::set_sync_position (jack_nframes_t absolute_pos)
696 jack_nframes_t file_pos;
698 file_pos = _start + (absolute_pos - _position);
700 if (file_pos != _sync_position) {
702 _sync_position = file_pos;
703 _flags = Flag (_flags|SyncMarked);
708 snprintf (buf, sizeof (buf), "sync point set to %u", _sync_position);
711 send_change (SyncOffsetChanged);
716 Region::clear_sync_position ()
718 if (_flags & SyncMarked) {
719 _flags = Flag (_flags & ~SyncMarked);
723 save_state ("sync point removed");
725 send_change (SyncOffsetChanged);
730 Region::sync_offset (int& dir) const
732 /* returns the sync point relative the first frame of the region */
734 if (_flags & SyncMarked) {
735 if (_sync_position > _start) {
737 return _sync_position - _start;
740 return _start - _sync_position;
749 Region::adjust_to_sync (jack_nframes_t pos)
752 jack_nframes_t offset = sync_offset (sync_dir);
755 if (max_frames - pos > offset) {
770 Region::sync_position() const
772 if (_flags & SyncMarked) {
773 return _sync_position;
783 if (_playlist == 0) {
787 _playlist->raise_region (*this);
793 if (_playlist == 0) {
797 _playlist->lower_region (*this);
801 Region::raise_to_top ()
804 if (_playlist == 0) {
808 _playlist->raise_region_to_top (*this);
812 Region::lower_to_bottom ()
814 if (_playlist == 0) {
818 _playlist->lower_region_to_bottom (*this);
822 Region::set_layer (layer_t l)
829 snprintf (buf, sizeof (buf), "layer set to %" PRIu32, _layer);
833 send_change (LayerChanged);
838 Region::state (bool full_state)
840 XMLNode *node = new XMLNode ("Region");
844 node->add_property ("id", buf);
845 node->add_property ("name", _name);
846 snprintf (buf, sizeof (buf), "%u", _start);
847 node->add_property ("start", buf);
848 snprintf (buf, sizeof (buf), "%u", _length);
849 node->add_property ("length", buf);
850 snprintf (buf, sizeof (buf), "%u", _position);
851 node->add_property ("position", buf);
853 /* note: flags are stored by derived classes */
855 snprintf (buf, sizeof (buf), "%d", (int) _layer);
856 node->add_property ("layer", buf);
857 snprintf (buf, sizeof (buf), "%u", _sync_position);
858 node->add_property ("sync-position", buf);
870 Region::set_state (const XMLNode& node)
872 const XMLNodeList& nlist = node.children();
873 const XMLProperty *prop;
880 if ((prop = node.property ("id")) == 0) {
881 error << _("Session: XMLNode describing a Region is incomplete (no id)") << endmsg;
887 if ((prop = node.property ("name")) == 0) {
888 error << _("Session: XMLNode describing a Region is incomplete (no name)") << endmsg;
892 _name = prop->value();
894 if ((prop = node.property ("start")) != 0) {
895 _start = (jack_nframes_t) atoi (prop->value().c_str());
898 if ((prop = node.property ("length")) != 0) {
899 _length = (jack_nframes_t) atoi (prop->value().c_str());
902 if ((prop = node.property ("position")) != 0) {
903 _position = (jack_nframes_t) atoi (prop->value().c_str());
906 if ((prop = node.property ("layer")) != 0) {
907 _layer = (layer_t) atoi (prop->value().c_str());
910 /* note: derived classes set flags */
912 if ((prop = node.property ("sync-position")) != 0) {
913 _sync_position = (jack_nframes_t) atoi (prop->value().c_str());
915 _sync_position = _start;
918 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
924 if (child->name () == "extra") {
925 _extra_xml = new XMLNode (*child);
930 _first_edit = EditChangesNothing;
942 Region::thaw (const string& why)
944 Change what_changed = Change (0);
947 Glib::Mutex::Lock lm (lock);
949 if (_frozen && --_frozen > 0) {
953 if (pending_changed) {
954 what_changed = pending_changed;
955 pending_changed = Change (0);
959 if (what_changed == Change (0)) {
963 if (what_changed & LengthChanged) {
964 if (what_changed & PositionChanged) {
965 recompute_at_start ();
971 StateChanged (what_changed);
975 Region::send_change (Change what_changed)
978 Glib::Mutex::Lock lm (lock);
980 pending_changed = Change (pending_changed|what_changed);
985 StateManager::send_state_changed (what_changed);
989 Region::set_last_layer_op (uint64_t when)
991 _last_layer_op = when;