fix compose mess, and a number of 64 bit printf specs
[ardour.git] / libs / ardour / playlist.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 <set>
22 #include <fstream>
23 #include <algorithm>
24 #include <unistd.h>
25 #include <cerrno>
26 #include <string>
27 #include <climits>
28
29 #include <sigc++/bind.h>
30
31 #include <pbd/failed_constructor.h>
32 #include <pbd/stl_delete.h>
33 #include <pbd/xml++.h>
34
35 #include <ardour/playlist.h>
36 #include <ardour/session.h>
37 #include <ardour/region.h>
38 #include <ardour/region_factory.h>
39
40 #include "i18n.h"
41
42 using namespace std;
43 using namespace ARDOUR;
44 //using namespace sigc;
45
46 sigc::signal<void,Playlist*> Playlist::PlaylistCreated;
47
48 struct ShowMeTheList {
49     ShowMeTheList (Playlist *pl, const string& n) : playlist (pl), name (n) {}
50     ~ShowMeTheList () { 
51             cerr << ">>>>" << name << endl; playlist->dump(); cerr << "<<<<" << name << endl << endl; 
52     };
53     Playlist *playlist;
54     string name;
55 };
56
57 struct RegionSortByLayer {
58     bool operator() (Region *a, Region *b) {
59             return a->layer() < b->layer();
60     }
61 };
62
63 struct RegionSortByPosition {
64     bool operator() (Region *a, Region *b) {
65             return a->position() < b->position();
66     }
67 };
68
69 struct RegionSortByLastLayerOp {
70     bool operator() (Region *a, Region *b) {
71             return a->last_layer_op() < b->last_layer_op();
72     }
73 };
74
75 Playlist::Playlist (Session& sess, string nom, bool hide)
76         : _session (sess)
77 {
78         init (hide);
79         _name = nom;
80         _orig_diskstream_id = 0;
81         
82 }
83
84 Playlist::Playlist (Session& sess, const XMLNode& node, bool hide)
85         : _session (sess)
86 {
87         init (hide);
88         _name = "unnamed"; /* reset by set_state */
89         _orig_diskstream_id = 0;
90         
91         if (set_state (node)) {
92                 throw failed_constructor();
93         }
94 }
95
96 Playlist::Playlist (const Playlist& other, string namestr, bool hide)
97         : _name (namestr), _session (other._session), _orig_diskstream_id(other._orig_diskstream_id)
98 {
99         init (hide);
100
101         other.copy_regions (regions);
102
103         for (list<Region*>::iterator x = regions.begin(); x != regions.end(); ++x) {
104                 (*x)->set_playlist (this);
105         }
106 }
107
108 Playlist::Playlist (const Playlist& other, jack_nframes_t start, jack_nframes_t cnt, string str, bool hide)
109         : _name (str), _session (other._session), _orig_diskstream_id(other._orig_diskstream_id)
110 {
111         RegionLock rlock2 (&((Playlist&)other));
112         
113         jack_nframes_t end = start + cnt - 1;
114
115         init (hide);
116
117         for (RegionList::const_iterator i = other.regions.begin(); i != other.regions.end(); i++) {
118
119                 Region   *region;
120                 Region   *new_region;
121                 jack_nframes_t offset = 0;
122                 jack_nframes_t position = 0;
123                 jack_nframes_t len = 0;
124                 string    new_name;
125                 OverlapType overlap;
126
127                 region = *i;
128
129                 overlap = region->coverage (start, end);
130
131                 switch (overlap) {
132                 case OverlapNone:
133                         continue;
134
135                 case OverlapInternal:
136                         offset = start - region->position();
137                         position = 0;
138                         len = cnt;
139                         break;
140
141                 case OverlapStart:
142                         offset = 0;
143                         position = region->position() - start;
144                         len = end - region->position();
145                         break;
146
147                 case OverlapEnd:
148                         offset = start - region->position();
149                         position = 0;
150                         len = region->length() - offset;
151                         break;
152
153                 case OverlapExternal:
154                         offset = 0;
155                         position = region->position() - start;
156                         len = region->length();
157                         break;
158                 }
159
160                 _session.region_name (new_name, region->name(), false);
161
162                 new_region = createRegion (*region, offset, len, new_name, region->layer(), region->flags());
163
164                 add_region_internal (new_region, position, true);
165         }
166         
167         /* this constructor does NOT notify others (session) */
168 }
169
170 void
171 Playlist::ref ()
172 {
173         ++_refcnt;
174         InUse (this, true); /* EMIT SIGNAL */
175 }
176
177 void
178 Playlist::unref ()
179 {
180         if (_refcnt > 0) {
181                 _refcnt--; 
182         }
183         if (_refcnt == 0) {
184                 InUse (this, false); /* EMIT SIGNAL */
185                 
186                 if (_hidden) {
187                         /* nobody knows we exist */
188                         delete this;
189                 }
190         }
191 }
192
193
194 void
195 Playlist::copy_regions (RegionList& newlist) const
196 {
197         RegionLock rlock (const_cast<Playlist *> (this));
198
199         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
200                 newlist.push_back (createRegion (**i));
201         }
202 }
203
204 void
205 Playlist::init (bool hide)
206 {
207         atomic_set (&block_notifications, 0);
208         atomic_set (&ignore_state_changes, 0);
209         pending_modified = false;
210         pending_length = false;
211         _refcnt = 0;
212         _hidden = hide;
213         _splicing = false;
214         _nudging = false;
215         in_set_state = false;
216         _edit_mode = _session.get_edit_mode();
217         in_flush = false;
218         in_partition = false;
219         subcnt = 0;
220         _read_data_count = 0;
221         _frozen = false;
222         save_on_thaw = false;
223         layer_op_counter = 0;
224         freeze_length = 0;
225
226         // _session.LayerModelChanged.connect (slot (*this, &Playlist::relayer));
227
228         Modified.connect (mem_fun (*this, &Playlist::mark_session_dirty));
229 }
230
231 Playlist::Playlist (const Playlist& pl)
232         : _session (pl._session)
233 {
234         fatal << _("playlist const copy constructor called") << endmsg;
235 }
236
237 Playlist::Playlist (Playlist& pl)
238         : _session (pl._session)
239 {
240         fatal << _("playlist non-const copy constructor called") << endmsg;
241 }
242
243 Playlist::~Playlist ()
244 {
245 }
246
247 void
248 Playlist::set_name (const string& str)
249 {
250         /* in a typical situation, a playlist is being used
251            by one diskstream and also is referenced by the
252            Session. if there are more references than that,
253            then don't change the name.
254         */
255
256         if (_refcnt > 2) {
257                 return;
258         }
259
260         _name = str; 
261         NameChanged(); /* EMIT SIGNAL */
262 }
263
264 /***********************************************************************
265  CHANGE NOTIFICATION HANDLING
266  
267  Notifications must be delayed till the region_lock is released. This
268  is necessary because handlers for the signals may need to acquire
269  the lock (e.g. to read from the playlist).
270  ***********************************************************************/
271
272 void
273 Playlist::freeze ()
274 {
275         delay_notifications ();
276         atomic_inc (&ignore_state_changes);
277 }
278
279 void
280 Playlist::thaw ()
281 {
282         atomic_dec (&ignore_state_changes);
283         release_notifications ();
284 }
285
286
287 void
288 Playlist::delay_notifications ()
289 {
290         atomic_inc (&block_notifications);
291         freeze_length = _get_maximum_extent();
292 }
293
294 void
295 Playlist::release_notifications ()
296 {
297         if (atomic_dec_and_test(&block_notifications)) { 
298                 flush_notifications ();
299         } 
300 }
301
302
303 void
304 Playlist::notify_modified ()
305 {
306         if (holding_state ()) {
307                 pending_modified = true;
308         } else {
309                 pending_modified = false;
310                 Modified(); /* EMIT SIGNAL */
311         }
312 }
313
314 void
315 Playlist::notify_region_removed (Region *r)
316 {
317         if (holding_state ()) {
318                 pending_removals.insert (pending_removals.end(), r);
319         } else {
320                 RegionRemoved (r); /* EMIT SIGNAL */
321                 /* this might not be true, but we have to act
322                    as though it could be.
323                 */
324                 LengthChanged (); /* EMIT SIGNAL */
325                 Modified (); /* EMIT SIGNAL */
326         }
327 }
328
329 void
330 Playlist::notify_region_added (Region *r)
331 {
332         if (holding_state()) {
333                 pending_adds.insert (pending_adds.end(), r);
334         } else {
335                 RegionAdded (r); /* EMIT SIGNAL */
336                 /* this might not be true, but we have to act
337                    as though it could be.
338                 */
339                 LengthChanged (); /* EMIT SIGNAL */
340                 Modified (); /* EMIT SIGNAL */
341         }
342 }
343
344 void
345 Playlist::notify_length_changed ()
346 {
347         if (holding_state ()) {
348                 pending_length = true;
349         } else {
350                 LengthChanged(); /* EMIT SIGNAL */
351                 Modified (); /* EMIT SIGNAL */
352         }
353 }
354
355 void
356 Playlist::flush_notifications ()
357 {
358         RegionList::iterator r;
359         RegionList::iterator a;
360         set<Region*> dependent_checks_needed;
361         uint32_t n = 0;
362
363         if (in_flush) {
364                 return;
365         }
366
367         in_flush = true;
368
369         /* we have no idea what order the regions ended up in pending
370            bounds (it could be based on selection order, for example).
371            so, to preserve layering in the "most recently moved is higher" 
372            model, sort them by existing layer, then timestamp them.
373         */
374
375         // RegionSortByLayer cmp;
376         // pending_bounds.sort (cmp);
377
378         for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
379                 if (_session.get_layer_model() == Session::MoveAddHigher) {
380                         timestamp_layer_op (**r);
381                 }
382                 pending_length = true;
383                 n++;
384         }
385
386         for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
387                 dependent_checks_needed.insert (*r);
388                 /* don't increment n again - its the same list */
389         }
390
391         for (a = pending_adds.begin(); a != pending_adds.end(); ++a) {
392                 dependent_checks_needed.insert (*a);
393                 RegionAdded (*a); /* EMIT SIGNAL */
394                 n++;
395         }
396
397         for (set<Region*>::iterator x = dependent_checks_needed.begin(); x != dependent_checks_needed.end(); ++x) {
398                 check_dependents (**x, false);
399         }
400
401         for (r = pending_removals.begin(); r != pending_removals.end(); ++r) {
402                 remove_dependents (**r);
403                 RegionRemoved (*r); /* EMIT SIGNAL */
404                 n++;
405         }
406
407         if ((freeze_length != _get_maximum_extent()) || pending_length) {
408                 pending_length = 0;
409                 LengthChanged(); /* EMIT SIGNAL */
410                 n++;
411         }
412
413         if (n || pending_modified) {
414                 possibly_splice ();
415                 relayer ();
416                 pending_modified = false;
417                 Modified (); /* EMIT SIGNAL */
418         }
419
420         pending_adds.clear ();
421         pending_removals.clear ();
422         pending_bounds.clear ();
423
424         if (save_on_thaw) {
425                 save_on_thaw = false;
426                 save_state (last_save_reason);
427         }
428         
429         in_flush = false;
430 }
431
432 /*************************************************************
433   PLAYLIST OPERATIONS
434  *************************************************************/
435
436 void
437 Playlist::add_region (const Region& region, jack_nframes_t position, float times, bool with_save) 
438
439         RegionLock rlock (this);
440         
441         times = fabs (times);
442         
443         int itimes = (int) floor (times);
444
445         jack_nframes_t pos = position;
446         
447         if (itimes >= 1) {
448                 add_region_internal (const_cast<Region*>(&region), pos, true);
449                 pos += region.length();
450                 --itimes;
451         }
452         
453         /* later regions will all be spliced anyway */
454         
455         if (!holding_state ()) {
456                 possibly_splice_unlocked ();
457         }
458
459         /* note that itimes can be zero if we being asked to just
460            insert a single fraction of the region.
461         */
462
463         for (int i = 0; i < itimes; ++i) {
464                 Region *copy = createRegion (region);
465                 add_region_internal (copy, pos, true);
466                 pos += region.length();
467         }
468         
469         if (floor (times) != times) {
470                 jack_nframes_t length = (jack_nframes_t) floor (region.length() * (times - floor (times)));
471                 string name;
472                 _session.region_name (name, region.name(), false);
473                 Region *sub = createRegion (region, 0, length, name, region.layer(), region.flags());
474                 add_region_internal (sub, pos, true);
475         }
476         
477         if (with_save) {
478                 maybe_save_state (_("add region"));
479         }
480 }
481
482 void
483 Playlist::add_region_internal (Region *region, jack_nframes_t position, bool delay_sort)
484 {
485         RegionSortByPosition cmp;
486         jack_nframes_t old_length = 0;
487
488         // cerr << "adding region " << region->name() << " at " << position << endl;
489
490         if (!holding_state()) {
491                  old_length = _get_maximum_extent();
492         }
493
494         region->set_playlist (this);
495         region->set_position (position, this);
496         region->lock_sources ();
497
498         timestamp_layer_op (*region);
499
500         regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
501
502         if (!holding_state () && !in_set_state) {
503                 /* layers get assigned from XML state */
504                 relayer ();
505         }
506
507         /* we need to notify the existence of new region before checking dependents. Ick. */
508
509         notify_region_added (region);
510         
511         if (!holding_state ()) {
512                 check_dependents (*region, false);
513                 if (old_length != _get_maximum_extent()) {
514                         notify_length_changed ();
515                 }
516         }
517
518         region->StateChanged.connect (sigc::bind (mem_fun (this, &Playlist::region_changed_proxy), region));
519 }
520
521 void
522 Playlist::replace_region (Region& old, Region& newr, jack_nframes_t pos)
523 {
524         RegionLock rlock (this);
525
526         remove_region_internal (&old);
527         add_region_internal (&newr, pos);
528
529         if (!holding_state ()) {
530                 possibly_splice_unlocked ();
531         }
532
533         maybe_save_state (_("replace region"));
534 }
535
536 void
537 Playlist::remove_region (Region *region)
538 {
539         RegionLock rlock (this);
540         remove_region_internal (region);
541
542         if (!holding_state ()) {
543                 possibly_splice_unlocked ();
544         }
545
546         maybe_save_state (_("remove region"));
547 }
548
549 int
550 Playlist::remove_region_internal (Region *region, bool delay_sort)
551 {
552         RegionList::iterator i;
553         jack_nframes_t old_length = 0;
554
555         // cerr << "removing region " << region->name() << endl;
556
557         if (!holding_state()) {
558                 old_length = _get_maximum_extent();
559         }
560
561         for (i = regions.begin(); i != regions.end(); ++i) {
562                 if (*i == region) {
563
564                         regions.erase (i);
565
566                         if (!holding_state ()) {
567                                 relayer ();
568                                 remove_dependents (*region);
569                                 
570                                 if (old_length != _get_maximum_extent()) {
571                                         notify_length_changed ();
572                                 }
573                         }
574
575                         notify_region_removed (region);
576                         return 0;
577                 }
578         }
579         return -1;
580 }
581
582 void
583 Playlist::partition (jack_nframes_t start, jack_nframes_t end, bool just_top_level)
584 {
585         RegionList thawlist;
586
587         partition_internal (start, end, false, thawlist);
588
589         for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
590                 (*i)->thaw ("separation");
591         }
592
593         maybe_save_state (_("separate"));
594 }
595
596 void
597 Playlist::partition_internal (jack_nframes_t start, jack_nframes_t end, bool cutting, RegionList& thawlist)
598 {
599         RegionLock rlock (this);
600         Region *region;
601         Region *current;
602         string new_name;
603         RegionList::iterator tmp;
604         OverlapType overlap;
605         jack_nframes_t pos1, pos2, pos3, pos4;
606         RegionList new_regions;
607
608         in_partition = true;
609
610         /* need to work from a copy, because otherwise the regions we add during the process
611            get operated on as well.
612         */
613
614         RegionList copy = regions;
615
616         for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
617                 
618                 tmp = i;
619                 ++tmp;
620
621                 current = *i;
622                 
623                 if (current->first_frame() == start && current->last_frame() == end) {
624                         if (cutting) {
625                                 remove_region_internal (current);
626                         }
627                         continue;
628                 }
629                 
630                 if ((overlap = current->coverage (start, end)) == OverlapNone) {
631                         continue;
632                 }
633                 
634                 pos1 = current->position();
635                 pos2 = start;
636                 pos3 = end;
637                 pos4 = current->last_frame();
638
639                 if (overlap == OverlapInternal) {
640                         
641                         /* split: we need 3 new regions, the front, middle and end.
642                            cut:   we need 2 regions, the front and end.
643                         */
644                         
645                         /*
646                                          start                 end
647                           ---------------*************************------------
648                                          P1  P2              P3  P4
649                           SPLIT:
650                           ---------------*****++++++++++++++++====------------
651                           CUT
652                           ---------------*****----------------====------------
653                           
654                         */
655
656                         if (!cutting) {
657                                 
658                                 /* "middle" ++++++ */
659                                 
660                                 _session.region_name (new_name, current->name(), false);
661                                 region = createRegion (*current, pos2 - pos1, pos3 - pos2, new_name,
662                                                        regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit|Region::RightOfSplit));
663                                 add_region_internal (region, start, true);
664                                 new_regions.push_back (region);
665                         }
666                         
667                         /* "end" ====== */
668                         
669                         _session.region_name (new_name, current->name(), false);
670                         region = createRegion (*current, pos3 - pos1, pos4 - pos3, new_name, 
671                                                regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
672
673                         add_region_internal (region, end, true);
674                         new_regions.push_back (region);
675
676                         /* "front" ***** */
677                                 
678                         current->freeze ();
679                         thawlist.push_back (current);
680                         current->trim_end (pos2, this);
681
682                 } else if (overlap == OverlapEnd) {
683
684                         /*
685                                                               start           end
686                                     ---------------*************************------------
687                                                    P1           P2         P4   P3
688                                     SPLIT:                                                 
689                                     ---------------**************+++++++++++------------
690                                     CUT:                                                   
691                                     ---------------**************-----------------------
692
693                         */
694
695                         if (!cutting) {
696                                 
697                                 /* end +++++ */
698                                 
699                                 _session.region_name (new_name, current->name(), false);
700                                 region = createRegion (*current, pos2 - pos1, pos4 - pos2, new_name, (layer_t) regions.size(),
701                                                        Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit));
702                                 add_region_internal (region, start, true);
703                                 new_regions.push_back (region);
704                         }
705
706                         /* front ****** */
707
708                         current->freeze ();
709                         thawlist.push_back (current);
710                         current->trim_end (pos2, this);
711
712                 } else if (overlap == OverlapStart) {
713
714                         /* split: we need 2 regions: the front and the end.
715                            cut: just trim current to skip the cut area
716                         */
717                                 
718                         /*
719                                                         start           end
720                                     ---------------*************************------------
721                                        P2          P1 P3                   P4          
722
723                                     SPLIT:
724                                     ---------------****+++++++++++++++++++++------------
725                                     CUT:
726                                     -------------------*********************------------
727                                     
728                         */
729
730                         if (!cutting) {
731                                 
732                                 /* front **** */
733                                  _session.region_name (new_name, current->name(), false);
734                                  region = createRegion (*current, 0, pos3 - pos1, new_name,
735                                                         regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
736                                  add_region_internal (region, pos1, true);
737                                  new_regions.push_back (region);
738                         } 
739                         
740                         /* end */
741                         
742                         current->freeze ();
743                         thawlist.push_back (current);
744                         current->trim_front (pos3, this);
745
746                 } else if (overlap == OverlapExternal) {
747
748                         /* split: no split required.
749                            cut: remove the region.
750                         */
751                                 
752                         /*
753                                        start                                      end
754                                     ---------------*************************------------
755                                        P2          P1 P3                   P4          
756
757                                     SPLIT:
758                                     ---------------*************************------------
759                                     CUT:
760                                     ----------------------------------------------------
761                                     
762                         */
763
764                         if (cutting) {
765                                 remove_region_internal (current);
766                         }
767                         new_regions.push_back (current);
768                 }
769         }
770
771         in_partition = false;
772
773         for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
774                 check_dependents (**i, false);
775         }
776 }
777
778 Playlist*
779 Playlist::cut_copy (Playlist* (Playlist::*pmf)(jack_nframes_t, jack_nframes_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
780 {
781         Playlist* ret;
782         Playlist* pl;
783         jack_nframes_t start;
784
785         if (ranges.empty()) {
786                 return 0;
787         }
788
789         start = ranges.front().start;
790
791
792         for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
793
794                 pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
795                 
796                 if (i == ranges.begin()) {
797                         ret = pl;
798                 } else {
799                         
800                         /* paste the next section into the nascent playlist,
801                            offset to reflect the start of the first range we
802                            chopped.
803                         */
804
805                         ret->paste (*pl, (*i).start - start, 1.0f);
806                         delete pl;
807                 }
808         }
809
810         if (ret) {
811                 /* manually notify session of new playlist here
812                    because the playlists were constructed without notifying 
813                 */
814                 PlaylistCreated (ret);
815         }
816         
817         return ret;
818 }
819
820 Playlist*
821 Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
822 {
823         Playlist* (Playlist::*pmf)(jack_nframes_t,jack_nframes_t,bool) = &Playlist::cut;
824         return cut_copy (pmf, ranges, result_is_hidden);
825 }
826
827 Playlist*
828 Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
829 {
830         Playlist* (Playlist::*pmf)(jack_nframes_t,jack_nframes_t,bool) = &Playlist::copy;
831         return cut_copy (pmf, ranges, result_is_hidden);
832 }
833
834 Playlist *
835 Playlist::cut (jack_nframes_t start, jack_nframes_t cnt, bool result_is_hidden)
836 {
837         Playlist *the_copy;
838         RegionList thawlist;
839         char buf[32];
840
841         snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
842         string new_name = _name;
843         new_name += '.';
844         new_name += buf;
845
846         if ((the_copy = copyPlaylist (*this, start, cnt, new_name, result_is_hidden)) == 0) {
847                 return 0;
848         }
849
850         partition_internal (start, start+cnt-1, true, thawlist);
851         possibly_splice ();
852
853         for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
854                 (*i)->thaw ("playlist cut");
855         }
856
857         maybe_save_state (_("cut"));
858
859         return the_copy;
860 }
861
862 Playlist *
863 Playlist::copy (jack_nframes_t start, jack_nframes_t cnt, bool result_is_hidden)
864 {
865         char buf[32];
866         
867         snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
868         string new_name = _name;
869         new_name += '.';
870         new_name += buf;
871
872         cnt = min (_get_maximum_extent() - start, cnt);
873         return copyPlaylist (*this, start, cnt, new_name, result_is_hidden);
874 }
875
876 int
877 Playlist::paste (Playlist& other, jack_nframes_t position, float times)
878 {
879         times = fabs (times);
880         jack_nframes_t old_length;
881
882         {
883                 RegionLock rl1 (this);
884                 RegionLock rl2 (&other);
885
886                 old_length = _get_maximum_extent();
887         
888                 int itimes = (int) floor (times);
889                 jack_nframes_t pos = position;
890                 jack_nframes_t shift = other._get_maximum_extent();
891                 layer_t top_layer = regions.size();
892
893                 while (itimes--) {
894                         for (RegionList::iterator i = other.regions.begin(); i != other.regions.end(); ++i) {
895                                 Region *copy_of_region = createRegion (**i);
896
897                                 /* put these new regions on top of all existing ones, but preserve
898                                    the ordering they had in the original playlist.
899                                 */
900                                 
901                                 copy_of_region->set_layer (copy_of_region->layer() + top_layer);
902                                 add_region_internal (copy_of_region, copy_of_region->position() + pos);
903                         }
904                         pos += shift;
905                 }
906
907                 possibly_splice_unlocked ();
908
909                 /* XXX shall we handle fractional cases at some point? */
910
911                 if (old_length != _get_maximum_extent()) {
912                         notify_length_changed ();
913                 }
914
915                 
916         }
917
918         maybe_save_state (_("paste"));
919
920         return 0;
921 }
922
923
924 void
925 Playlist::duplicate (Region& region, jack_nframes_t position, float times)
926 {
927         times = fabs (times);
928
929         RegionLock rl (this);
930         int itimes = (int) floor (times);
931         jack_nframes_t pos = position;
932
933         while (itimes--) {
934                 Region *copy = createRegion (region);
935                 add_region_internal (copy, pos, true);
936                 pos += region.length();
937         }
938
939         if (floor (times) != times) {
940                 jack_nframes_t length = (jack_nframes_t) floor (region.length() * (times - floor (times)));
941                 string name;
942                 _session.region_name (name, region.name(), false);
943                 Region *sub = createRegion (region, 0, length, name, region.layer(), region.flags());
944                 add_region_internal (sub, pos, true);
945         }
946
947         maybe_save_state (_("duplicate"));
948 }
949
950 void
951 Playlist::split_region (Region& region, jack_nframes_t playlist_position)
952 {
953         RegionLock rl (this);
954
955         if (!region.covers (playlist_position)) {
956                 return;
957         }
958
959         if (region.position() == playlist_position ||
960             region.last_frame() == playlist_position) {
961                 return;
962         }
963
964         if (remove_region_internal (&region, true)) {
965                 return;
966         }
967
968         Region *left;
969         Region *right;
970         jack_nframes_t before;
971         jack_nframes_t after;
972         string before_name;
973         string after_name;
974
975         before = playlist_position - region.position();
976         after = region.length() - before;
977         
978         _session.region_name (before_name, region.name(), false);
979         left = createRegion (region, 0, before, before_name, region.layer(), Region::Flag (region.flags()|Region::LeftOfSplit));
980
981         _session.region_name (after_name, region.name(), false);
982         right = createRegion (region, before, after, after_name, region.layer(), Region::Flag (region.flags()|Region::RightOfSplit));
983         
984         add_region_internal (left, region.position(), true);
985         add_region_internal (right, region.position() + before);
986
987         maybe_save_state (_("split"));
988 }
989
990 void
991 Playlist::possibly_splice ()
992 {
993         if (_edit_mode == Splice) {
994                 splice_locked ();
995         }
996 }
997
998 void
999 Playlist::possibly_splice_unlocked ()
1000 {
1001         if (_edit_mode == Splice) {
1002                 splice_unlocked ();
1003         }
1004 }
1005
1006 void
1007 Playlist::splice_locked ()
1008 {
1009         {
1010                 RegionLock rl (this);
1011                 core_splice ();
1012         }
1013
1014         notify_length_changed ();
1015 }
1016
1017 void
1018 Playlist::splice_unlocked ()
1019 {
1020         core_splice ();
1021         notify_length_changed ();
1022 }
1023
1024 void
1025 Playlist::core_splice ()
1026 {
1027         _splicing = true;
1028         
1029         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1030                 
1031                 RegionList::iterator next;
1032                 
1033                 next = i;
1034                 ++next;
1035                 
1036                 if (next == regions.end()) {
1037                         break;
1038                 }
1039                 
1040                 (*next)->set_position ((*i)->last_frame() + 1, this);
1041         }
1042         
1043         _splicing = false;
1044 }
1045
1046 void
1047 Playlist::region_bounds_changed (Change what_changed, Region *region)
1048 {
1049         if (in_set_state || _splicing || _nudging) {
1050                 return;
1051         }
1052
1053         if (what_changed & ARDOUR::PositionChanged) {
1054
1055                 /* remove it from the list then add it back in
1056                    the right place again.
1057                 */
1058                 
1059                 RegionSortByPosition cmp;
1060
1061                 RegionList::iterator i = find (regions.begin(), regions.end(), region);
1062                 
1063                 if (i == regions.end()) {
1064                         warning << string_compose (_("%1: bounds changed received for region (%2)not in playlist"),
1065                                             _name, region->name())
1066                                 << endmsg;
1067                         return;
1068                 }
1069
1070                 regions.erase (i);
1071                 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp),
1072                                 region);
1073
1074         }
1075
1076         if (what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged)) {
1077         
1078                 if (holding_state ()) {
1079                         pending_bounds.push_back (region);
1080                 } else {
1081                         if (_session.get_layer_model() == Session::MoveAddHigher) {
1082                                 /* it moved or changed length, so change the timestamp */
1083                                 timestamp_layer_op (*region);
1084                         }
1085                         
1086                         possibly_splice ();
1087                         check_dependents (*region, false);
1088                         notify_length_changed ();
1089                         relayer ();
1090                 }
1091         }
1092 }
1093
1094 void
1095 Playlist::region_changed_proxy (Change what_changed, Region* region)
1096 {
1097         /* this makes a virtual call to the right kind of playlist ... */
1098
1099         region_changed (what_changed, region);
1100 }
1101
1102 bool
1103 Playlist::region_changed (Change what_changed, Region* region)
1104 {
1105         Change our_interests = Change (Region::MuteChanged|Region::LayerChanged|Region::OpacityChanged);
1106         bool save = false;
1107
1108         if (in_set_state || in_flush) {
1109                 return false;
1110         }
1111
1112         {
1113                 if (what_changed & BoundsChanged) {
1114                         region_bounds_changed (what_changed, region);
1115                         save = !(_splicing || _nudging);
1116                 }
1117                 
1118                 if ((what_changed & Region::MuteChanged) && 
1119                     !(what_changed &  Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) {
1120                         check_dependents (*region, false);
1121                 }
1122                 
1123                 if (what_changed & our_interests) {
1124                         save = true;
1125                 }
1126         }
1127
1128         return save;
1129 }
1130
1131 void
1132 Playlist::clear (bool with_delete, bool with_save)
1133 {
1134         RegionList::iterator i;
1135         RegionList tmp;
1136
1137         { 
1138                 RegionLock rl (this);
1139                 tmp = regions;
1140                 regions.clear ();
1141         }
1142         
1143         for (i = tmp.begin(); i != tmp.end(); ++i) {
1144                 notify_region_removed (*i);
1145                 if (with_delete) {
1146                         delete *i;
1147                 }
1148         }
1149
1150         if (with_save) {
1151                 maybe_save_state (_("clear"));
1152         }
1153 }
1154
1155 /***********************************************************************
1156  FINDING THINGS
1157  **********************************************************************/
1158
1159 Playlist::RegionList *
1160 Playlist::regions_at (jack_nframes_t frame)
1161
1162 {
1163         RegionLock rlock (this);
1164         return find_regions_at (frame);
1165 }       
1166
1167 Region *
1168 Playlist::top_region_at (jack_nframes_t frame)
1169
1170 {
1171         RegionLock rlock (this);
1172         RegionList *rlist = find_regions_at (frame);
1173         Region *region = 0;
1174
1175         if (rlist->size()) {
1176                 RegionSortByLayer cmp;
1177                 rlist->sort (cmp);
1178                 region = rlist->back();
1179         } 
1180
1181         delete rlist;
1182         return region;
1183 }       
1184
1185 Playlist::RegionList *
1186 Playlist::find_regions_at (jack_nframes_t frame)
1187 {
1188         RegionList *rlist = new RegionList;
1189
1190         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1191                 if ((*i)->covers (frame)) {
1192                         rlist->push_back (*i);
1193                 }
1194         }
1195
1196         return rlist;
1197 }
1198
1199 Playlist::RegionList *
1200 Playlist::regions_touched (jack_nframes_t start, jack_nframes_t end)
1201 {
1202         RegionLock rlock (this);
1203         RegionList *rlist = new RegionList;
1204
1205         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1206                 if ((*i)->coverage (start, end) != OverlapNone) {
1207                         rlist->push_back (*i);
1208                 }
1209         }
1210
1211         return rlist;
1212 }
1213
1214
1215 Region*
1216
1217 Playlist::find_next_region (jack_nframes_t frame, RegionPoint point, int dir)
1218 {
1219         RegionLock rlock (this);
1220         Region* ret = 0;
1221         jack_nframes_t closest = max_frames;
1222
1223         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1224
1225                 jack_nframes_t distance;
1226                 Region* r = (*i);
1227                 jack_nframes_t pos = 0;
1228
1229                 switch (point) {
1230                 case Start:
1231                         pos = r->first_frame ();
1232                         break;
1233                 case End:
1234                         pos = r->last_frame ();
1235                         break;
1236                 case SyncPoint:
1237                         pos = r->adjust_to_sync (r->first_frame());
1238                         break;
1239                 }
1240
1241                 switch (dir) {
1242                 case 1: /* forwards */
1243
1244                         if (pos > frame) {
1245                                 if ((distance = pos - frame) < closest) {
1246                                         closest = distance;
1247                                         ret = r;
1248                                 }
1249                         }
1250
1251                         break;
1252
1253                 default: /* backwards */
1254
1255                         if (pos < frame) {
1256                                 if ((distance = frame - pos) < closest) {
1257                                         closest = distance;
1258                                         ret = r;
1259                                 }
1260                         }
1261                         break;
1262                 }
1263         }
1264
1265         return ret;
1266 }
1267
1268 /***********************************************************************/
1269
1270
1271
1272 void
1273 Playlist::mark_session_dirty ()
1274 {
1275         if (!in_set_state && !holding_state ()) {
1276                 _session.set_dirty();
1277         }
1278 }
1279
1280 int
1281 Playlist::set_state (const XMLNode& node)
1282 {
1283         in_set_state = true;
1284
1285         XMLNode *child;
1286         XMLNodeList nlist;
1287         XMLNodeConstIterator niter;
1288         XMLPropertyList plist;
1289         XMLPropertyConstIterator piter;
1290         XMLProperty *prop;
1291         Region *region;
1292         string region_name;
1293
1294         clear (false, false);
1295
1296         if (node.name() != "Playlist") {
1297                 in_set_state = false;
1298                 return -1;
1299         }
1300
1301         plist = node.properties();
1302
1303         for (piter = plist.begin(); piter != plist.end(); ++piter) {
1304
1305                 prop = *piter;
1306                 
1307                 if (prop->name() == X_("name")) {
1308                         _name = prop->value();
1309                 } else if (prop->name() == X_("orig_diskstream_id")) {
1310                         sscanf (prop->value().c_str(), "%" PRIu64, &_orig_diskstream_id);
1311                 } else if (prop->name() == X_("frozen")) {
1312                         _frozen = (prop->value() == X_("yes"));
1313                 }
1314         }
1315
1316         nlist = node.children();
1317
1318         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1319
1320                 child = *niter;
1321                 
1322                 if (child->name() == "Region") {
1323
1324                         if ((region = createRegion (_session, *child, true)) == 0) {
1325                                 error << _("Playlist: cannot create region from state file") << endmsg;
1326                                 continue;
1327                         }
1328
1329                         add_region (*region, region->position(), 1.0, false);
1330
1331                 }                       
1332         }
1333
1334         /* update dependents, which was not done during add_region_internal 
1335            due to in_set_state being true 
1336         */
1337
1338         for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
1339                 check_dependents (**r, false);
1340         }
1341
1342         in_set_state = false;
1343
1344         return 0;
1345 }
1346
1347 XMLNode&
1348 Playlist::get_state()
1349 {
1350         return state(true);
1351 }
1352
1353 XMLNode&
1354 Playlist::get_template()
1355 {
1356         return state(false);
1357 }
1358
1359 XMLNode&
1360 Playlist::state (bool full_state)
1361 {
1362         XMLNode *node = new XMLNode (X_("Playlist"));
1363         char buf[64];
1364         
1365         node->add_property (X_("name"), _name);
1366
1367         snprintf (buf, sizeof(buf), "%" PRIu64, _orig_diskstream_id);
1368         node->add_property (X_("orig_diskstream_id"), buf);
1369         node->add_property (X_("frozen"), _frozen ? "yes" : "no");
1370
1371         if (full_state) {
1372                 RegionLock rlock (this, false);
1373
1374                 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1375                         node->add_child_nocopy ((*i)->get_state());
1376                 }
1377         }
1378
1379         if (_extra_xml) {
1380                 node->add_child_copy (*_extra_xml);
1381         }
1382
1383         return *node;
1384 }
1385
1386 bool
1387 Playlist::empty() const
1388 {
1389         return regions.empty();
1390 }
1391
1392 jack_nframes_t
1393 Playlist::get_maximum_extent () const
1394 {
1395         RegionLock rlock (const_cast<Playlist *>(this));
1396         return _get_maximum_extent ();
1397 }
1398
1399 jack_nframes_t
1400 Playlist::_get_maximum_extent () const
1401 {
1402         RegionList::const_iterator i;
1403         jack_nframes_t max_extent = 0;
1404         jack_nframes_t end = 0;
1405
1406         for (i = regions.begin(); i != regions.end(); ++i) {
1407                 if ((end = (*i)->position() + (*i)->length()) > max_extent) {
1408                         max_extent = end;
1409                 }
1410         }
1411
1412         return max_extent;
1413 }
1414
1415 string 
1416 Playlist::bump_name (string name, Session &session)
1417 {
1418         string newname = name;
1419
1420         do {
1421                 newname = Playlist::bump_name_once (newname);
1422         } while (session.playlist_by_name(newname)!=NULL);
1423
1424         return newname;
1425 }
1426
1427 string
1428 Playlist::bump_name_once (string name)
1429 {
1430         string::size_type period;
1431         string newname;
1432
1433         if ((period = name.find_last_of ('.')) == string::npos) {
1434                 newname = name;
1435                 newname += ".1";
1436         } else {
1437                 char buf[32];
1438                 int version;
1439                 
1440                 sscanf (name.substr (period+1).c_str(), "%d", &version);
1441                 snprintf (buf, sizeof(buf), "%d", version+1);
1442                 
1443                 newname = name.substr (0, period+1);
1444                 newname += buf;
1445         }
1446
1447         return newname;
1448 }
1449
1450 layer_t
1451 Playlist::top_layer() const
1452 {
1453         RegionLock rlock (const_cast<Playlist *> (this));
1454         layer_t top = 0;
1455
1456         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1457                 top = max (top, (*i)->layer());
1458         }
1459         return top;
1460 }
1461
1462 void
1463 Playlist::set_edit_mode (EditMode mode)
1464 {
1465         _edit_mode = mode;
1466 }
1467
1468 /********************
1469  * Region Layering
1470  ********************/
1471
1472 void
1473 Playlist::relayer ()
1474 {
1475         RegionList::iterator i;
1476         uint32_t layer = 0;
1477
1478         /* don't send multiple Modified notifications
1479            when multiple regions are relayered.
1480         */
1481
1482         freeze ();
1483
1484         if (_session.get_layer_model() == Session::MoveAddHigher || 
1485             _session.get_layer_model() == Session::AddHigher) {
1486
1487                 RegionSortByLastLayerOp cmp;
1488                 RegionList copy = regions;
1489
1490                 copy.sort (cmp);
1491
1492                 for (i = copy.begin(); i != copy.end(); ++i) {
1493                         (*i)->set_layer (layer++);
1494                 }
1495
1496         } else {
1497                 
1498                 /* Session::LaterHigher model */
1499
1500                 for (i = regions.begin(); i != regions.end(); ++i) {
1501                         (*i)->set_layer (layer++);
1502                 }
1503         }
1504
1505         /* sending Modified means that various kinds of layering
1506            models operate correctly at the GUI
1507            level. slightly inefficient, but only slightly.
1508
1509            We force a Modified signal here in case no layers actually
1510            changed.
1511         */
1512
1513         notify_modified ();
1514
1515         thaw ();
1516 }
1517
1518 /* XXX these layer functions are all deprecated */
1519
1520 void
1521 Playlist::raise_region (Region& region)
1522 {
1523         uint32_t rsz = regions.size();
1524         layer_t target = region.layer() + 1U;
1525
1526         if (target >= rsz) {
1527                 /* its already at the effective top */
1528                 return;
1529         }
1530
1531         move_region_to_layer (target, region, 1);
1532 }
1533
1534 void
1535 Playlist::lower_region (Region& region)
1536 {
1537         if (region.layer() == 0) {
1538                 /* its already at the bottom */
1539                 return;
1540         }
1541
1542         layer_t target = region.layer() - 1U;
1543
1544         move_region_to_layer (target, region, -1);
1545 }
1546
1547 void
1548 Playlist::raise_region_to_top (Region& region)
1549 {
1550         /* does nothing useful if layering mode is later=higher */
1551         if ((_session.get_layer_model() == Session::MoveAddHigher) ||
1552             (_session.get_layer_model() == Session::AddHigher)) {
1553                 timestamp_layer_op (region);
1554                 relayer ();
1555         }
1556 }
1557
1558 void
1559 Playlist::lower_region_to_bottom (Region& region)
1560 {
1561         /* does nothing useful if layering mode is later=higher */
1562         if ((_session.get_layer_model() == Session::MoveAddHigher) ||
1563             (_session.get_layer_model() == Session::AddHigher)) {
1564                 region.set_last_layer_op (0);
1565                 relayer ();
1566         }
1567 }
1568
1569 int
1570 Playlist::move_region_to_layer (layer_t target_layer, Region& region, int dir)
1571 {
1572         RegionList::iterator i;
1573         typedef pair<Region*,layer_t> LayerInfo;
1574         list<LayerInfo> layerinfo;
1575         layer_t dest;
1576
1577         {
1578                 RegionLock rlock (const_cast<Playlist *> (this));
1579                 
1580                 for (i = regions.begin(); i != regions.end(); ++i) {
1581                         
1582                         if (&region == *i) {
1583                                 continue;
1584                         }
1585
1586                         if (dir > 0) {
1587
1588                                 /* region is moving up, move all regions on intermediate layers
1589                                    down 1
1590                                 */
1591                                 
1592                                 if ((*i)->layer() > region.layer() && (*i)->layer() <= target_layer) {
1593                                         dest = (*i)->layer() - 1;
1594                                 } else {
1595                                         /* not affected */
1596                                         continue;
1597                                 }
1598                         } else {
1599
1600                                 /* region is moving down, move all regions on intermediate layers
1601                                    up 1
1602                                 */
1603
1604                                 if ((*i)->layer() < region.layer() && (*i)->layer() >= target_layer) {
1605                                         dest = (*i)->layer() + 1;
1606                                 } else {
1607                                         /* not affected */
1608                                         continue;
1609                                 }
1610                         }
1611
1612                         LayerInfo newpair;
1613                         
1614                         newpair.first = *i;
1615                         newpair.second = dest;
1616                         
1617                         layerinfo.push_back (newpair);
1618                 } 
1619         }
1620
1621         /* now reset the layers without holding the region lock */
1622
1623         for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
1624                 x->first->set_layer (x->second);
1625         }
1626
1627         region.set_layer (target_layer);
1628
1629         /* now check all dependents */
1630
1631         for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
1632                 check_dependents (*(x->first), false);
1633         }
1634         
1635         check_dependents (region, false);
1636         
1637         return 0;
1638 }
1639
1640 void
1641 Playlist::nudge_after (jack_nframes_t start, jack_nframes_t distance, bool forwards)
1642 {
1643         RegionList::iterator i;
1644         jack_nframes_t new_pos;
1645         bool moved = false;
1646
1647         _nudging = true;
1648
1649         {
1650                 RegionLock rlock (const_cast<Playlist *> (this));
1651                 
1652                 for (i = regions.begin(); i != regions.end(); ++i) {
1653
1654                         if ((*i)->position() >= start) {
1655
1656                                 if (forwards) {
1657
1658                                         if ((*i)->last_frame() > max_frames - distance) {
1659                                                 new_pos = max_frames - (*i)->length();
1660                                         } else {
1661                                                 new_pos = (*i)->position() + distance;
1662                                         }
1663                                         
1664                                 } else {
1665                                         
1666                                         if ((*i)->position() > distance) {
1667                                                 new_pos = (*i)->position() - distance;
1668                                         } else {
1669                                                 new_pos = 0;
1670                                         }
1671                                 }
1672
1673                                 (*i)->set_position (new_pos, this);
1674                                 moved = true;
1675                         }
1676                 }
1677         }
1678
1679         if (moved) {
1680                 _nudging = false;
1681                 maybe_save_state (_("nudged"));
1682                 notify_length_changed ();
1683         }
1684
1685 }
1686
1687 Region*
1688 Playlist::find_region (id_t id) const
1689 {
1690         RegionLock rlock (const_cast<Playlist*> (this));
1691         RegionList::const_iterator i;
1692         
1693         for (i = regions.begin(); i != regions.end(); ++i) {
1694                 if ((*i)->id() == id) {
1695                         return (*i);
1696                 }
1697         }
1698
1699         return 0;
1700 }
1701         
1702 void
1703 Playlist::save_state (std::string why)
1704 {
1705         if (!in_set_state) {
1706                 StateManager::save_state (why);
1707         }
1708 }
1709
1710 void
1711 Playlist::dump () const
1712 {
1713         Region *r;
1714
1715         cerr << "Playlist \"" << _name << "\" " << endl
1716              << regions.size() << " regions "
1717              << endl;
1718
1719         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1720                 r = *i;
1721                 cerr << "  " << r->name() << " [" 
1722                      << r->start() << "+" << r->length() 
1723                      << "] at " 
1724                      << r->position()
1725                      << " on layer "
1726                      << r->layer ()
1727                      << endl;
1728         }
1729 }
1730
1731 void
1732 Playlist::set_frozen (bool yn)
1733 {
1734         _frozen = yn;
1735 }
1736
1737 void
1738 Playlist::timestamp_layer_op (Region& region)
1739 {
1740 //      struct timeval tv;
1741 //      gettimeofday (&tv, 0);
1742         region.set_last_layer_op (++layer_op_counter);
1743 }
1744
1745 void
1746 Playlist::maybe_save_state (string why)
1747 {
1748         if (holding_state ()) {
1749                 save_on_thaw = true;
1750                 last_save_reason = why;
1751         } else {
1752                 save_state (why);
1753         }
1754 }