- MIDI "recording" - rec region creation/drawing, actual MIDI region creation/view...
[ardour.git] / libs / ardour / region.cc
1 /*
2     Copyright (C) 2000-2003 Paul Davis 
3
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.
8
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.
13
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.
17
18     $Id$
19 */
20
21 #include <iostream>
22 #include <cmath>
23 #include <climits>
24 #include <algorithm>
25
26 #include <sigc++/bind.h>
27 #include <sigc++/class_slot.h>
28
29 #include <glibmm/thread.h>
30 #include <pbd/xml++.h>
31
32 #include <ardour/region.h>
33 #include <ardour/playlist.h>
34 #include <ardour/session.h>
35 #include <ardour/source.h>
36
37 #include "i18n.h"
38
39 using namespace std;
40 using namespace ARDOUR;
41 using namespace PBD;
42
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 ();
50
51 sigc::signal<void,Region *> Region::CheckNewRegion;
52
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)
55         : _name(name)
56         , _type(type)
57         , _flags(flags)
58         , _start(start) 
59         , _length(length) 
60         , _position(0) 
61         , _sync_position(_start)
62         , _layer(layer)
63         , _first_edit(EditChangesNothing)
64         , _frozen(0)
65         , _read_data_count(0)
66         , _pending_changed(Change (0))
67         , _last_layer_op(0)
68         , _playlist(0)
69 {
70         _current_state_id = 0;
71         
72         _sources.push_back (&src);
73         _master_sources.push_back (&src);
74         src.GoingAway.connect (mem_fun (*this, &Region::source_deleted));
75
76         assert(_sources.size() > 0);
77 }
78
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)
81         : _name(name)
82         , _type(type)
83         , _flags(flags)
84         , _start(start) 
85         , _length(length) 
86         , _position(0) 
87         , _sync_position(_start)
88         , _layer(layer)
89         , _first_edit(EditChangesNothing)
90         , _frozen(0)
91         , _read_data_count(0)
92         , _pending_changed(Change (0))
93         , _last_layer_op(0)
94         , _playlist(0)
95 {
96         _current_state_id = 0;
97         
98         set<Source*> unique_srcs;
99
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);
104         }
105
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));
110                 }
111         }
112         
113         assert(_sources.size() > 0);
114 }
115
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)
118         : _name(name)
119         , _type(other.data_type())
120         , _flags(Flag(flags & ~(Locked|WholeFile|Hidden)))
121         , _start(other._start + offset) 
122         , _length(length) 
123         , _position(0) 
124         , _sync_position(_start)
125         , _layer(layer)
126         , _first_edit(EditChangesNothing)
127         , _frozen(0)
128         , _read_data_count(0)
129         , _pending_changed(Change (0))
130         , _last_layer_op(0)
131         , _playlist(0)
132 {
133         _current_state_id = 0;
134         
135         if (other._sync_position < offset)
136                 _sync_position = other._sync_position;
137
138         set<Source*> unique_srcs;
139
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);
144         }
145
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));
149                 }
150                 _master_sources.push_back (*i);
151         }
152         
153         assert(_sources.size() > 0);
154 }
155
156 /** Pure copy constructor */
157 Region::Region (const Region &other)
158         : _name(other._name)
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)
167         , _frozen(0)
168         , _read_data_count(0)
169         , _pending_changed(Change(0))
170         , _last_layer_op(other._last_layer_op)
171         , _playlist(0)
172 {
173         _current_state_id = 0;
174         
175         other._first_edit = EditChangesName;
176
177         if (other._extra_xml) {
178                 _extra_xml = new XMLNode (*other._extra_xml);
179         } else {
180                 _extra_xml = 0;
181         }
182
183         set<Source*> unique_srcs;
184
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);
189         }
190
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));
195                 }
196         }
197         
198         assert(_sources.size() > 0);
199 }
200
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
204         , _flags(Flag(0))
205         , _start(0) 
206         , _length(0) 
207         , _position(0) 
208         , _sync_position(_start)
209         , _layer(0)
210         , _first_edit(EditChangesNothing)
211         , _frozen(0)
212         , _read_data_count(0)
213         , _pending_changed(Change(0))
214         , _last_layer_op(0)
215         , _playlist(0)
216
217 {
218         set<Source*> unique_srcs;
219
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);
224         }
225
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));
230                 }
231         }
232
233         _current_state_id = 0;
234
235         if (set_state (node)) {
236                 throw failed_constructor();
237         }
238
239         assert(_type != DataType::NIL);
240         assert(_sources.size() > 0);
241 }
242
243 Region::Region (Source& src, const XMLNode& node)
244         : _name(X_("error: XML did not reset this"))
245         , _type(DataType::NIL)
246         , _flags(Flag(0))
247         , _start(0) 
248         , _length(0) 
249         , _position(0) 
250         , _sync_position(_start)
251         , _layer(0)
252         , _first_edit(EditChangesNothing)
253         , _frozen(0)
254         , _read_data_count(0)
255         , _pending_changed(Change(0))
256         , _last_layer_op(0)
257         , _playlist(0)
258 {
259         _sources.push_back (&src);
260
261         _current_state_id = 0;
262
263         if (set_state (node)) {
264                 throw failed_constructor();
265         }
266         
267         assert(_type != DataType::NIL);
268         assert(_sources.size() > 0);
269 }
270
271 Region::~Region ()
272 {
273 }
274
275 void
276 Region::set_playlist (Playlist* pl)
277 {
278         _playlist = pl;
279 }
280
281 void
282 Region::store_state (RegionState& state) const
283 {
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;
290         state._name = _name;
291         state._first_edit = _first_edit;
292 }       
293
294 Change
295 Region::restore_and_return_flags (RegionState& state)
296 {
297         Change what_changed = Change (0);
298
299         {
300                 Glib::Mutex::Lock lm (_lock);
301                 
302                 if (_start != state._start) {
303                         what_changed = Change (what_changed|StartChanged);      
304                         _start = state._start;
305                 }
306                 if (_length != state._length) {
307                         what_changed = Change (what_changed|LengthChanged);
308                         _length = state._length;
309                 }
310                 if (_position != state._position) {
311                         what_changed = Change (what_changed|PositionChanged);
312                         _position = state._position;
313                 } 
314                 if (_sync_position != state._sync_position) {
315                         _sync_position = state._sync_position;
316                         what_changed = Change (what_changed|SyncOffsetChanged);
317                 }
318                 if (_layer != state._layer) {
319                         what_changed = Change (what_changed|LayerChanged);
320                         _layer = state._layer;
321                 }
322
323                 uint32_t old_flags = _flags;
324                 _flags = Flag (state._flags);
325                 
326                 if ((old_flags ^ state._flags) & Muted) {
327                         what_changed = Change (what_changed|MuteChanged);
328                 }
329                 if ((old_flags ^ state._flags) & Opaque) {
330                         what_changed = Change (what_changed|OpacityChanged);
331                 }
332                 if ((old_flags ^ state._flags) & Locked) {
333                         what_changed = Change (what_changed|LockChanged);
334                 }
335
336                 _first_edit = state._first_edit;
337         }
338
339         return what_changed;
340 }
341
342 void
343 Region::set_name (string str)
344
345 {
346         if (_name != str) {
347                 _name = str; 
348                 send_change (NameChanged);
349         }
350 }
351
352 void
353 Region::set_length (jack_nframes_t len, void *src)
354 {
355         if (_flags & Locked) {
356                 return;
357         }
358
359         if (_length != len && len != 0) {
360
361                 if (!verify_length (len)) {
362                         return;
363                 }
364                 
365                 _length = len;
366
367                 _flags = Region::Flag (_flags & ~WholeFile);
368
369                 first_edit ();
370                 maybe_uncopy ();
371
372                 if (!_frozen) {
373                         recompute_at_end ();
374
375                         char buf[64];
376                         snprintf (buf, sizeof (buf), "length set to %u", len);
377                         save_state (buf);
378                 }
379
380                 send_change (LengthChanged);
381         }
382 }
383
384 void
385 Region::maybe_uncopy ()
386 {
387 }
388
389 void
390 Region::first_edit ()
391 {
392         if (_first_edit != EditChangesNothing && _playlist) {
393
394                 _name = _playlist->session().new_region_name (_name);
395                 _first_edit = EditChangesNothing;
396
397                 send_change (NameChanged);
398                 CheckNewRegion (this);
399         }
400 }
401
402 void
403 Region::move_to_natural_position (void *src)
404 {
405         if (!_playlist) {
406                 return;
407         }
408
409         Region* whole_file_region = get_parent();
410
411         if (whole_file_region) {
412                 set_position (whole_file_region->position() + _start, src);
413         }
414 }
415         
416 void
417 Region::special_set_position (jack_nframes_t pos)
418 {
419         /* this is used when creating a whole file region as 
420            a way to store its "natural" or "captured" position.
421         */
422
423         _position = pos;
424 }
425
426 void
427 Region::set_position (jack_nframes_t pos, void *src)
428 {
429         if (_flags & Locked) {
430                 return;
431         }
432
433         if (_position != pos) {
434                 _position = pos;
435
436                 if (!_frozen) {
437                         char buf[64];
438                         snprintf (buf, sizeof (buf), "position set to %u", pos);
439                         save_state (buf);
440                 }
441         }
442
443         /* do this even if the position is the same. this helps out
444            a GUI that has moved its representation already.
445         */
446
447         send_change (PositionChanged);
448 }
449
450 void
451 Region::set_position_on_top (jack_nframes_t pos, void *src)
452 {
453         if (_flags & Locked) {
454                 return;
455         }
456
457         if (_position != pos) {
458                 _position = pos;
459
460                 if (!_frozen) {
461                         char buf[64];
462                         snprintf (buf, sizeof (buf), "position set to %u", pos);
463                         save_state (buf);
464                 }
465         }
466
467         _playlist->raise_region_to_top (*this);
468
469         /* do this even if the position is the same. this helps out
470            a GUI that has moved its representation already.
471         */
472         
473         send_change (PositionChanged);
474 }
475
476 void
477 Region::nudge_position (long n, void *src)
478 {
479         if (_flags & Locked) {
480                 return;
481         }
482
483         if (n == 0) {
484                 return;
485         }
486         
487         if (n > 0) {
488                 if (_position > max_frames - n) {
489                         _position = max_frames;
490                 } else {
491                         _position += n;
492                 }
493         } else {
494                 if (_position < (jack_nframes_t) -n) {
495                         _position = 0;
496                 } else {
497                         _position += n;
498                 }
499         }
500
501         if (!_frozen) {
502                 char buf[64];
503                 snprintf (buf, sizeof (buf), "position set to %u", _position);
504                 save_state (buf);
505         }
506
507         send_change (PositionChanged);
508 }
509
510 void
511 Region::set_start (jack_nframes_t pos, void *src)
512 {
513         if (_flags & Locked) {
514                 return;
515         }
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
519         */
520
521         if (_start != pos) {
522
523                 if (!verify_start (pos)) {
524                         return;
525                 }
526
527                 _start = pos;
528                 _flags = Region::Flag (_flags & ~WholeFile);
529                 first_edit ();
530
531                 if (!_frozen) {
532                         char buf[64];
533                         snprintf (buf, sizeof (buf), "start set to %u", pos);
534                         save_state (buf);
535                 }
536
537                 send_change (StartChanged);
538         }
539 }
540
541 void
542 Region::trim_start (jack_nframes_t new_position, void *src)
543 {
544         if (_flags & Locked) {
545                 return;
546         }
547         jack_nframes_t new_start;
548         int32_t start_shift;
549         
550         if (new_position > _position) {
551                 start_shift = new_position - _position;
552         } else {
553                 start_shift = -(_position - new_position);
554         }
555
556         if (start_shift > 0) {
557
558                 if (_start > max_frames - start_shift) {
559                         new_start = max_frames;
560                 } else {
561                         new_start = _start + start_shift;
562                 }
563
564                 if (!verify_start (new_start)) {
565                         return;
566                 }
567
568         } else if (start_shift < 0) {
569
570                 if (_start < (jack_nframes_t) -start_shift) {
571                         new_start = 0;
572                 } else {
573                         new_start = _start + start_shift;
574                 }
575         } else {
576                 return;
577         }
578
579         if (new_start == _start) {
580                 return;
581         }
582         
583         _start = new_start;
584         _flags = Region::Flag (_flags & ~WholeFile);
585         first_edit ();
586
587         if (!_frozen) {
588                 char buf[64];
589                 snprintf (buf, sizeof (buf), "slipped start to %u", _start);
590                 save_state (buf);
591         }
592
593         send_change (StartChanged);
594 }
595
596 void
597 Region::trim_front (jack_nframes_t new_position, void *src)
598 {
599         if (_flags & Locked) {
600                 return;
601         }
602
603         jack_nframes_t end = _position + _length - 1;
604         jack_nframes_t source_zero;
605
606         if (_position > _start) {
607                 source_zero = _position - _start;
608         } else {
609                 source_zero = 0; // its actually negative, but this will work for us
610         }
611
612         if (new_position < end) { /* can't trim it zero or negative length */
613                 
614                 jack_nframes_t newlen;
615
616                 /* can't trim it back passed where source position zero is located */
617                 
618                 new_position = max (new_position, source_zero);
619                 
620                 
621                 if (new_position > _position) {
622                         newlen = _length - (new_position - _position);
623                 } else {
624                         newlen = _length + (_position - new_position);
625                 }
626                 
627                 trim_to_internal (new_position, newlen, src);
628                 if (!_frozen) {
629                         recompute_at_start ();
630                 }
631         }
632 }
633
634 void
635 Region::trim_end (jack_nframes_t new_endpoint, void *src)
636 {
637         if (_flags & Locked) {
638                 return;
639         }
640
641         if (new_endpoint > _position) {
642                 trim_to_internal (_position, new_endpoint - _position, this);
643                 if (!_frozen) {
644                         recompute_at_end ();
645                 }
646         }
647 }
648
649 void
650 Region::trim_to (jack_nframes_t position, jack_nframes_t length, void *src)
651 {
652         if (_flags & Locked) {
653                 return;
654         }
655
656         trim_to_internal (position, length, src);
657
658         if (!_frozen) {
659                 recompute_at_start ();
660                 recompute_at_end ();
661         }
662 }
663
664 void
665 Region::trim_to_internal (jack_nframes_t position, jack_nframes_t length, void *src)
666 {
667         int32_t start_shift;
668         jack_nframes_t new_start;
669
670         if (_flags & Locked) {
671                 return;
672         }
673
674         if (position > _position) {
675                 start_shift = position - _position;
676         } else {
677                 start_shift = -(_position - position);
678         }
679
680         if (start_shift > 0) {
681
682                 if (_start > max_frames - start_shift) {
683                         new_start = max_frames;
684                 } else {
685                         new_start = _start + start_shift;
686                 }
687
688
689         } else if (start_shift < 0) {
690
691                 if (_start < (jack_nframes_t) -start_shift) {
692                         new_start = 0;
693                 } else {
694                         new_start = _start + start_shift;
695                 }
696         } else {
697                 new_start = _start;
698         }
699
700         if (!verify_start_and_length (new_start, length)) {
701                 return;
702         }
703
704         Change what_changed = Change (0);
705
706         if (_start != new_start) {
707                 _start = new_start;
708                 what_changed = Change (what_changed|StartChanged);
709         }
710         if (_length != length) {
711                 _length = length;
712                 what_changed = Change (what_changed|LengthChanged);
713         }
714         if (_position != position) {
715                 _position = position;
716                 what_changed = Change (what_changed|PositionChanged);
717         }
718         
719         _flags = Region::Flag (_flags & ~WholeFile);
720
721         if (what_changed & (StartChanged|LengthChanged)) {
722                 first_edit ();
723         } 
724
725         if (what_changed) {
726                 
727                 if (!_frozen) {
728                         char buf[64];
729                         snprintf (buf, sizeof (buf), "trimmed to %u-%u", _position, _position+_length-1);
730                         save_state (buf);
731                 }
732
733                 send_change (what_changed);
734         }
735 }       
736
737 void
738 Region::set_hidden (bool yn)
739 {
740         if (hidden() != yn) {
741
742                 if (yn) {
743                         _flags = Flag (_flags|Hidden);
744                 } else {
745                         _flags = Flag (_flags & ~Hidden);
746                 }
747
748                 send_change (HiddenChanged);
749         }
750 }
751
752 void
753 Region::set_muted (bool yn)
754 {
755         if (muted() != yn) {
756
757                 if (yn) {
758                         _flags = Flag (_flags|Muted);
759                 } else {
760                         _flags = Flag (_flags & ~Muted);
761                 }
762
763                 if (!_frozen) {
764                         char buf[64];
765                         if (yn) {
766                                 snprintf (buf, sizeof (buf), "muted");
767                         } else {
768                                 snprintf (buf, sizeof (buf), "unmuted");
769                         }
770                         save_state (buf);
771                 }
772
773                 send_change (MuteChanged);
774         }
775 }
776
777 void
778 Region::set_opaque (bool yn)
779 {
780         if (opaque() != yn) {
781                 if (!_frozen) {
782                         char buf[64];
783                         if (yn) {
784                                 snprintf (buf, sizeof (buf), "opaque");
785                                 _flags = Flag (_flags|Opaque);
786                         } else {
787                                 snprintf (buf, sizeof (buf), "translucent");
788                                 _flags = Flag (_flags & ~Opaque);
789                         }
790                         save_state (buf);
791                 }
792                 send_change (OpacityChanged);
793         }
794 }
795
796 void
797 Region::set_locked (bool yn)
798 {
799         if (locked() != yn) {
800                 if (!_frozen) {
801                         char buf[64];
802                         if (yn) {
803                                 snprintf (buf, sizeof (buf), "locked");
804                                 _flags = Flag (_flags|Locked);
805                         } else {
806                                 snprintf (buf, sizeof (buf), "unlocked");
807                                 _flags = Flag (_flags & ~Locked);
808                         }
809                         save_state (buf);
810                 }
811                 send_change (LockChanged);
812         }
813 }
814
815 void
816 Region::set_sync_position (jack_nframes_t absolute_pos)
817 {
818         jack_nframes_t file_pos;
819
820         file_pos = _start + (absolute_pos - _position);
821
822         if (file_pos != _sync_position) {
823                 
824                 _sync_position = file_pos;
825                 _flags = Flag (_flags|SyncMarked);
826
827                 if (!_frozen) {
828                         char buf[64];
829                         maybe_uncopy ();
830                         snprintf (buf, sizeof (buf), "sync point set to %u", _sync_position);
831                         save_state (buf);
832                 }
833                 send_change (SyncOffsetChanged);
834         }
835 }
836
837 void
838 Region::clear_sync_position ()
839 {
840         if (_flags & SyncMarked) {
841                 _flags = Flag (_flags & ~SyncMarked);
842
843                 if (!_frozen) {
844                         maybe_uncopy ();
845                         save_state ("sync point removed");
846                 }
847                 send_change (SyncOffsetChanged);
848         }
849 }
850
851 jack_nframes_t
852 Region::sync_offset (int& dir) const
853 {
854         /* returns the sync point relative the first frame of the region */
855
856         if (_flags & SyncMarked) {
857                 if (_sync_position > _start) {
858                         dir = 1;
859                         return _sync_position - _start; 
860                 } else {
861                         dir = -1;
862                         return _start - _sync_position;
863                 }
864         } else {
865                 dir = 0;
866                 return 0;
867         }
868 }
869
870 jack_nframes_t 
871 Region::adjust_to_sync (jack_nframes_t pos)
872 {
873         int sync_dir;
874         jack_nframes_t offset = sync_offset (sync_dir);
875         
876         if (sync_dir > 0) {
877                 if (max_frames - pos > offset) {
878                         pos += offset;
879                 }
880         } else {
881                 if (pos > offset) {
882                         pos -= offset;
883                 } else {
884                         pos = 0;
885                 }
886         }
887
888         return pos;
889 }
890
891 jack_nframes_t
892 Region::sync_position() const
893 {
894         if (_flags & SyncMarked) {
895                 return _sync_position; 
896         } else {
897                 return _start;
898         }
899 }
900
901
902 void
903 Region::raise ()
904 {
905         if (_playlist == 0) {
906                 return;
907         }
908
909         _playlist->raise_region (*this);
910 }
911
912 void
913 Region::lower ()
914 {
915         if (_playlist == 0) {
916                 return;
917         }
918
919         _playlist->lower_region (*this);
920 }
921
922 void
923 Region::raise_to_top ()
924 {
925
926         if (_playlist == 0) {
927                 return;
928         }
929
930         _playlist->raise_region_to_top (*this);
931 }
932
933 void
934 Region::lower_to_bottom ()
935 {
936         if (_playlist == 0) {
937                 return;
938         }
939
940         _playlist->lower_region_to_bottom (*this);
941 }
942
943 void
944 Region::set_layer (layer_t l)
945 {
946         if (_layer != l) {
947                 _layer = l;
948                 
949                 if (!_frozen) {
950                         char buf[64];
951                         snprintf (buf, sizeof (buf), "layer set to %" PRIu32, _layer);
952                         save_state (buf);
953                 }
954                 
955                 send_change (LayerChanged);
956         }
957 }
958
959 XMLNode&
960 Region::state (bool full_state)
961 {
962         XMLNode *node = new XMLNode ("Region");
963         char buf[64];
964         
965         _id.print (buf);
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);
975
976         /* note: flags are stored by derived classes */
977
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);
982
983         return *node;
984 }
985
986 XMLNode&
987 Region::get_state ()
988 {
989         return state (true);
990 }
991
992 int
993 Region::set_state (const XMLNode& node)
994 {
995         const XMLNodeList& nlist = node.children();
996         const XMLProperty *prop;
997
998         if (_extra_xml) {
999                 delete _extra_xml;
1000                 _extra_xml = 0;
1001         }
1002
1003         if ((prop = node.property ("id")) == 0) {
1004                 error << _("Session: XMLNode describing a Region is incomplete (no id)") << endmsg;
1005                 return -1;
1006         }
1007
1008         _id = prop->value();
1009
1010         if ((prop = node.property ("name")) == 0) {
1011                 error << _("Session: XMLNode describing a Region is incomplete (no name)") << endmsg;
1012                 return -1;
1013         }
1014
1015         _name = prop->value();
1016         
1017         if ((prop = node.property ("type")) == 0) {
1018                 _type = DataType::AUDIO;
1019         } else {
1020                 _type = DataType(prop->value());
1021         }
1022
1023         if ((prop = node.property ("start")) != 0) {
1024                 _start = (jack_nframes_t) atoi (prop->value().c_str());
1025         }
1026
1027         if ((prop = node.property ("length")) != 0) {
1028                 _length = (jack_nframes_t) atoi (prop->value().c_str());
1029         }
1030
1031         if ((prop = node.property ("position")) != 0) {
1032                 _position = (jack_nframes_t) atoi (prop->value().c_str());
1033         }
1034
1035         if ((prop = node.property ("layer")) != 0) {
1036                 _layer = (layer_t) atoi (prop->value().c_str());
1037         }
1038
1039         /* note: derived classes set flags */
1040
1041         if ((prop = node.property ("sync-position")) != 0) {
1042                 _sync_position = (jack_nframes_t) atoi (prop->value().c_str());
1043         } else {
1044                 _sync_position = _start;
1045         }
1046         
1047         for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1048                 
1049                 XMLNode *child;
1050                 
1051                 child = (*niter);
1052                 
1053                 if (child->name () == "extra") {
1054                         _extra_xml = new XMLNode (*child);
1055                         break;
1056                 }
1057         }
1058
1059         _first_edit = EditChangesNothing;
1060
1061         return 0;
1062 }
1063
1064 void
1065 Region::freeze ()
1066 {
1067         _frozen++;
1068 }
1069
1070 void
1071 Region::thaw (const string& why)
1072 {
1073         Change what_changed = Change (0);
1074
1075         {
1076                 Glib::Mutex::Lock lm (_lock);
1077
1078                 if (_frozen && --_frozen > 0) {
1079                         return;
1080                 }
1081
1082                 if (_pending_changed) {
1083                         what_changed = _pending_changed;
1084                         _pending_changed = Change (0);
1085                 }
1086         }
1087
1088         if (what_changed == Change (0)) {
1089                 return;
1090         }
1091
1092         if (what_changed & LengthChanged) {
1093                 if (what_changed & PositionChanged) {
1094                         recompute_at_start ();
1095                 } 
1096                 recompute_at_end ();
1097         }
1098                 
1099         save_state (why);
1100         StateChanged (what_changed);
1101 }
1102
1103 void
1104 Region::send_change (Change what_changed)
1105 {
1106         {
1107                 Glib::Mutex::Lock lm (_lock);
1108                 if (_frozen) {
1109                         _pending_changed = Change (_pending_changed|what_changed);
1110                         return;
1111                 } 
1112         }
1113
1114         StateManager::send_state_changed (what_changed);
1115 }
1116
1117 void
1118 Region::set_last_layer_op (uint64_t when)
1119 {
1120         _last_layer_op = when;
1121 }
1122
1123 bool
1124 Region::overlap_equivalent (const Region& other) const
1125 {
1126         return coverage (other.first_frame(), other.last_frame()) != OverlapNone;
1127 }
1128
1129 bool
1130 Region::equivalent (const Region& other) const
1131 {
1132         return _start == other._start &&
1133                 _position == other._position &&
1134                 _length == other._length;
1135 }
1136
1137 bool
1138 Region::size_equivalent (const Region& other) const
1139 {
1140         return _start == other._start &&
1141                 _length == other._length;
1142 }
1143
1144 bool
1145 Region::region_list_equivalent (const Region& other) const
1146 {
1147         return size_equivalent (other) && source_equivalent (other) && _name == other._name;
1148 }
1149
1150 void
1151 Region::source_deleted (Source* ignored)
1152 {
1153         delete this;
1154 }
1155
1156 void
1157 Region::lock_sources ()
1158 {
1159         SourceList::iterator i;
1160         set<Source*> unique_srcs;
1161
1162         for (i = _sources.begin(); i != _sources.end(); ++i) {
1163                 unique_srcs.insert (*i);
1164                 (*i)->use ();
1165         }
1166
1167         for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1168                 if (unique_srcs.find (*i) == unique_srcs.end()) {
1169                         (*i)->use ();
1170                 }
1171         }
1172 }
1173
1174 void
1175 Region::unlock_sources ()
1176 {
1177         SourceList::iterator i;
1178         set<Source*> unique_srcs;
1179
1180         for (i = _sources.begin(); i != _sources.end(); ++i) {
1181                 unique_srcs.insert (*i);
1182                 (*i)->release ();
1183         }
1184
1185         for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1186                 if (unique_srcs.find (*i) == unique_srcs.end()) {
1187                         (*i)->release ();
1188                 }
1189         }
1190 }
1191
1192 vector<string>
1193 Region::master_source_names ()
1194 {
1195         SourceList::iterator i;
1196
1197         vector<string> names;
1198         for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1199                 names.push_back((*i)->name());
1200         }
1201
1202         return names;
1203 }
1204
1205 bool
1206 Region::source_equivalent (const Region& other) const
1207 {
1208         SourceList::const_iterator i;
1209         SourceList::const_iterator io;
1210
1211         for (i = _sources.begin(), io = other._sources.begin(); i != _sources.end() && io != other._sources.end(); ++i, ++io) {
1212                 if ((*i)->id() != (*io)->id()) {
1213                         return false;
1214                 }
1215         }
1216
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()) {
1219                         return false;
1220                 }
1221         }
1222
1223         return true;
1224 }
1225
1226 bool
1227 Region::verify_length (jack_nframes_t len)
1228 {
1229         for (uint32_t n=0; n < _sources.size(); ++n) {
1230                 if (_start > _sources[n]->length() - len) {
1231                         return false;
1232                 }
1233         }
1234         return true;
1235 }
1236
1237 bool
1238 Region::verify_start_and_length (jack_nframes_t new_start, jack_nframes_t new_length)
1239 {
1240         for (uint32_t n=0; n < _sources.size(); ++n) {
1241                 if (new_length > _sources[n]->length() - new_start) {
1242                         return false;
1243                 }
1244         }
1245         return true;
1246 }
1247 bool
1248 Region::verify_start (jack_nframes_t pos)
1249 {
1250         for (uint32_t n=0; n < _sources.size(); ++n) {
1251                 if (pos > _sources[n]->length() - _length) {
1252                         return false;
1253                 }
1254         }
1255         return true;
1256 }
1257
1258 bool
1259 Region::verify_start_mutable (jack_nframes_t& new_start)
1260 {
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;
1264                 }
1265         }
1266         return true;
1267 }
1268
1269 Region*
1270 Region::get_parent()
1271 {
1272         Region* r = 0;
1273
1274         if (_playlist) {
1275                 r = _playlist->session().find_whole_file_parent (*this);
1276         }
1277         
1278         return r;
1279 }
1280