Differentiate between pitch-shift (for audio) and transpose (for MIDI). Fixes #3940.
[ardour.git] / gtk2_ardour / editor_ops.cc
1 /*
2     Copyright (C) 2000-2004 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 */
19
20 /* Note: public Editor methods are documented in public_editor.h */
21
22 #include <unistd.h>
23
24 #include <cstdlib>
25 #include <cmath>
26 #include <string>
27 #include <map>
28 #include <set>
29
30 #include "pbd/error.h"
31 #include "pbd/basename.h"
32 #include "pbd/pthread_utils.h"
33 #include "pbd/memento_command.h"
34 #include "pbd/whitespace.h"
35 #include "pbd/stateful_diff_command.h"
36
37 #include <gtkmm2ext/utils.h>
38 #include <gtkmm2ext/choice.h>
39 #include <gtkmm2ext/popup.h>
40
41 #include "ardour/audioengine.h"
42 #include "ardour/session.h"
43 #include "ardour/audioplaylist.h"
44 #include "ardour/audioregion.h"
45 #include "ardour/audio_diskstream.h"
46 #include "ardour/utils.h"
47 #include "ardour/location.h"
48 #include "ardour/audio_track.h"
49 #include "ardour/audioplaylist.h"
50 #include "ardour/region_factory.h"
51 #include "ardour/playlist_factory.h"
52 #include "ardour/reverse.h"
53 #include "ardour/transient_detector.h"
54 #include "ardour/dB.h"
55 #include "ardour/quantize.h"
56 #include "ardour/strip_silence.h"
57 #include "ardour/route_group.h"
58 #include "ardour/operations.h"
59
60 #include "ardour_ui.h"
61 #include "debug.h"
62 #include "editor.h"
63 #include "time_axis_view.h"
64 #include "route_time_axis.h"
65 #include "audio_time_axis.h"
66 #include "automation_time_axis.h"
67 #include "streamview.h"
68 #include "audio_streamview.h"
69 #include "audio_region_view.h"
70 #include "midi_region_view.h"
71 #include "rgb_macros.h"
72 #include "selection_templates.h"
73 #include "selection.h"
74 #include "editing.h"
75 #include "gtk-custom-hruler.h"
76 #include "gui_thread.h"
77 #include "keyboard.h"
78 #include "utils.h"
79 #include "editor_drag.h"
80 #include "strip_silence_dialog.h"
81 #include "editor_routes.h"
82 #include "editor_regions.h"
83 #include "quantize_dialog.h"
84 #include "interthread_progress_window.h"
85 #include "insert_time_dialog.h"
86 #include "normalize_dialog.h"
87 #include "editor_cursors.h"
88 #include "mouse_cursors.h"
89 #include "patch_change_dialog.h"
90 #include "transpose_dialog.h"
91
92 #include "i18n.h"
93
94 using namespace std;
95 using namespace ARDOUR;
96 using namespace PBD;
97 using namespace Gtk;
98 using namespace Gtkmm2ext;
99 using namespace Editing;
100 using Gtkmm2ext::Keyboard;
101
102 /***********************************************************************
103   Editor operations
104  ***********************************************************************/
105
106 void
107 Editor::undo (uint32_t n)
108 {
109         if (_session) {
110                 _session->undo (n);
111         }
112 }
113
114 void
115 Editor::redo (uint32_t n)
116 {
117         if (_session) {
118                 _session->redo (n);
119         }
120 }
121
122 void
123 Editor::split_regions_at (framepos_t where, RegionSelection& regions)
124 {
125         bool frozen = false;
126
127         list <boost::shared_ptr<Playlist > > used_playlists;
128
129         if (regions.empty()) {
130                 return;
131         }
132
133         begin_reversible_command (_("split"));
134
135         // if splitting a single region, and snap-to is using
136         // region boundaries, don't pay attention to them
137
138         if (regions.size() == 1) {
139                 switch (_snap_type) {
140                 case SnapToRegionStart:
141                 case SnapToRegionSync:
142                 case SnapToRegionEnd:
143                         break;
144                 default:
145                         snap_to (where);
146                 }
147         } else {
148                 snap_to (where);
149                 
150                 frozen = true;
151                 EditorFreeze(); /* Emit Signal */
152         }
153
154         for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
155
156                 RegionSelection::iterator tmp;
157
158                 /* XXX this test needs to be more complicated, to make sure we really
159                    have something to split.
160                 */
161
162                 if (!(*a)->region()->covers (where)) {
163                         ++a;
164                         continue;
165                 }
166
167                 tmp = a;
168                 ++tmp;
169
170                 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
171
172                 if (!pl) {
173                         a = tmp;
174                         continue;
175                 }
176
177                 if (!pl->frozen()) {
178                         /* we haven't seen this playlist before */
179
180                         /* remember used playlists so we can thaw them later */
181                         used_playlists.push_back(pl);
182                         pl->freeze();
183                 }
184
185                 if (pl) {
186                         pl->clear_changes ();
187                         pl->split_region ((*a)->region(), where);
188                         _session->add_command (new StatefulDiffCommand (pl));
189                 }
190
191                 a = tmp;
192         }
193
194         while (used_playlists.size() > 0) {
195                 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
196                 (*i)->thaw();
197                 used_playlists.pop_front();
198         }
199
200         commit_reversible_command ();
201         
202         if (frozen){
203                 EditorThaw(); /* Emit Signal */
204         }
205 }
206
207 boost::shared_ptr<Region>
208 Editor::select_region_for_operation (int /*dir*/, TimeAxisView **tv)
209 {
210         RegionView* rv;
211         boost::shared_ptr<Region> region;
212         framepos_t start = 0;
213
214         if (selection->time.start () == selection->time.end_frame ()) {
215
216                 /* no current selection-> is there a selected regionview? */
217
218                 if (selection->regions.empty()) {
219                         return region;
220                 }
221
222         }
223
224         if (!selection->regions.empty()) {
225
226                 rv = *(selection->regions.begin());
227                 (*tv) = &rv->get_time_axis_view();
228                 region = rv->region();
229
230         } else if (!selection->tracks.empty()) {
231
232                 (*tv) = selection->tracks.front();
233
234                 RouteTimeAxisView* rtv;
235
236                 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*tv)) != 0) {
237                         boost::shared_ptr<Playlist> pl;
238
239                         if ((pl = rtv->playlist()) == 0) {
240                                 return region;
241                         }
242
243                         region = pl->top_region_at (start);
244                 }
245         }
246
247         return region;
248 }
249
250 void
251 Editor::extend_selection_to_end_of_region (bool next)
252 {
253         TimeAxisView *tv;
254         boost::shared_ptr<Region> region;
255         framepos_t start;
256
257         if ((region = select_region_for_operation (next ? 1 : 0, &tv)) == 0) {
258                 return;
259         }
260
261         if (region && selection->time.start () == selection->time.end_frame ()) {
262                 start = region->position();
263         } else {
264                 start = selection->time.start ();
265         }
266
267         begin_reversible_command (_("extend selection"));
268         selection->set (start, region->position() + region->length());
269         commit_reversible_command ();
270 }
271
272 void
273 Editor::extend_selection_to_start_of_region (bool previous)
274 {
275         TimeAxisView *tv;
276         boost::shared_ptr<Region> region;
277         framepos_t end;
278
279         if ((region = select_region_for_operation (previous ? -1 : 0, &tv)) == 0) {
280                 return;
281         }
282
283         if (region && selection->time.start () == selection->time.end_frame ()) {
284                 end = region->position() + region->length();
285         } else {
286                 end = selection->time.end_frame ();
287         }
288
289         /* Try to leave the selection with the same route if possible */
290
291         begin_reversible_command (_("extend selection"));
292         selection->set (region->position(), end);
293         commit_reversible_command ();
294 }
295
296 bool
297 Editor::nudge_forward_release (GdkEventButton* ev)
298 {
299         if (ev->state & Keyboard::PrimaryModifier) {
300                 nudge_forward (false, true);
301         } else {
302                 nudge_forward (false, false);
303         }
304         return false;
305 }
306
307 bool
308 Editor::nudge_backward_release (GdkEventButton* ev)
309 {
310         if (ev->state & Keyboard::PrimaryModifier) {
311                 nudge_backward (false, true);
312         } else {
313                 nudge_backward (false, false);
314         }
315         return false;
316 }
317
318
319 void
320 Editor::nudge_forward (bool next, bool force_playhead)
321 {
322         framepos_t distance;
323         framepos_t next_distance;
324
325         if (!_session) {
326                 return;
327         }
328
329         RegionSelection rs = get_regions_from_selection_and_entered ();
330
331         if (!force_playhead && !rs.empty()) {
332
333                 begin_reversible_command (_("nudge regions forward"));
334
335                 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
336                         boost::shared_ptr<Region> r ((*i)->region());
337
338                         distance = get_nudge_distance (r->position(), next_distance);
339
340                         if (next) {
341                                 distance = next_distance;
342                         }
343
344                         r->clear_changes ();
345                         r->set_position (r->position() + distance, this);
346                         _session->add_command (new StatefulDiffCommand (r));
347                 }
348
349                 commit_reversible_command ();
350
351
352         } else if (!force_playhead && !selection->markers.empty()) {
353
354                 bool is_start;
355
356                 begin_reversible_command (_("nudge location forward"));
357
358                 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
359
360                         Location* loc = find_location_from_marker ((*i), is_start);
361
362                         if (loc) {
363
364                                 XMLNode& before (loc->get_state());
365
366                                 if (is_start) {
367                                         distance = get_nudge_distance (loc->start(), next_distance);
368                                         if (next) {
369                                                 distance = next_distance;
370                                         }
371                                         if (max_framepos - distance > loc->start() + loc->length()) {
372                                                 loc->set_start (loc->start() + distance);
373                                         } else {
374                                                 loc->set_start (max_framepos - loc->length());
375                                         }
376                                 } else {
377                                         distance = get_nudge_distance (loc->end(), next_distance);
378                                         if (next) {
379                                                 distance = next_distance;
380                                         }
381                                         if (max_framepos - distance > loc->end()) {
382                                                 loc->set_end (loc->end() + distance);
383                                         } else {
384                                                 loc->set_end (max_framepos);
385                                         }
386                                 }
387                                 XMLNode& after (loc->get_state());
388                                 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
389                         }
390                 }
391
392                 commit_reversible_command ();
393
394         } else {
395                 distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
396                 _session->request_locate (playhead_cursor->current_frame + distance);
397         }
398 }
399
400 void
401 Editor::nudge_backward (bool next, bool force_playhead)
402 {
403         framepos_t distance;
404         framepos_t next_distance;
405
406         if (!_session) {
407                 return;
408         }
409
410         RegionSelection rs = get_regions_from_selection_and_entered ();
411
412         if (!force_playhead && !rs.empty()) {
413
414                 begin_reversible_command (_("nudge regions backward"));
415
416                 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
417                         boost::shared_ptr<Region> r ((*i)->region());
418
419                         distance = get_nudge_distance (r->position(), next_distance);
420
421                         if (next) {
422                                 distance = next_distance;
423                         }
424                         
425                         r->clear_changes ();
426
427                         if (r->position() > distance) {
428                                 r->set_position (r->position() - distance, this);
429                         } else {
430                                 r->set_position (0, this);
431                         }
432                         _session->add_command (new StatefulDiffCommand (r));
433                 }
434
435                 commit_reversible_command ();
436
437         } else if (!force_playhead && !selection->markers.empty()) {
438
439                 bool is_start;
440
441                 begin_reversible_command (_("nudge location forward"));
442
443                 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
444
445                         Location* loc = find_location_from_marker ((*i), is_start);
446
447                         if (loc) {
448
449                                 XMLNode& before (loc->get_state());
450
451                                 if (is_start) {
452                                         distance = get_nudge_distance (loc->start(), next_distance);
453                                         if (next) {
454                                                 distance = next_distance;
455                                         }
456                                         if (distance < loc->start()) {
457                                                 loc->set_start (loc->start() - distance);
458                                         } else {
459                                                 loc->set_start (0);
460                                         }
461                                 } else {
462                                         distance = get_nudge_distance (loc->end(), next_distance);
463
464                                         if (next) {
465                                                 distance = next_distance;
466                                         }
467
468                                         if (distance < loc->end() - loc->length()) {
469                                                 loc->set_end (loc->end() - distance);
470                                         } else {
471                                                 loc->set_end (loc->length());
472                                         }
473                                 }
474
475                                 XMLNode& after (loc->get_state());
476                                 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
477                         }
478                 }
479
480                 commit_reversible_command ();
481
482         } else {
483
484                 distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
485
486                 if (playhead_cursor->current_frame > distance) {
487                         _session->request_locate (playhead_cursor->current_frame - distance);
488                 } else {
489                         _session->goto_start();
490                 }
491         }
492 }
493
494 void
495 Editor::nudge_forward_capture_offset ()
496 {
497         RegionSelection rs = get_regions_from_selection_and_entered ();
498         
499         if (!_session || rs.empty()) {
500                 return;
501         }
502
503         begin_reversible_command (_("nudge forward"));
504         
505         framepos_t const distance = _session->worst_output_latency();
506         
507         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
508                 boost::shared_ptr<Region> r ((*i)->region());
509                 
510                 r->clear_changes ();
511                 r->set_position (r->position() + distance, this);
512                 _session->add_command(new StatefulDiffCommand (r));
513         }
514         
515         commit_reversible_command ();
516 }
517
518 void
519 Editor::nudge_backward_capture_offset ()
520 {
521         RegionSelection rs = get_regions_from_selection_and_entered ();
522
523         if (!_session || rs.empty()) {
524                 return;
525         }
526
527         begin_reversible_command (_("nudge forward"));
528         
529         framepos_t const distance = _session->worst_output_latency();
530
531         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
532                 boost::shared_ptr<Region> r ((*i)->region());
533                 
534                 r->clear_changes ();
535                 
536                 if (r->position() > distance) {
537                         r->set_position (r->position() - distance, this);
538                 } else {
539                         r->set_position (0, this);
540                 }
541                 _session->add_command(new StatefulDiffCommand (r));
542         }
543         
544         commit_reversible_command ();
545 }
546
547 /* DISPLAY MOTION */
548
549 void
550 Editor::move_to_start ()
551 {
552         _session->goto_start ();
553 }
554
555 void
556 Editor::move_to_end ()
557 {
558
559         _session->request_locate (_session->current_end_frame());
560 }
561
562 void
563 Editor::build_region_boundary_cache ()
564 {
565         framepos_t pos = 0;
566         vector<RegionPoint> interesting_points;
567         boost::shared_ptr<Region> r;
568         TrackViewList tracks;
569         bool at_end = false;
570
571         region_boundary_cache.clear ();
572
573         if (_session == 0) {
574                 return;
575         }
576
577         switch (_snap_type) {
578         case SnapToRegionStart:
579                 interesting_points.push_back (Start);
580                 break;
581         case SnapToRegionEnd:
582                 interesting_points.push_back (End);
583                 break;
584         case SnapToRegionSync:
585                 interesting_points.push_back (SyncPoint);
586                 break;
587         case SnapToRegionBoundary:
588                 interesting_points.push_back (Start);
589                 interesting_points.push_back (End);
590                 break;
591         default:
592                 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
593                 /*NOTREACHED*/
594                 return;
595         }
596
597         TimeAxisView *ontrack = 0;
598         TrackViewList tlist;
599
600         if (!selection->tracks.empty()) {
601                 tlist = selection->tracks;
602         } else {
603                 tlist = track_views;
604         }
605
606         while (pos < _session->current_end_frame() && !at_end) {
607
608                 framepos_t rpos;
609                 framepos_t lpos = max_framepos;
610
611                 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
612
613                         if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
614                                 if (*p == interesting_points.back()) {
615                                         at_end = true;
616                                 }
617                                 /* move to next point type */
618                                 continue;
619                         }
620
621                         switch (*p) {
622                         case Start:
623                                 rpos = r->first_frame();
624                                 break;
625
626                         case End:
627                                 rpos = r->last_frame();
628                                 break;
629
630                         case SyncPoint:
631                                 rpos = r->sync_position ();
632                                 break;
633
634                         default:
635                                 break;
636                         }
637
638                         float speed = 1.0f;
639                         RouteTimeAxisView *rtav;
640
641                         if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
642                                 if (rtav->track() != 0) {
643                                         speed = rtav->track()->speed();
644                                 }
645                         }
646
647                         rpos = track_frame_to_session_frame (rpos, speed);
648
649                         if (rpos < lpos) {
650                                 lpos = rpos;
651                         }
652
653                         /* prevent duplicates, but we don't use set<> because we want to be able
654                            to sort later.
655                         */
656
657                         vector<framepos_t>::iterator ri;
658
659                         for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
660                                 if (*ri == rpos) {
661                                         break;
662                                 }
663                         }
664
665                         if (ri == region_boundary_cache.end()) {
666                                 region_boundary_cache.push_back (rpos);
667                         }
668                 }
669
670                 pos = lpos + 1;
671         }
672
673         /* finally sort to be sure that the order is correct */
674
675         sort (region_boundary_cache.begin(), region_boundary_cache.end());
676 }
677
678 boost::shared_ptr<Region>
679 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
680 {
681         TrackViewList::iterator i;
682         framepos_t closest = max_framepos;
683         boost::shared_ptr<Region> ret;
684         framepos_t rpos = 0;
685
686         float track_speed;
687         framepos_t track_frame;
688         RouteTimeAxisView *rtav;
689
690         for (i = tracks.begin(); i != tracks.end(); ++i) {
691
692                 framecnt_t distance;
693                 boost::shared_ptr<Region> r;
694
695                 track_speed = 1.0f;
696                 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
697                         if (rtav->track()!=0)
698                                 track_speed = rtav->track()->speed();
699                 }
700
701                 track_frame = session_frame_to_track_frame(frame, track_speed);
702
703                 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
704                         continue;
705                 }
706
707                 switch (point) {
708                 case Start:
709                         rpos = r->first_frame ();
710                         break;
711
712                 case End:
713                         rpos = r->last_frame ();
714                         break;
715
716                 case SyncPoint:
717                         rpos = r->sync_position ();
718                         break;
719                 }
720
721                 // rpos is a "track frame", converting it to "_session frame"
722                 rpos = track_frame_to_session_frame(rpos, track_speed);
723
724                 if (rpos > frame) {
725                         distance = rpos - frame;
726                 } else {
727                         distance = frame - rpos;
728                 }
729
730                 if (distance < closest) {
731                         closest = distance;
732                         if (ontrack != 0)
733                                 *ontrack = (*i);
734                         ret = r;
735                 }
736         }
737
738         return ret;
739 }
740
741 framepos_t
742 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
743 {
744         framecnt_t distance = max_framepos;
745         framepos_t current_nearest = -1;
746
747         for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
748                 framepos_t contender;
749                 framecnt_t d;
750                 
751                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
752
753                 if (!rtv) {
754                         continue;
755                 }
756
757                 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
758                         continue;
759                 }
760
761                 d = ::llabs (pos - contender);
762
763                 if (d < distance) {
764                         current_nearest = contender;
765                         distance = d;
766                 }
767         }
768
769         return current_nearest;
770 }
771
772 framepos_t
773 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
774 {
775         framepos_t target;
776         TrackViewList tvl;
777
778         if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
779
780                 if (!selection->tracks.empty()) {
781
782                         target = find_next_region_boundary (pos, dir, selection->tracks);
783
784                 } else {
785
786                         if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
787                                 get_onscreen_tracks (tvl);
788                                 target = find_next_region_boundary (pos, dir, tvl);
789                         } else {
790                                 target = find_next_region_boundary (pos, dir, track_views);
791                         }
792                 }
793
794         } else {
795
796                 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
797                         get_onscreen_tracks (tvl);
798                         target = find_next_region_boundary (pos, dir, tvl);
799                 } else {
800                         target = find_next_region_boundary (pos, dir, track_views);
801                 }
802         }
803
804         return target;
805 }
806
807 void
808 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
809 {
810         framepos_t pos = playhead_cursor->current_frame;
811         framepos_t target;
812
813         if (!_session) {
814                 return;
815         }
816
817         // so we don't find the current region again..
818         if (dir > 0 || pos > 0) {
819                 pos += dir;
820         }
821
822         if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
823                 return;
824         }
825
826         _session->request_locate (target);
827 }
828
829 void
830 Editor::cursor_to_next_region_boundary (bool with_selection)
831 {
832         cursor_to_region_boundary (with_selection, 1);
833 }
834
835 void
836 Editor::cursor_to_previous_region_boundary (bool with_selection)
837 {
838         cursor_to_region_boundary (with_selection, -1);
839 }
840
841 void
842 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
843 {
844         boost::shared_ptr<Region> r;
845         framepos_t pos = cursor->current_frame;
846
847         if (!_session) {
848                 return;
849         }
850
851         TimeAxisView *ontrack = 0;
852
853         // so we don't find the current region again..
854         if (dir>0 || pos>0)
855                 pos+=dir;
856
857         if (!selection->tracks.empty()) {
858
859                 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
860
861         } else if (clicked_axisview) {
862
863                 TrackViewList t;
864                 t.push_back (clicked_axisview);
865
866                 r = find_next_region (pos, point, dir, t, &ontrack);
867
868         } else {
869
870                 r = find_next_region (pos, point, dir, track_views, &ontrack);
871         }
872
873         if (r == 0) {
874                 return;
875         }
876
877         switch (point) {
878         case Start:
879                 pos = r->first_frame ();
880                 break;
881
882         case End:
883                 pos = r->last_frame ();
884                 break;
885
886         case SyncPoint:
887                 pos = r->sync_position ();
888                 break;
889         }
890
891         float speed = 1.0f;
892         RouteTimeAxisView *rtav;
893
894         if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
895                 if (rtav->track() != 0) {
896                         speed = rtav->track()->speed();
897                 }
898         }
899
900         pos = track_frame_to_session_frame(pos, speed);
901
902         if (cursor == playhead_cursor) {
903                 _session->request_locate (pos);
904         } else {
905                 cursor->set_position (pos);
906         }
907 }
908
909 void
910 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
911 {
912         cursor_to_region_point (cursor, point, 1);
913 }
914
915 void
916 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
917 {
918         cursor_to_region_point (cursor, point, -1);
919 }
920
921 void
922 Editor::cursor_to_selection_start (EditorCursor *cursor)
923 {
924         framepos_t pos = 0;
925
926         switch (mouse_mode) {
927         case MouseObject:
928                 if (!selection->regions.empty()) {
929                         pos = selection->regions.start();
930                 }
931                 break;
932
933         case MouseRange:
934                 if (!selection->time.empty()) {
935                         pos = selection->time.start ();
936                 }
937                 break;
938
939         default:
940                 return;
941         }
942
943         if (cursor == playhead_cursor) {
944                 _session->request_locate (pos);
945         } else {
946                 cursor->set_position (pos);
947         }
948 }
949
950 void
951 Editor::cursor_to_selection_end (EditorCursor *cursor)
952 {
953         framepos_t pos = 0;
954
955         switch (mouse_mode) {
956         case MouseObject:
957                 if (!selection->regions.empty()) {
958                         pos = selection->regions.end_frame();
959                 }
960                 break;
961
962         case MouseRange:
963                 if (!selection->time.empty()) {
964                         pos = selection->time.end_frame ();
965                 }
966                 break;
967
968         default:
969                 return;
970         }
971
972         if (cursor == playhead_cursor) {
973                 _session->request_locate (pos);
974         } else {
975                 cursor->set_position (pos);
976         }
977 }
978
979 void
980 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
981 {
982         framepos_t target;
983         Location* loc;
984         bool ignored;
985
986         if (!_session) {
987                 return;
988         }
989
990         if (selection->markers.empty()) {
991                 framepos_t mouse;
992                 bool ignored;
993
994                 if (!mouse_frame (mouse, ignored)) {
995                         return;
996                 }
997
998                 add_location_mark (mouse);
999         }
1000
1001         if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1002                 return;
1003         }
1004
1005         framepos_t pos = loc->start();
1006
1007         // so we don't find the current region again..
1008         if (dir > 0 || pos > 0) {
1009                 pos += dir;
1010         }
1011
1012         if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1013                 return;
1014         }
1015
1016         loc->move_to (target);
1017 }
1018
1019 void
1020 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1021 {
1022         selected_marker_to_region_boundary (with_selection, 1);
1023 }
1024
1025 void
1026 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1027 {
1028         selected_marker_to_region_boundary (with_selection, -1);
1029 }
1030
1031 void
1032 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1033 {
1034         boost::shared_ptr<Region> r;
1035         framepos_t pos;
1036         Location* loc;
1037         bool ignored;
1038
1039         if (!_session || selection->markers.empty()) {
1040                 return;
1041         }
1042
1043         if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1044                 return;
1045         }
1046
1047         TimeAxisView *ontrack = 0;
1048
1049         pos = loc->start();
1050
1051         // so we don't find the current region again..
1052         if (dir>0 || pos>0)
1053                 pos+=dir;
1054
1055         if (!selection->tracks.empty()) {
1056
1057                 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1058
1059         } else {
1060
1061                 r = find_next_region (pos, point, dir, track_views, &ontrack);
1062         }
1063
1064         if (r == 0) {
1065                 return;
1066         }
1067
1068         switch (point) {
1069         case Start:
1070                 pos = r->first_frame ();
1071                 break;
1072
1073         case End:
1074                 pos = r->last_frame ();
1075                 break;
1076
1077         case SyncPoint:
1078                 pos = r->adjust_to_sync (r->first_frame());
1079                 break;
1080         }
1081
1082         float speed = 1.0f;
1083         RouteTimeAxisView *rtav;
1084
1085         if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1086                 if (rtav->track() != 0) {
1087                         speed = rtav->track()->speed();
1088                 }
1089         }
1090
1091         pos = track_frame_to_session_frame(pos, speed);
1092
1093         loc->move_to (pos);
1094 }
1095
1096 void
1097 Editor::selected_marker_to_next_region_point (RegionPoint point)
1098 {
1099         selected_marker_to_region_point (point, 1);
1100 }
1101
1102 void
1103 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1104 {
1105         selected_marker_to_region_point (point, -1);
1106 }
1107
1108 void
1109 Editor::selected_marker_to_selection_start ()
1110 {
1111         framepos_t pos = 0;
1112         Location* loc;
1113         bool ignored;
1114
1115         if (!_session || selection->markers.empty()) {
1116                 return;
1117         }
1118
1119         if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1120                 return;
1121         }
1122
1123         switch (mouse_mode) {
1124         case MouseObject:
1125                 if (!selection->regions.empty()) {
1126                         pos = selection->regions.start();
1127                 }
1128                 break;
1129
1130         case MouseRange:
1131                 if (!selection->time.empty()) {
1132                         pos = selection->time.start ();
1133                 }
1134                 break;
1135
1136         default:
1137                 return;
1138         }
1139
1140         loc->move_to (pos);
1141 }
1142
1143 void
1144 Editor::selected_marker_to_selection_end ()
1145 {
1146         framepos_t pos = 0;
1147         Location* loc;
1148         bool ignored;
1149
1150         if (!_session || selection->markers.empty()) {
1151                 return;
1152         }
1153
1154         if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1155                 return;
1156         }
1157
1158         switch (mouse_mode) {
1159         case MouseObject:
1160                 if (!selection->regions.empty()) {
1161                         pos = selection->regions.end_frame();
1162                 }
1163                 break;
1164
1165         case MouseRange:
1166                 if (!selection->time.empty()) {
1167                         pos = selection->time.end_frame ();
1168                 }
1169                 break;
1170
1171         default:
1172                 return;
1173         }
1174
1175         loc->move_to (pos);
1176 }
1177
1178 void
1179 Editor::scroll_playhead (bool forward)
1180 {
1181         framepos_t pos = playhead_cursor->current_frame;
1182         framecnt_t delta = (framecnt_t) floor (current_page_frames() / 0.8);
1183
1184         if (forward) {
1185                 if (pos == max_framepos) {
1186                         return;
1187                 }
1188
1189                 if (pos < max_framepos - delta) {
1190                         pos += delta ;
1191                 } else {
1192                         pos = max_framepos;
1193                 }
1194
1195         } else {
1196
1197                 if (pos == 0) {
1198                         return;
1199                 }
1200
1201                 if (pos > delta) {
1202                         pos -= delta;
1203                 } else {
1204                         pos = 0;
1205                 }
1206         }
1207
1208         _session->request_locate (pos);
1209 }
1210
1211 void
1212 Editor::cursor_align (bool playhead_to_edit)
1213 {
1214         if (!_session) {
1215                 return;
1216         }
1217
1218         if (playhead_to_edit) {
1219
1220                 if (selection->markers.empty()) {
1221                         return;
1222                 }
1223
1224                 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1225
1226         } else {
1227                 /* move selected markers to playhead */
1228
1229                 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1230                         bool ignored;
1231
1232                         Location* loc = find_location_from_marker (*i, ignored);
1233
1234                         if (loc->is_mark()) {
1235                                 loc->set_start (playhead_cursor->current_frame);
1236                         } else {
1237                                 loc->set (playhead_cursor->current_frame,
1238                                           playhead_cursor->current_frame + loc->length());
1239                         }
1240                 }
1241         }
1242 }
1243
1244 void
1245 Editor::scroll_backward (float pages)
1246 {
1247         framepos_t const one_page = (framepos_t) rint (_canvas_width * frames_per_unit);
1248         framepos_t const cnt = (framepos_t) floor (pages * one_page);
1249
1250         framepos_t frame;
1251         if (leftmost_frame < cnt) {
1252                 frame = 0;
1253         } else {
1254                 frame = leftmost_frame - cnt;
1255         }
1256
1257         reset_x_origin (frame);
1258 }
1259
1260 void
1261 Editor::scroll_forward (float pages)
1262 {
1263         framepos_t const one_page = (framepos_t) rint (_canvas_width * frames_per_unit);
1264         framepos_t const cnt = (framepos_t) floor (pages * one_page);
1265
1266         framepos_t frame;
1267         if (max_framepos - cnt < leftmost_frame) {
1268                 frame = max_framepos - cnt;
1269         } else {
1270                 frame = leftmost_frame + cnt;
1271         }
1272
1273         reset_x_origin (frame);
1274 }
1275
1276 void
1277 Editor::scroll_tracks_down ()
1278 {
1279         double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1280         if (vert_value > vertical_adjustment.get_upper() - _canvas_height) {
1281                 vert_value = vertical_adjustment.get_upper() - _canvas_height;
1282         }
1283         
1284         vertical_adjustment.set_value (vert_value);
1285 }
1286
1287 void
1288 Editor::scroll_tracks_up ()
1289 {
1290         vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1291 }
1292
1293 void
1294 Editor::scroll_tracks_down_line ()
1295 {
1296         double vert_value = vertical_adjustment.get_value() + 60;
1297
1298         if (vert_value > vertical_adjustment.get_upper() - _canvas_height) {
1299                 vert_value = vertical_adjustment.get_upper() - _canvas_height;
1300         }
1301         
1302         vertical_adjustment.set_value (vert_value);
1303 }
1304
1305 void
1306 Editor::scroll_tracks_up_line ()
1307 {
1308         reset_y_origin (vertical_adjustment.get_value() - 60);
1309 }
1310
1311 /* ZOOM */
1312
1313 void
1314 Editor::tav_zoom_step (bool coarser)
1315 {
1316         ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1317
1318         _routes->suspend_redisplay ();
1319
1320         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1321                 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1322                         tv->step_height (coarser);
1323         }
1324
1325         _routes->resume_redisplay ();
1326 }
1327
1328 void
1329 Editor::temporal_zoom_step (bool coarser)
1330 {
1331         ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1332
1333         double nfpu;
1334
1335         nfpu = frames_per_unit;
1336
1337         if (coarser) {
1338                 nfpu *= 1.61803399;
1339         } else {
1340                 nfpu = max(1.0,(nfpu/1.61803399));
1341         }
1342
1343         temporal_zoom (nfpu);
1344 }
1345
1346 void
1347 Editor::temporal_zoom (gdouble fpu)
1348 {
1349         if (!_session) return;
1350
1351         framepos_t current_page = current_page_frames();
1352         framepos_t current_leftmost = leftmost_frame;
1353         framepos_t current_rightmost;
1354         framepos_t current_center;
1355         framepos_t new_page_size;
1356         framepos_t half_page_size;
1357         framepos_t leftmost_after_zoom = 0;
1358         framepos_t where;
1359         bool in_track_canvas;
1360         double nfpu;
1361         double l;
1362
1363         /* XXX this limit is also in ::set_frames_per_unit() */
1364
1365         if (frames_per_unit <= 1.0 && fpu <= frames_per_unit) {
1366                 return;
1367         }
1368
1369         nfpu = fpu;
1370
1371         new_page_size = (framepos_t) floor (_canvas_width * nfpu);
1372         half_page_size = new_page_size / 2;
1373
1374         switch (zoom_focus) {
1375         case ZoomFocusLeft:
1376                 leftmost_after_zoom = current_leftmost;
1377                 break;
1378
1379         case ZoomFocusRight:
1380                 current_rightmost = leftmost_frame + current_page;
1381                 if (current_rightmost < new_page_size) {
1382                         leftmost_after_zoom = 0;
1383                 } else {
1384                         leftmost_after_zoom = current_rightmost - new_page_size;
1385                 }
1386                 break;
1387
1388         case ZoomFocusCenter:
1389                 current_center = current_leftmost + (current_page/2);
1390                 if (current_center < half_page_size) {
1391                         leftmost_after_zoom = 0;
1392                 } else {
1393                         leftmost_after_zoom = current_center - half_page_size;
1394                 }
1395                 break;
1396
1397         case ZoomFocusPlayhead:
1398                 /* centre playhead */
1399                 l = playhead_cursor->current_frame - (new_page_size * 0.5);
1400
1401                 if (l < 0) {
1402                         leftmost_after_zoom = 0;
1403                 } else if (l > max_framepos) {
1404                         leftmost_after_zoom = max_framepos - new_page_size;
1405                 } else {
1406                         leftmost_after_zoom = (framepos_t) l;
1407                 }
1408                 break;
1409
1410         case ZoomFocusMouse:
1411                 /* try to keep the mouse over the same point in the display */
1412
1413                 if (!mouse_frame (where, in_track_canvas)) {
1414                         /* use playhead instead */
1415                         where = playhead_cursor->current_frame;
1416
1417                         if (where < half_page_size) {
1418                                 leftmost_after_zoom = 0;
1419                         } else {
1420                                 leftmost_after_zoom = where - half_page_size;
1421                         }
1422
1423                 } else {
1424
1425                         l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1426
1427                         if (l < 0) {
1428                                 leftmost_after_zoom = 0;
1429                         } else if (l > max_framepos) {
1430                                 leftmost_after_zoom = max_framepos - new_page_size;
1431                         } else {
1432                                 leftmost_after_zoom = (framepos_t) l;
1433                         }
1434                 }
1435
1436                 break;
1437
1438         case ZoomFocusEdit:
1439                 /* try to keep the edit point in the same place */
1440                 where = get_preferred_edit_position ();
1441
1442                 if (where > 0) {
1443
1444                         double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1445
1446                         if (l < 0) {
1447                                 leftmost_after_zoom = 0;
1448                         } else if (l > max_framepos) {
1449                                 leftmost_after_zoom = max_framepos - new_page_size;
1450                         } else {
1451                                 leftmost_after_zoom = (framepos_t) l;
1452                         }
1453
1454                 } else {
1455                         /* edit point not defined */
1456                         return;
1457                 }
1458                 break;
1459
1460         }
1461
1462         // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1463
1464         reposition_and_zoom (leftmost_after_zoom, nfpu);
1465 }
1466
1467 void
1468 Editor::temporal_zoom_region (bool both_axes)
1469 {
1470         framepos_t start = max_framepos;
1471         framepos_t end = 0;
1472         set<TimeAxisView*> tracks;
1473
1474         RegionSelection rs = get_regions_from_selection_and_entered ();
1475
1476         if (rs.empty()) {
1477                 return;
1478         }
1479
1480         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1481
1482                 if ((*i)->region()->position() < start) {
1483                         start = (*i)->region()->position();
1484                 }
1485
1486                 if ((*i)->region()->last_frame() + 1 > end) {
1487                         end = (*i)->region()->last_frame() + 1;
1488                 }
1489
1490                 tracks.insert (&((*i)->get_time_axis_view()));
1491         }
1492
1493         /* now comes an "interesting" hack ... make sure we leave a little space
1494            at each end of the editor so that the zoom doesn't fit the region
1495            precisely to the screen.
1496         */
1497
1498         GdkScreen* screen = gdk_screen_get_default ();
1499         gint pixwidth = gdk_screen_get_width (screen);
1500         gint mmwidth = gdk_screen_get_width_mm (screen);
1501         double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1502         double one_centimeter_in_pixels = pix_per_mm * 10.0;
1503
1504         if ((start == 0 && end == 0) || end < start) {
1505                 return;
1506         }
1507
1508         framepos_t range = end - start;
1509         double new_fpu = (double)range / (double)_canvas_width;
1510         framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpu);
1511
1512         if (start > extra_samples) {
1513                 start -= extra_samples;
1514         } else {
1515                 start = 0;
1516         }
1517
1518         if (max_framepos - extra_samples > end) {
1519                 end += extra_samples;
1520         } else {
1521                 end = max_framepos;
1522         }
1523
1524         if (both_axes) {
1525                 /* save visual state with track states included, and prevent
1526                    set_frames_per_unit() from doing it again.
1527                 */
1528                 undo_visual_stack.push_back (current_visual_state(true));
1529                 no_save_visual = true;
1530         }
1531
1532         temporal_zoom_by_frame (start, end, "zoom to region");
1533
1534         if (both_axes) {
1535                 uint32_t per_track_height = (uint32_t) floor ((_canvas_height - canvas_timebars_vsize - 10.0) / tracks.size());
1536
1537                 /* set visible track heights appropriately */
1538
1539                 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1540                         (*t)->set_height (per_track_height);
1541                 }
1542
1543                 /* hide irrelevant tracks */
1544
1545                 _routes->suspend_redisplay ();
1546
1547                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1548                         if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1549                                 hide_track_in_display (*i);
1550                         }
1551                 }
1552
1553                 _routes->resume_redisplay ();
1554
1555                 vertical_adjustment.set_value (0.0);
1556                 no_save_visual = false;
1557         }
1558
1559         redo_visual_stack.push_back (current_visual_state());
1560 }
1561
1562 void
1563 Editor::zoom_to_region (bool both_axes)
1564 {
1565         temporal_zoom_region (both_axes);
1566 }
1567
1568 void
1569 Editor::temporal_zoom_selection ()
1570 {
1571         if (!selection) return;
1572
1573         if (selection->time.empty()) {
1574                 return;
1575         }
1576
1577         framepos_t start = selection->time[clicked_selection].start;
1578         framepos_t end = selection->time[clicked_selection].end;
1579
1580         temporal_zoom_by_frame (start, end, "zoom to selection");
1581 }
1582
1583 void
1584 Editor::temporal_zoom_session ()
1585 {
1586         ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1587
1588         if (_session) {
1589                 framecnt_t const l = _session->current_end_frame() - _session->current_start_frame();
1590                 double s = _session->current_start_frame() - l * 0.01;
1591                 if (s < 0) {
1592                         s = 0;
1593                 }
1594                 framecnt_t const e = _session->current_end_frame() + l * 0.01;
1595                 temporal_zoom_by_frame (framecnt_t (s), e, "zoom to _session");
1596         }
1597 }
1598
1599 void
1600 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end, const string & /*op*/)
1601 {
1602         if (!_session) return;
1603
1604         if ((start == 0 && end == 0) || end < start) {
1605                 return;
1606         }
1607
1608         framepos_t range = end - start;
1609
1610         double new_fpu = (double)range / (double)_canvas_width;
1611
1612         framepos_t new_page = (framepos_t) floor (_canvas_width * new_fpu);
1613         framepos_t middle = (framepos_t) floor( (double)start + ((double)range / 2.0f ));
1614         framepos_t new_leftmost = (framepos_t) floor( (double)middle - ((double)new_page/2.0f));
1615
1616         if (new_leftmost > middle) {
1617                 new_leftmost = 0;
1618         }
1619
1620         reposition_and_zoom (new_leftmost, new_fpu);
1621 }
1622
1623 void
1624 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1625 {
1626         if (!_session) {
1627                 return;
1628         }
1629         double range_before = frame - leftmost_frame;
1630         double new_fpu;
1631
1632         new_fpu = frames_per_unit;
1633
1634         if (coarser) {
1635                 new_fpu *= 1.61803399;
1636                 range_before *= 1.61803399;
1637         } else {
1638                 new_fpu = max(1.0,(new_fpu/1.61803399));
1639                 range_before /= 1.61803399;
1640         }
1641
1642         if (new_fpu == frames_per_unit)  {
1643                 return;
1644         }
1645
1646         framepos_t new_leftmost = frame - (framepos_t)range_before;
1647
1648         if (new_leftmost > frame) {
1649                 new_leftmost = 0;
1650         }
1651
1652         if (new_leftmost < 0) {
1653                 new_leftmost = 0;
1654         }
1655
1656         reposition_and_zoom (new_leftmost, new_fpu);
1657 }
1658
1659
1660 bool
1661 Editor::choose_new_marker_name(string &name) {
1662
1663         if (!Config->get_name_new_markers()) {
1664                 /* don't prompt user for a new name */
1665                 return true;
1666         }
1667
1668         ArdourPrompter dialog (true);
1669
1670         dialog.set_prompt (_("New Name:"));
1671
1672         dialog.set_title (_("New Location Marker"));
1673
1674         dialog.set_name ("MarkNameWindow");
1675         dialog.set_size_request (250, -1);
1676         dialog.set_position (Gtk::WIN_POS_MOUSE);
1677
1678         dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1679         dialog.set_initial_text (name);
1680
1681         dialog.show ();
1682
1683         switch (dialog.run ()) {
1684         case RESPONSE_ACCEPT:
1685                 break;
1686         default:
1687                 return false;
1688         }
1689
1690         dialog.get_result(name);
1691         return true;
1692
1693 }
1694
1695
1696 void
1697 Editor::add_location_from_selection ()
1698 {
1699         string rangename;
1700
1701         if (selection->time.empty()) {
1702                 return;
1703         }
1704
1705         if (_session == 0 || clicked_axisview == 0) {
1706                 return;
1707         }
1708
1709         framepos_t start = selection->time[clicked_selection].start;
1710         framepos_t end = selection->time[clicked_selection].end;
1711
1712         _session->locations()->next_available_name(rangename,"selection");
1713         Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1714
1715         _session->begin_reversible_command (_("add marker"));
1716         XMLNode &before = _session->locations()->get_state();
1717         _session->locations()->add (location, true);
1718         XMLNode &after = _session->locations()->get_state();
1719         _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1720         _session->commit_reversible_command ();
1721 }
1722
1723 void
1724 Editor::add_location_mark (framepos_t where)
1725 {
1726         string markername;
1727
1728         select_new_marker = true;
1729
1730         _session->locations()->next_available_name(markername,"mark");
1731         if (!choose_new_marker_name(markername)) {
1732                 return;
1733         }
1734         Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1735         _session->begin_reversible_command (_("add marker"));
1736         XMLNode &before = _session->locations()->get_state();
1737         _session->locations()->add (location, true);
1738         XMLNode &after = _session->locations()->get_state();
1739         _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1740         _session->commit_reversible_command ();
1741 }
1742
1743 void
1744 Editor::add_location_from_playhead_cursor ()
1745 {
1746         add_location_mark (_session->audible_frame());
1747 }
1748
1749 /** Add a range marker around each selected region */
1750 void
1751 Editor::add_locations_from_region ()
1752 {
1753         RegionSelection rs = get_regions_from_selection_and_entered ();
1754         
1755         if (rs.empty()) {
1756                 return;
1757         }
1758
1759         _session->begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
1760         XMLNode &before = _session->locations()->get_state();
1761
1762         for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
1763
1764                 boost::shared_ptr<Region> region = (*i)->region ();
1765
1766                 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
1767
1768                 _session->locations()->add (location, true);
1769         }
1770
1771         XMLNode &after = _session->locations()->get_state();
1772         _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1773         _session->commit_reversible_command ();
1774 }
1775
1776 /** Add a single range marker around all selected regions */
1777 void
1778 Editor::add_location_from_region ()
1779 {
1780         RegionSelection rs = get_regions_from_selection_and_entered ();
1781         
1782         if (rs.empty()) {
1783                 return;
1784         }
1785
1786         _session->begin_reversible_command (_("add marker"));
1787         XMLNode &before = _session->locations()->get_state();
1788
1789         string markername;
1790
1791         if (rs.size() > 1) {
1792                 _session->locations()->next_available_name(markername, "regions");
1793         } else {
1794                 RegionView* rv = *(rs.begin());
1795                 boost::shared_ptr<Region> region = rv->region();
1796                 markername = region->name();
1797         }
1798
1799         if (!choose_new_marker_name(markername)) {
1800                 return;
1801         }
1802
1803         // single range spanning all selected
1804         Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
1805         _session->locations()->add (location, true);
1806
1807         XMLNode &after = _session->locations()->get_state();
1808         _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1809         _session->commit_reversible_command ();
1810 }
1811
1812 /* MARKS */
1813
1814 void
1815 Editor::jump_forward_to_mark ()
1816 {
1817         if (!_session) {
1818                 return;
1819         }
1820
1821         Location *location = _session->locations()->first_location_after (playhead_cursor->current_frame);
1822
1823         if (location) {
1824                 _session->request_locate (location->start(), _session->transport_rolling());
1825         } else {
1826                 _session->request_locate (_session->current_end_frame());
1827         }
1828 }
1829
1830 void
1831 Editor::jump_backward_to_mark ()
1832 {
1833         if (!_session) {
1834                 return;
1835         }
1836
1837         Location *location = _session->locations()->first_location_before (playhead_cursor->current_frame);
1838
1839         if (location) {
1840                 _session->request_locate (location->start(), _session->transport_rolling());
1841         } else {
1842                 _session->goto_start ();
1843         }
1844 }
1845
1846 void
1847 Editor::set_mark ()
1848 {
1849         framepos_t const pos = _session->audible_frame ();
1850
1851         string markername;
1852         _session->locations()->next_available_name (markername, "mark");
1853         
1854         if (!choose_new_marker_name (markername)) {
1855                 return;
1856         }
1857         
1858         _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
1859 }
1860
1861 void
1862 Editor::clear_markers ()
1863 {
1864         if (_session) {
1865                 _session->begin_reversible_command (_("clear markers"));
1866                 XMLNode &before = _session->locations()->get_state();
1867                 _session->locations()->clear_markers ();
1868                 XMLNode &after = _session->locations()->get_state();
1869                 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1870                 _session->commit_reversible_command ();
1871         }
1872 }
1873
1874 void
1875 Editor::clear_ranges ()
1876 {
1877         if (_session) {
1878                 _session->begin_reversible_command (_("clear ranges"));
1879                 XMLNode &before = _session->locations()->get_state();
1880
1881                 Location * looploc = _session->locations()->auto_loop_location();
1882                 Location * punchloc = _session->locations()->auto_punch_location();
1883
1884                 _session->locations()->clear_ranges ();
1885                 // re-add these
1886                 if (looploc) _session->locations()->add (looploc);
1887                 if (punchloc) _session->locations()->add (punchloc);
1888
1889                 XMLNode &after = _session->locations()->get_state();
1890                 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1891                 _session->commit_reversible_command ();
1892         }
1893 }
1894
1895 void
1896 Editor::clear_locations ()
1897 {
1898         _session->begin_reversible_command (_("clear locations"));
1899         XMLNode &before = _session->locations()->get_state();
1900         _session->locations()->clear ();
1901         XMLNode &after = _session->locations()->get_state();
1902         _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1903         _session->commit_reversible_command ();
1904         _session->locations()->clear ();
1905 }
1906
1907 void
1908 Editor::unhide_markers ()
1909 {
1910         for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1911                 Location *l = (*i).first;
1912                 if (l->is_hidden() && l->is_mark()) {
1913                         l->set_hidden(false, this);
1914                 }
1915         }
1916 }
1917
1918 void
1919 Editor::unhide_ranges ()
1920 {
1921         for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1922                 Location *l = (*i).first;
1923                 if (l->is_hidden() && l->is_range_marker()) {
1924                         l->set_hidden(false, this);
1925                 }
1926         }
1927 }
1928
1929 /* INSERT/REPLACE */
1930
1931 void
1932 Editor::insert_region_list_drag (boost::shared_ptr<Region> region, int x, int y)
1933 {
1934         double wx, wy;
1935         double cx, cy;
1936         framepos_t where;
1937         RouteTimeAxisView *rtv = 0;
1938         boost::shared_ptr<Playlist> playlist;
1939
1940         track_canvas->window_to_world (x, y, wx, wy);
1941
1942         GdkEvent event;
1943         event.type = GDK_BUTTON_RELEASE;
1944         event.button.x = wx;
1945         event.button.y = wy;
1946
1947         where = event_frame (&event, &cx, &cy);
1948
1949         if (where < leftmost_frame || where > leftmost_frame + current_page_frames()) {
1950                 /* clearly outside canvas area */
1951                 return;
1952         }
1953
1954         std::pair<TimeAxisView*, int> tv = trackview_by_y_position (cy);
1955         if (tv.first == 0) {
1956                 return;
1957         }
1958
1959         if ((rtv = dynamic_cast<RouteTimeAxisView*> (tv.first)) == 0) {
1960                 return;
1961         }
1962
1963         if ((playlist = rtv->playlist()) == 0) {
1964                 return;
1965         }
1966
1967         snap_to (where);
1968
1969         begin_reversible_command (_("insert dragged region"));
1970         playlist->clear_changes ();
1971         playlist->add_region (RegionFactory::create (region, true), where, 1.0);
1972         _session->add_command(new StatefulDiffCommand (playlist));
1973         commit_reversible_command ();
1974 }
1975
1976 void
1977 Editor::insert_route_list_drag (boost::shared_ptr<Route> route, int x, int y)
1978 {
1979         double wx, wy;
1980         double cx, cy;
1981         framepos_t where;
1982         RouteTimeAxisView *dest_rtv = 0;
1983         RouteTimeAxisView *source_rtv = 0;
1984
1985         track_canvas->window_to_world (x, y, wx, wy);
1986         wx += horizontal_position ();
1987         wy += vertical_adjustment.get_value();
1988
1989         GdkEvent event;
1990         event.type = GDK_BUTTON_RELEASE;
1991         event.button.x = wx;
1992         event.button.y = wy;
1993
1994         where = event_frame (&event, &cx, &cy);
1995
1996         std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (cy);
1997         if (tv.first == 0) {
1998                 return;
1999         }
2000
2001         if ((dest_rtv = dynamic_cast<RouteTimeAxisView*> (tv.first)) == 0) {
2002                 return;
2003         }
2004
2005         /* use this drag source to add underlay to a track. But we really don't care
2006            about the Route, only the view of the route, so find it first */
2007         for(TrackViewList::iterator it = track_views.begin(); it != track_views.end(); ++it) {
2008                 if((source_rtv = dynamic_cast<RouteTimeAxisView*>(*it)) == 0) {
2009                         continue;
2010                 }
2011
2012                 if(source_rtv->route() == route && source_rtv != dest_rtv) {
2013                         dest_rtv->add_underlay(source_rtv->view());
2014                         break;
2015                 }
2016         }
2017 }
2018
2019 void
2020 Editor::insert_region_list_selection (float times)
2021 {
2022         RouteTimeAxisView *tv = 0;
2023         boost::shared_ptr<Playlist> playlist;
2024
2025         if (clicked_routeview != 0) {
2026                 tv = clicked_routeview;
2027         } else if (!selection->tracks.empty()) {
2028                 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2029                         return;
2030                 }
2031         } else if (entered_track != 0) {
2032                 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2033                         return;
2034                 }
2035         } else {
2036                 return;
2037         }
2038
2039         if ((playlist = tv->playlist()) == 0) {
2040                 return;
2041         }
2042
2043         boost::shared_ptr<Region> region = _regions->get_single_selection ();
2044         if (region == 0) {
2045                 return;
2046         }
2047
2048         begin_reversible_command (_("insert region"));
2049         playlist->clear_changes ();
2050         playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2051         _session->add_command(new StatefulDiffCommand (playlist));
2052         commit_reversible_command ();
2053 }
2054
2055 /* BUILT-IN EFFECTS */
2056
2057 void
2058 Editor::reverse_selection ()
2059 {
2060
2061 }
2062
2063 /* GAIN ENVELOPE EDITING */
2064
2065 void
2066 Editor::edit_envelope ()
2067 {
2068 }
2069
2070 /* PLAYBACK */
2071
2072 void
2073 Editor::transition_to_rolling (bool fwd)
2074 {
2075         if (!_session) {
2076                 return;
2077         }
2078
2079         if (_session->config.get_external_sync()) {
2080                 switch (_session->config.get_sync_source()) {
2081                 case JACK:
2082                         break;
2083                 default:
2084                         /* transport controlled by the master */
2085                         return;
2086                 }
2087         }
2088
2089         if (_session->is_auditioning()) {
2090                 _session->cancel_audition ();
2091                 return;
2092         }
2093
2094         _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2095 }
2096
2097 void
2098 Editor::play_from_start ()
2099 {
2100         _session->request_locate (_session->current_start_frame(), true);
2101 }
2102
2103 void
2104 Editor::play_from_edit_point ()
2105 {
2106         _session->request_locate (get_preferred_edit_position(), true);
2107 }
2108
2109 void
2110 Editor::play_from_edit_point_and_return ()
2111 {
2112         framepos_t start_frame;
2113         framepos_t return_frame;
2114
2115         start_frame = get_preferred_edit_position (true);
2116
2117         if (_session->transport_rolling()) {
2118                 _session->request_locate (start_frame, false);
2119                 return;
2120         }
2121
2122         /* don't reset the return frame if its already set */
2123
2124         if ((return_frame = _session->requested_return_frame()) < 0) {
2125                 return_frame = _session->audible_frame();
2126         }
2127
2128         if (start_frame >= 0) {
2129                 _session->request_roll_at_and_return (start_frame, return_frame);
2130         }
2131 }
2132
2133 void
2134 Editor::play_selection ()
2135 {
2136         if (selection->time.empty()) {
2137                 return;
2138         }
2139
2140         _session->request_play_range (&selection->time, true);
2141 }
2142
2143 void
2144 Editor::play_location (Location& location)
2145 {
2146         if (location.start() <= location.end()) {
2147                 return;
2148         }
2149
2150         _session->request_bounded_roll (location.start(), location.end());
2151 }
2152
2153 void
2154 Editor::loop_location (Location& location)
2155 {
2156         if (location.start() <= location.end()) {
2157                 return;
2158         }
2159
2160         Location* tll;
2161
2162         if ((tll = transport_loop_location()) != 0) {
2163                 tll->set (location.start(), location.end());
2164
2165                 // enable looping, reposition and start rolling
2166                 _session->request_play_loop (true);
2167                 _session->request_locate (tll->start(), true);
2168         }
2169 }
2170
2171 void
2172 Editor::raise_region ()
2173 {
2174         selection->foreach_region (&Region::raise);
2175 }
2176
2177 void
2178 Editor::raise_region_to_top ()
2179 {
2180         selection->foreach_region (&Region::raise_to_top);
2181 }
2182
2183 void
2184 Editor::lower_region ()
2185 {
2186         selection->foreach_region (&Region::lower);
2187 }
2188
2189 void
2190 Editor::lower_region_to_bottom ()
2191 {
2192         selection->foreach_region (&Region::lower_to_bottom);
2193 }
2194
2195 /** Show the region editor for the selected regions */
2196 void
2197 Editor::show_region_properties ()
2198 {
2199         selection->foreach_regionview (&RegionView::show_region_editor);
2200 }
2201
2202 /** Show the midi list editor for the selected MIDI regions */
2203 void
2204 Editor::show_midi_list_editor ()
2205 {
2206         selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2207 }
2208
2209 void
2210 Editor::rename_region ()
2211 {
2212         RegionSelection rs = get_regions_from_selection_and_entered ();
2213         
2214         if (rs.empty()) {
2215                 return;
2216         }
2217
2218         ArdourDialog d (*this, _("Rename Region"), true, false);
2219         Entry entry;
2220         Label label (_("New name:"));
2221         HBox hbox;
2222
2223         hbox.set_spacing (6);
2224         hbox.pack_start (label, false, false);
2225         hbox.pack_start (entry, true, true);
2226
2227         d.get_vbox()->set_border_width (12);
2228         d.get_vbox()->pack_start (hbox, false, false);
2229
2230         d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2231         d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2232
2233         d.set_size_request (300, -1);
2234         d.set_position (Gtk::WIN_POS_MOUSE);
2235
2236         entry.set_text (selection->regions.front()->region()->name());
2237         entry.select_region (0, -1);
2238
2239         entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2240
2241         d.show_all ();
2242
2243         entry.grab_focus();
2244
2245         int const ret = d.run();
2246
2247         d.hide ();
2248
2249         if (ret != RESPONSE_OK) {
2250                 return;
2251         }
2252         
2253         std::string str = entry.get_text();
2254         strip_whitespace_edges (str);
2255         if (!str.empty()) {
2256                 rs.front()->region()->set_name (str);
2257                 _regions->redisplay ();
2258         }
2259 }
2260
2261 void
2262 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2263 {
2264         if (_session->is_auditioning()) {
2265                 _session->cancel_audition ();
2266         }
2267
2268         // note: some potential for creativity here, because region doesn't
2269         // have to belong to the playlist that Route is handling
2270
2271         // bool was_soloed = route.soloed();
2272
2273         route.set_solo (true, this);
2274
2275         _session->request_bounded_roll (region->position(), region->position() + region->length());
2276
2277         /* XXX how to unset the solo state ? */
2278 }
2279
2280 /** Start an audition of the first selected region */
2281 void
2282 Editor::play_edit_range ()
2283 {
2284         framepos_t start, end;
2285
2286         if (get_edit_op_range (start, end)) {
2287                 _session->request_bounded_roll (start, end);
2288         }
2289 }
2290
2291 void
2292 Editor::play_selected_region ()
2293 {
2294         framepos_t start = max_framepos;
2295         framepos_t end = 0;
2296
2297         RegionSelection rs = get_regions_from_selection_and_entered ();
2298         
2299         if (rs.empty()) {
2300                 return;
2301         }
2302
2303         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2304                 if ((*i)->region()->position() < start) {
2305                         start = (*i)->region()->position();
2306                 }
2307                 if ((*i)->region()->last_frame() + 1 > end) {
2308                         end = (*i)->region()->last_frame() + 1;
2309                 }
2310         }
2311
2312         _session->request_bounded_roll (start, end);
2313 }
2314
2315 void
2316 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2317 {
2318         _session->audition_region (region);
2319 }
2320
2321 void
2322 Editor::region_from_selection ()
2323 {
2324         if (clicked_axisview == 0) {
2325                 return;
2326         }
2327
2328         if (selection->time.empty()) {
2329                 return;
2330         }
2331
2332         framepos_t start = selection->time[clicked_selection].start;
2333         framepos_t end = selection->time[clicked_selection].end;
2334
2335         TrackViewList tracks = get_tracks_for_range_action ();
2336
2337         framepos_t selection_cnt = end - start + 1;
2338
2339         for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2340                 boost::shared_ptr<Region> current;
2341                 boost::shared_ptr<Playlist> pl;
2342                 framepos_t internal_start;
2343                 string new_name;
2344
2345                 if ((pl = (*i)->playlist()) == 0) {
2346                         continue;
2347                 }
2348
2349                 if ((current = pl->top_region_at (start)) == 0) {
2350                         continue;
2351                 }
2352
2353                 internal_start = start - current->position();
2354                 RegionFactory::region_name (new_name, current->name(), true);
2355
2356                 PropertyList plist; 
2357                 
2358                 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2359                 plist.add (ARDOUR::Properties::length, selection_cnt);
2360                 plist.add (ARDOUR::Properties::name, new_name);
2361                 plist.add (ARDOUR::Properties::layer, 0);
2362
2363                 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2364         }
2365 }
2366
2367 void
2368 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2369 {
2370         if (selection->time.empty() || selection->tracks.empty()) {
2371                 return;
2372         }
2373
2374         framepos_t start = selection->time[clicked_selection].start;
2375         framepos_t end = selection->time[clicked_selection].end;
2376
2377         sort_track_selection ();
2378
2379         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2380                 boost::shared_ptr<Region> current;
2381                 boost::shared_ptr<Playlist> playlist;
2382                 framepos_t internal_start;
2383                 string new_name;
2384
2385                 if ((playlist = (*i)->playlist()) == 0) {
2386                         continue;
2387                 }
2388
2389                 if ((current = playlist->top_region_at(start)) == 0) {
2390                         continue;
2391                 }
2392
2393                 internal_start = start - current->position();
2394                 RegionFactory::region_name (new_name, current->name(), true);
2395
2396                 PropertyList plist; 
2397                 
2398                 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2399                 plist.add (ARDOUR::Properties::length, end - start + 1);
2400                 plist.add (ARDOUR::Properties::name, new_name);
2401
2402                 new_regions.push_back (RegionFactory::create (current, plist));
2403         }
2404 }
2405
2406 void
2407 Editor::split_multichannel_region ()
2408 {
2409         RegionSelection rs = get_regions_from_selection_and_entered ();
2410         
2411         if (rs.empty()) {
2412                 return;
2413         }
2414
2415         vector< boost::shared_ptr<Region> > v;
2416
2417         for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2418                 (*x)->region()->separate_by_channel (*_session, v);
2419         }
2420 }
2421
2422 void
2423 Editor::new_region_from_selection ()
2424 {
2425         region_from_selection ();
2426         cancel_selection ();
2427 }
2428
2429 static void
2430 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2431 {
2432         switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2433         case OverlapNone:
2434                 break;
2435         default:
2436                 rs->push_back (rv);
2437         }
2438 }
2439
2440 /** Return either:
2441  *    - selected tracks, or if there are none...
2442  *    - tracks containing selected regions, or if there are none...
2443  *    - all tracks
2444  * @return tracks.
2445  */
2446 TrackViewList
2447 Editor::get_tracks_for_range_action () const
2448 {
2449         TrackViewList t;
2450
2451         if (selection->tracks.empty()) {
2452
2453                 /* use tracks with selected regions */
2454
2455                 RegionSelection rs = selection->regions;
2456
2457                 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2458                         TimeAxisView* tv = &(*i)->get_time_axis_view();
2459
2460                         if (!t.contains (tv)) {
2461                                 t.push_back (tv);
2462                         }
2463                 }
2464
2465                 if (t.empty()) {
2466                         /* no regions and no tracks: use all tracks */
2467                         t = track_views;
2468                 }
2469
2470         } else {
2471
2472                 t = selection->tracks;
2473         }
2474
2475         return t;
2476 }
2477
2478 void
2479 Editor::separate_regions_between (const TimeSelection& ts)
2480 {
2481         bool in_command = false;
2482         boost::shared_ptr<Playlist> playlist;
2483         RegionSelection new_selection;
2484
2485         TrackViewList tmptracks = get_tracks_for_range_action ();
2486         sort_track_selection (&tmptracks);
2487
2488         for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2489
2490                 RouteTimeAxisView* rtv;
2491
2492                 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2493
2494                         if (rtv->is_track()) {
2495
2496                                 /* no edits to destructive tracks */
2497
2498                                 if (rtv->track()->destructive()) {
2499                                         continue;
2500                                 }
2501
2502                                 if ((playlist = rtv->playlist()) != 0) {
2503
2504                                         playlist->clear_changes ();
2505
2506                                         /* XXX need to consider musical time selections here at some point */
2507
2508                                         double speed = rtv->track()->speed();
2509
2510
2511                                         for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2512
2513                                                 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2514                                                                 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2515
2516                                                 latest_regionviews.clear ();
2517
2518                                                 playlist->partition ((framepos_t)((*t).start * speed),
2519                                                                 (framepos_t)((*t).end * speed), false);
2520
2521                                                 c.disconnect ();
2522
2523                                                 if (!latest_regionviews.empty()) {
2524
2525                                                         rtv->view()->foreach_regionview (sigc::bind (
2526                                                                                 sigc::ptr_fun (add_if_covered),
2527                                                                                 &(*t), &new_selection));
2528                                                         
2529                                                         if (!in_command) {
2530                                                                 begin_reversible_command (_("separate"));
2531                                                                 in_command = true;
2532                                                         }
2533                                                         
2534                                                         /* pick up changes to existing regions */
2535
2536                                                         vector<Command*> cmds;
2537                                                         playlist->rdiff (cmds);
2538                                                         _session->add_commands (cmds);
2539
2540                                                         /* pick up changes to the playlist itself (adds/removes)
2541                                                          */
2542
2543                                                         _session->add_command(new StatefulDiffCommand (playlist));
2544                                                 }
2545                                         }
2546                                 }
2547                         }
2548                 }
2549         }
2550
2551         if (in_command) {
2552                 selection->set (new_selection);
2553                 set_mouse_mode (MouseObject);
2554
2555                 commit_reversible_command ();
2556         }
2557 }
2558
2559 struct PlaylistState {
2560     boost::shared_ptr<Playlist> playlist;
2561     XMLNode*  before;
2562 };
2563
2564 /** Take tracks from get_tracks_for_range_action and cut any regions
2565  *  on those tracks so that the tracks are empty over the time
2566  *  selection.
2567  */
2568 void
2569 Editor::separate_region_from_selection ()
2570 {
2571         /* preferentially use *all* ranges in the time selection if we're in range mode
2572            to allow discontiguous operation, since get_edit_op_range() currently
2573            returns a single range.
2574         */
2575
2576         if (mouse_mode == MouseRange && !selection->time.empty()) {
2577
2578                 separate_regions_between (selection->time);
2579
2580         } else {
2581
2582                 framepos_t start;
2583                 framepos_t end;
2584
2585                 if (get_edit_op_range (start, end)) {
2586
2587                         AudioRange ar (start, end, 1);
2588                         TimeSelection ts;
2589                         ts.push_back (ar);
2590
2591                         separate_regions_between (ts);
2592                 }
2593         }
2594 }
2595
2596 void
2597 Editor::separate_region_from_punch ()
2598 {
2599         Location* loc  = _session->locations()->auto_punch_location();
2600         if (loc) {
2601                 separate_regions_using_location (*loc);
2602         }
2603 }
2604
2605 void
2606 Editor::separate_region_from_loop ()
2607 {
2608         Location* loc  = _session->locations()->auto_loop_location();
2609         if (loc) {
2610                 separate_regions_using_location (*loc);
2611         }
2612 }
2613
2614 void
2615 Editor::separate_regions_using_location (Location& loc)
2616 {
2617         if (loc.is_mark()) {
2618                 return;
2619         }
2620
2621         AudioRange ar (loc.start(), loc.end(), 1);
2622         TimeSelection ts;
2623
2624         ts.push_back (ar);
2625
2626         separate_regions_between (ts);
2627 }
2628
2629 /** Separate regions under the selected region */
2630 void
2631 Editor::separate_under_selected_regions ()
2632 {
2633         vector<PlaylistState> playlists;
2634
2635         RegionSelection rs;
2636         
2637         rs = get_regions_from_selection_and_entered();
2638
2639         if (!_session || rs.empty()) {
2640                 return;
2641         }
2642
2643         begin_reversible_command (_("separate region under"));
2644
2645         list<boost::shared_ptr<Region> > regions_to_remove;
2646
2647         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2648                 // we can't just remove the region(s) in this loop because
2649                 // this removes them from the RegionSelection, and they thus
2650                 // disappear from underneath the iterator, and the ++i above
2651                 // SEGVs in a puzzling fashion.
2652
2653                 // so, first iterate over the regions to be removed from rs and
2654                 // add them to the regions_to_remove list, and then
2655                 // iterate over the list to actually remove them.
2656
2657                 regions_to_remove.push_back ((*i)->region());
2658         }
2659
2660         for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2661
2662                 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2663
2664                 if (!playlist) {
2665                         // is this check necessary?
2666                         continue;
2667                 }
2668
2669                 vector<PlaylistState>::iterator i;
2670
2671                 //only take state if this is a new playlist.
2672                 for (i = playlists.begin(); i != playlists.end(); ++i) {
2673                         if ((*i).playlist == playlist) {
2674                                 break;
2675                         }
2676                 }
2677
2678                 if (i == playlists.end()) {
2679
2680                         PlaylistState before;
2681                         before.playlist = playlist;
2682                         before.before = &playlist->get_state();
2683
2684                         playlist->freeze ();
2685                         playlists.push_back(before);
2686                 }
2687
2688                 //Partition on the region bounds
2689                 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2690                 
2691                 //Re-add region that was just removed due to the partition operation
2692                 playlist->add_region( (*rl), (*rl)->first_frame() );
2693         }
2694
2695         vector<PlaylistState>::iterator pl;
2696
2697         for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2698                 (*pl).playlist->thaw ();
2699                 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2700         }
2701
2702         commit_reversible_command ();
2703 }
2704
2705 void
2706 Editor::crop_region_to_selection ()
2707 {
2708         if (!selection->time.empty()) {
2709
2710                 crop_region_to (selection->time.start(), selection->time.end_frame());
2711
2712         } else {
2713
2714                 framepos_t start;
2715                 framepos_t end;
2716
2717                 if (get_edit_op_range (start, end)) {
2718                         crop_region_to (start, end);
2719                 }
2720         }
2721
2722 }
2723
2724 void
2725 Editor::crop_region_to (framepos_t start, framepos_t end)
2726 {
2727         vector<boost::shared_ptr<Playlist> > playlists;
2728         boost::shared_ptr<Playlist> playlist;
2729         TrackViewList* ts;
2730
2731         if (selection->tracks.empty()) {
2732                 ts = &track_views;
2733         } else {
2734                 sort_track_selection ();
2735                 ts = &selection->tracks;
2736         }
2737
2738         for (TrackSelection::iterator i = ts->begin(); i != ts->end(); ++i) {
2739
2740                 RouteTimeAxisView* rtv;
2741
2742                 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2743
2744                         boost::shared_ptr<Track> t = rtv->track();
2745
2746                         if (t != 0 && ! t->destructive()) {
2747
2748                                 if ((playlist = rtv->playlist()) != 0) {
2749                                         playlists.push_back (playlist);
2750                                 }
2751                         }
2752                 }
2753         }
2754
2755         if (playlists.empty()) {
2756                 return;
2757         }
2758
2759         framepos_t the_start;
2760         framepos_t the_end;
2761         framepos_t cnt;
2762
2763         begin_reversible_command (_("trim to selection"));
2764
2765         for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2766
2767                 boost::shared_ptr<Region> region;
2768
2769                 the_start = start;
2770
2771                 if ((region = (*i)->top_region_at(the_start)) == 0) {
2772                         continue;
2773                 }
2774
2775                 /* now adjust lengths to that we do the right thing
2776                    if the selection extends beyond the region
2777                 */
2778
2779                 the_start = max (the_start, (framepos_t) region->position());
2780                 if (max_framepos - the_start < region->length()) {
2781                         the_end = the_start + region->length() - 1;
2782                 } else {
2783                         the_end = max_framepos;
2784                 }
2785                 the_end = min (end, the_end);
2786                 cnt = the_end - the_start + 1;
2787
2788                 region->clear_changes ();
2789                 region->trim_to (the_start, cnt, this);
2790                 _session->add_command (new StatefulDiffCommand (region));
2791         }
2792
2793         commit_reversible_command ();
2794 }
2795
2796 void
2797 Editor::region_fill_track ()
2798 {
2799         RegionSelection rs = get_regions_from_selection_and_entered ();
2800
2801         if (!_session || rs.empty()) {
2802                 return;
2803         }
2804
2805         framepos_t const end = _session->current_end_frame ();
2806
2807         begin_reversible_command (Operations::region_fill);
2808
2809         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2810
2811                 boost::shared_ptr<Region> region ((*i)->region());
2812
2813                 boost::shared_ptr<Playlist> pl = region->playlist();
2814
2815                 if (end <= region->last_frame()) {
2816                         return;
2817                 }
2818
2819                 double times = (double) (end - region->last_frame()) / (double) region->length();
2820
2821                 if (times == 0) {
2822                         return;
2823                 }
2824
2825                 pl->clear_changes ();
2826                 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
2827                 _session->add_command (new StatefulDiffCommand (pl));
2828         }
2829
2830         commit_reversible_command ();
2831 }
2832
2833 void
2834 Editor::region_fill_selection ()
2835 {
2836         if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
2837                 return;
2838         }
2839
2840         if (selection->time.empty()) {
2841                 return;
2842         }
2843
2844         boost::shared_ptr<Region> region = _regions->get_single_selection ();
2845         if (region == 0) {
2846                 return;
2847         }
2848
2849         framepos_t start = selection->time[clicked_selection].start;
2850         framepos_t end = selection->time[clicked_selection].end;
2851
2852         boost::shared_ptr<Playlist> playlist;
2853
2854         if (selection->tracks.empty()) {
2855                 return;
2856         }
2857
2858         framepos_t selection_length = end - start;
2859         float times = (float)selection_length / region->length();
2860
2861         begin_reversible_command (Operations::fill_selection);
2862
2863         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2864
2865                 if ((playlist = (*i)->playlist()) == 0) {
2866                         continue;
2867                 }
2868
2869                 playlist->clear_changes ();
2870                 playlist->add_region (RegionFactory::create (region, true), start, times);
2871                 _session->add_command (new StatefulDiffCommand (playlist));
2872         }
2873
2874         commit_reversible_command ();
2875 }
2876
2877 void
2878 Editor::set_region_sync_position ()
2879 {
2880         set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
2881 }
2882
2883 void
2884 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
2885 {
2886         bool in_command = false;
2887
2888         for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
2889
2890                 if (!(*r)->region()->covers (where)) {
2891                         continue;
2892                 }
2893
2894                 boost::shared_ptr<Region> region ((*r)->region());
2895
2896                 if (!in_command) {
2897                         begin_reversible_command (_("set sync point"));
2898                         in_command = true;
2899                 }
2900
2901                 region->clear_changes ();
2902                 region->set_sync_position (where);
2903                 _session->add_command(new StatefulDiffCommand (region));
2904         }
2905
2906         if (in_command) {
2907                 commit_reversible_command ();
2908         }
2909 }
2910
2911 /** Remove the sync positions of the selection */
2912 void
2913 Editor::remove_region_sync ()
2914 {
2915         RegionSelection rs = get_regions_from_selection_and_entered ();
2916         
2917         if (rs.empty()) {
2918                 return;
2919         }
2920
2921         begin_reversible_command (_("remove region sync"));
2922         
2923         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2924
2925                 (*i)->region()->clear_changes ();
2926                 (*i)->region()->clear_sync_position ();
2927                 _session->add_command(new StatefulDiffCommand ((*i)->region()));
2928         }
2929         
2930         commit_reversible_command ();
2931 }
2932
2933 void
2934 Editor::naturalize_region ()
2935 {
2936         RegionSelection rs = get_regions_from_selection_and_entered ();
2937
2938         if (rs.empty()) {
2939                 return;
2940         }
2941
2942         if (rs.size() > 1) {
2943                 begin_reversible_command (_("move regions to original position"));
2944         } else {
2945                 begin_reversible_command (_("move region to original position"));
2946         }
2947                 
2948         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2949                 (*i)->region()->clear_changes ();
2950                 (*i)->region()->move_to_natural_position (this);
2951                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
2952         }
2953         
2954         commit_reversible_command ();
2955 }
2956
2957 void
2958 Editor::align_regions (RegionPoint what)
2959 {
2960         RegionSelection const rs = get_regions_from_selection_and_edit_point ();
2961         
2962         if (rs.empty()) {
2963                 return;
2964         }
2965
2966         begin_reversible_command (_("align selection"));
2967
2968         framepos_t const position = get_preferred_edit_position ();
2969
2970         for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
2971                 align_region_internal ((*i)->region(), what, position);
2972         }
2973
2974         commit_reversible_command ();
2975 }
2976
2977 struct RegionSortByTime {
2978     bool operator() (const RegionView* a, const RegionView* b) {
2979             return a->region()->position() < b->region()->position();
2980     }
2981 };
2982
2983 void
2984 Editor::align_regions_relative (RegionPoint point)
2985 {
2986         RegionSelection const rs = get_regions_from_selection_and_edit_point ();
2987         
2988         if (rs.empty()) {
2989                 return;
2990         }
2991
2992         framepos_t const position = get_preferred_edit_position ();
2993
2994         framepos_t distance = 0;
2995         framepos_t pos = 0;
2996         int dir = 1;
2997
2998         list<RegionView*> sorted;
2999         rs.by_position (sorted);
3000
3001         boost::shared_ptr<Region> r ((*sorted.begin())->region());
3002
3003         switch (point) {
3004         case Start:
3005                 pos = position;
3006                 if (position > r->position()) {
3007                         distance = position - r->position();
3008                 } else {
3009                         distance = r->position() - position;
3010                         dir = -1;
3011                 }
3012                 break;
3013
3014         case End:
3015                 if (position > r->last_frame()) {
3016                         distance = position - r->last_frame();
3017                         pos = r->position() + distance;
3018                 } else {
3019                         distance = r->last_frame() - position;
3020                         pos = r->position() - distance;
3021                         dir = -1;
3022                 }
3023                 break;
3024
3025         case SyncPoint:
3026                 pos = r->adjust_to_sync (position);
3027                 if (pos > r->position()) {
3028                         distance = pos - r->position();
3029                 } else {
3030                         distance = r->position() - pos;
3031                         dir = -1;
3032                 }
3033                 break;
3034         }
3035
3036         if (pos == r->position()) {
3037                 return;
3038         }
3039
3040         begin_reversible_command (_("align selection (relative)"));
3041
3042         /* move first one specially */
3043
3044         r->clear_changes ();
3045         r->set_position (pos, this);
3046         _session->add_command(new StatefulDiffCommand (r));
3047
3048         /* move rest by the same amount */
3049
3050         sorted.pop_front();
3051
3052         for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3053
3054                 boost::shared_ptr<Region> region ((*i)->region());
3055
3056                 region->clear_changes ();
3057
3058                 if (dir > 0) {
3059                         region->set_position (region->position() + distance, this);
3060                 } else {
3061                         region->set_position (region->position() - distance, this);
3062                 }
3063                 
3064                 _session->add_command(new StatefulDiffCommand (region));
3065
3066         }
3067
3068         commit_reversible_command ();
3069 }
3070
3071 void
3072 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3073 {
3074         begin_reversible_command (_("align region"));
3075         align_region_internal (region, point, position);
3076         commit_reversible_command ();
3077 }
3078
3079 void
3080 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3081 {
3082         region->clear_changes ();
3083
3084         switch (point) {
3085         case SyncPoint:
3086                 region->set_position (region->adjust_to_sync (position), this);
3087                 break;
3088
3089         case End:
3090                 if (position > region->length()) {
3091                         region->set_position (position - region->length(), this);
3092                 }
3093                 break;
3094
3095         case Start:
3096                 region->set_position (position, this);
3097                 break;
3098         }
3099
3100         _session->add_command(new StatefulDiffCommand (region));
3101 }
3102
3103 void
3104 Editor::trim_region_front ()
3105 {
3106         trim_region (true);
3107 }
3108
3109 void
3110 Editor::trim_region_back ()
3111 {
3112         trim_region (false);
3113 }
3114
3115 void
3116 Editor::trim_region (bool front)
3117 {
3118         framepos_t where = get_preferred_edit_position();
3119         RegionSelection rs = get_regions_from_selection_and_edit_point ();
3120
3121         cerr << "trim regions\n";
3122
3123         if (rs.empty()) {
3124                 cerr << " no regions\n";
3125                 return;
3126         }
3127
3128         cerr << "where = " << where << endl;
3129
3130         begin_reversible_command (front ? _("trim front") : _("trim back"));
3131
3132         for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3133                 if (!(*i)->region()->locked()) {
3134                         
3135                         (*i)->region()->clear_changes ();
3136                         
3137                         if (front) {
3138                                 (*i)->region()->trim_front (where, this);
3139                         } else {
3140                                 (*i)->region()->trim_end (where, this);
3141                         }
3142                         
3143                         _session->add_command (new StatefulDiffCommand ((*i)->region()));
3144                 }
3145         }
3146
3147         commit_reversible_command ();
3148 }
3149
3150 /** Trim the end of the selected regions to the position of the edit cursor */
3151 void
3152 Editor::trim_region_to_loop ()
3153 {
3154         Location* loc = _session->locations()->auto_loop_location();
3155         if (!loc) {
3156                 return;
3157         }
3158         trim_region_to_location (*loc, _("trim to loop"));
3159 }
3160
3161 void
3162 Editor::trim_region_to_punch ()
3163 {
3164         Location* loc = _session->locations()->auto_punch_location();
3165         if (!loc) {
3166                 return;
3167         }
3168         trim_region_to_location (*loc, _("trim to punch"));
3169 }
3170
3171 void
3172 Editor::trim_region_to_location (const Location& loc, const char* str)
3173 {
3174         RegionSelection rs = get_regions_from_selection_and_entered ();
3175
3176         begin_reversible_command (str);
3177
3178         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3179                 RegionView* rv = (*x);
3180
3181                 /* require region to span proposed trim */
3182                 switch (rv->region()->coverage (loc.start(), loc.end())) {
3183                 case OverlapInternal:
3184                         break;
3185                 default:
3186                         continue;
3187                 }
3188
3189                 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3190                 if (!tav) {
3191                         return;
3192                 }
3193
3194                 float speed = 1.0;
3195                 framepos_t start;
3196                 framepos_t end;
3197
3198                 if (tav->track() != 0) {
3199                         speed = tav->track()->speed();
3200                 }
3201
3202                 start = session_frame_to_track_frame (loc.start(), speed);
3203                 end = session_frame_to_track_frame (loc.end(), speed);
3204                 
3205                 rv->region()->clear_changes ();
3206                 rv->region()->trim_to (start, (end - start), this);
3207                 _session->add_command(new StatefulDiffCommand (rv->region()));
3208         }
3209
3210         commit_reversible_command ();
3211 }
3212
3213 void
3214 Editor::trim_region_to_previous_region_end ()
3215 {
3216         return trim_to_region(false);
3217 }
3218
3219 void
3220 Editor::trim_region_to_next_region_start ()
3221 {
3222         return trim_to_region(true);
3223 }
3224
3225 void
3226 Editor::trim_to_region(bool forward)
3227 {
3228         RegionSelection rs = get_regions_from_selection_and_entered ();
3229
3230         begin_reversible_command (_("trim to region"));
3231
3232         boost::shared_ptr<Region> next_region;
3233
3234         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3235
3236                 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3237
3238                 if (!arv) {
3239                         continue;
3240                 }
3241
3242                 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3243
3244                 if (!atav) {
3245                         return;
3246                 }
3247
3248                 float speed = 1.0;
3249
3250                 if (atav->track() != 0) {
3251                         speed = atav->track()->speed();
3252                 }
3253
3254
3255                 boost::shared_ptr<Region> region = arv->region();
3256                 boost::shared_ptr<Playlist> playlist (region->playlist());
3257
3258                 region->clear_changes ();
3259
3260                 if (forward) {
3261
3262                     next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3263
3264                     if (!next_region) {
3265                         continue;
3266                     }
3267
3268                     region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed), this);
3269                     arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3270                 }
3271                 else {
3272
3273                     next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3274
3275                     if(!next_region){
3276                         continue;
3277                     }
3278
3279                     region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed), this);
3280
3281                     arv->region_changed (ARDOUR::bounds_change);
3282                 }
3283
3284                 _session->add_command(new StatefulDiffCommand (region));
3285         }
3286
3287         commit_reversible_command ();
3288 }
3289
3290 void
3291 Editor::unfreeze_route ()
3292 {
3293         if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3294                 return;
3295         }
3296
3297         clicked_routeview->track()->unfreeze ();
3298 }
3299
3300 void*
3301 Editor::_freeze_thread (void* arg)
3302 {
3303         SessionEvent::create_per_thread_pool ("freeze events", 64);
3304
3305         return static_cast<Editor*>(arg)->freeze_thread ();
3306 }
3307
3308 void*
3309 Editor::freeze_thread ()
3310 {
3311         clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3312         current_interthread_info->done = true;
3313         return 0;
3314 }
3315
3316 void
3317 Editor::freeze_route ()
3318 {
3319         if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3320                 return;
3321         }
3322
3323         if (!clicked_routeview->track()->bounceable()) {
3324                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_routeview);
3325                 if (rtv && !rtv->track()->bounceable()) {
3326                         MessageDialog d (
3327                                 _("This route cannot be frozen because it has more outputs than inputs.  "
3328                                   "You can fix this by increasing the number of inputs.")
3329                                 );
3330                         d.set_title (_("Cannot freeze"));
3331                         d.run ();
3332                         return;
3333                 }
3334         }
3335
3336         InterThreadInfo itt;
3337         current_interthread_info = &itt;
3338
3339         InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3340
3341         pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3342
3343         set_canvas_cursor (_cursors->wait);
3344
3345         while (!itt.done && !itt.cancel) {
3346                 gtk_main_iteration ();
3347         }
3348
3349         current_interthread_info = 0;
3350         set_canvas_cursor (current_canvas_cursor);
3351 }
3352
3353 void
3354 Editor::bounce_range_selection (bool replace, bool enable_processing)
3355 {
3356         if (selection->time.empty()) {
3357                 return;
3358         }
3359
3360         TrackSelection views = selection->tracks;
3361
3362         for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3363                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3364                 if (rtv && !rtv->track()->bounceable()) {
3365                         MessageDialog d (
3366                                 _("One or more selected tracks cannot be bounced because it has more outputs than inputs.  "
3367                                   "You can fix this by increasing the number of inputs on that track.")
3368                                 );
3369                         d.set_title (_("Cannot bounce"));
3370                         d.run ();
3371                         return;
3372                 }
3373         }
3374
3375         framepos_t start = selection->time[clicked_selection].start;
3376         framepos_t end = selection->time[clicked_selection].end;
3377         framepos_t cnt = end - start + 1;
3378
3379         begin_reversible_command (_("bounce range"));
3380
3381         for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3382
3383                 RouteTimeAxisView* rtv;
3384
3385                 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3386                         continue;
3387                 }
3388
3389                 boost::shared_ptr<Playlist> playlist;
3390
3391                 if ((playlist = rtv->playlist()) == 0) {
3392                         return;
3393                 }
3394
3395                 InterThreadInfo itt;
3396
3397                 playlist->clear_changes ();
3398                 playlist->clear_owned_changes ();
3399                 
3400                 boost::shared_ptr<Region> r = rtv->track()->bounce_range (start, start+cnt, itt, enable_processing);
3401
3402                 if (replace) {
3403                         list<AudioRange> ranges;
3404                         ranges.push_back (AudioRange (start, start+cnt, 0));
3405                         playlist->cut (ranges); // discard result
3406                         playlist->add_region (r, start);
3407                 }
3408
3409                 vector<Command*> cmds;
3410                 playlist->rdiff (cmds);
3411                 _session->add_commands (cmds);
3412
3413                 _session->add_command (new StatefulDiffCommand (playlist));
3414         }
3415
3416         commit_reversible_command ();
3417 }
3418
3419 /** Cut selected regions, automation points or a time range */
3420 void
3421 Editor::cut ()
3422 {
3423         cut_copy (Cut);
3424 }
3425
3426 /** Copy selected regions, automation points or a time range */
3427 void
3428 Editor::copy ()
3429 {
3430         cut_copy (Copy);
3431 }
3432
3433
3434 /** @return true if a Cut, Copy or Clear is possible */
3435 bool
3436 Editor::can_cut_copy () const
3437 {
3438         switch (current_mouse_mode()) {
3439
3440         case MouseObject:
3441                 if (!selection->regions.empty() || !selection->points.empty()) {
3442                         return true;
3443                 }
3444                 break;
3445
3446         case MouseRange:
3447                 if (!selection->time.empty()) {
3448                         return true;
3449                 }
3450                 break;
3451
3452         default:
3453                 break;
3454         }
3455
3456         return false;
3457 }
3458
3459
3460 /** Cut, copy or clear selected regions, automation points or a time range.
3461  * @param op Operation (Cut, Copy or Clear)
3462  */
3463 void
3464 Editor::cut_copy (CutCopyOp op)
3465 {
3466         /* only cancel selection if cut/copy is successful.*/
3467
3468         string opname;
3469
3470         switch (op) {
3471         case Cut:
3472                 opname = _("cut");
3473                 break;
3474         case Copy:
3475                 opname = _("copy");
3476                 break;
3477         case Clear:
3478                 opname = _("clear");
3479                 break;
3480         }
3481
3482         /* if we're deleting something, and the mouse is still pressed,
3483            the thing we started a drag for will be gone when we release
3484            the mouse button(s). avoid this. see part 2 at the end of
3485            this function.
3486         */
3487
3488         if (op == Cut || op == Clear) {
3489                 if (_drags->active ()) {
3490                         _drags->abort ();
3491                 }
3492         }
3493
3494         cut_buffer->clear ();
3495
3496         if (entered_marker) {
3497
3498                 /* cut/delete op while pointing at a marker */
3499
3500                 bool ignored;
3501                 Location* loc = find_location_from_marker (entered_marker, ignored);
3502
3503                 if (_session && loc) {
3504                         Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3505                 }
3506
3507                 _drags->abort ();
3508                 return;
3509         }
3510
3511         if (internal_editing()) {
3512
3513                 switch (current_mouse_mode()) {
3514                 case MouseObject:
3515                 case MouseRange:
3516                         cut_copy_midi (op);
3517                         break;
3518                 default:
3519                         break;
3520                 }
3521
3522         } else {
3523
3524                 RegionSelection rs;
3525
3526                 /* we only want to cut regions if some are selected */
3527
3528                 if (!selection->regions.empty()) {
3529                         rs = selection->regions;
3530                 }
3531
3532                 switch (current_mouse_mode()) {
3533                 case MouseObject:
3534                         if (!rs.empty() || !selection->points.empty()) {
3535
3536                                 begin_reversible_command (opname + _(" objects"));
3537
3538                                 if (!rs.empty()) {
3539                                         cut_copy_regions (op, rs);
3540
3541                                         if (op == Cut) {
3542                                                 selection->clear_regions ();
3543                                         }
3544                                 }
3545
3546                                 if (!selection->points.empty()) {
3547                                         cut_copy_points (op);
3548
3549                                         if (op == Cut) {
3550                                                 selection->clear_points ();
3551                                         }
3552                                 }
3553
3554                                 commit_reversible_command ();
3555                                 break; // terminate case statement here
3556                         }
3557                         if (!selection->time.empty()) {
3558                                 /* don't cause suprises */
3559                                 break;
3560                         }
3561                         // fall thru if there was nothing selected
3562
3563                 case MouseRange:
3564                         if (selection->time.empty()) {
3565                                 framepos_t start, end;
3566                                 if (!get_edit_op_range (start, end)) {
3567                                         return;
3568                                 }
3569                                 selection->set (start, end);
3570                         }
3571
3572                         begin_reversible_command (opname + _(" range"));
3573                         cut_copy_ranges (op);
3574                         commit_reversible_command ();
3575
3576                         if (op == Cut) {
3577                                 selection->clear_time ();
3578                         }
3579
3580                         break;
3581
3582                 default:
3583                         break;
3584                 }
3585         }
3586
3587         if (op == Cut || op == Clear) {
3588                 _drags->abort ();
3589         }
3590 }
3591
3592 /** Cut, copy or clear selected automation points.
3593  * @param op Operation (Cut, Copy or Clear)
3594  */
3595 void
3596 Editor::cut_copy_points (CutCopyOp op)
3597 {
3598         for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3599
3600                 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>((*i).track);
3601
3602                 if (atv) {
3603                         atv->cut_copy_clear_objects (selection->points, op);
3604                 }
3605         }
3606 }
3607
3608 /** Cut, copy or clear selected automation points.
3609  * @param op Operation (Cut, Copy or Clear)
3610  */
3611 void
3612 Editor::cut_copy_midi (CutCopyOp op)
3613 {
3614         for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
3615                 MidiRegionView* mrv = *i;
3616                 mrv->cut_copy_clear (op);
3617         }
3618 }
3619
3620
3621
3622 struct lt_playlist {
3623     bool operator () (const PlaylistState& a, const PlaylistState& b) {
3624             return a.playlist < b.playlist;
3625     }
3626 };
3627
3628 struct PlaylistMapping {
3629     TimeAxisView* tv;
3630     boost::shared_ptr<Playlist> pl;
3631
3632     PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
3633 };
3634
3635 /** Remove `clicked_regionview' */
3636 void
3637 Editor::remove_clicked_region ()
3638 {
3639         if (clicked_routeview == 0 || clicked_regionview == 0) {
3640                 return;
3641         }
3642
3643         boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
3644
3645         begin_reversible_command (_("remove region"));
3646         playlist->clear_changes ();
3647         playlist->remove_region (clicked_regionview->region());
3648         _session->add_command(new StatefulDiffCommand (playlist));
3649         commit_reversible_command ();
3650 }
3651
3652
3653 /** Remove the selected regions */
3654 void
3655 Editor::remove_selected_regions ()
3656 {
3657         RegionSelection rs = get_regions_from_selection_and_entered ();
3658
3659         if (!_session || rs.empty()) {
3660                 return;
3661         }
3662
3663         begin_reversible_command (_("remove region"));
3664
3665         list<boost::shared_ptr<Region> > regions_to_remove;
3666
3667         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3668                 // we can't just remove the region(s) in this loop because
3669                 // this removes them from the RegionSelection, and they thus
3670                 // disappear from underneath the iterator, and the ++i above
3671                 // SEGVs in a puzzling fashion.
3672
3673                 // so, first iterate over the regions to be removed from rs and
3674                 // add them to the regions_to_remove list, and then
3675                 // iterate over the list to actually remove them.
3676
3677                 regions_to_remove.push_back ((*i)->region());
3678         }
3679
3680         vector<boost::shared_ptr<Playlist> > playlists;
3681
3682         for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3683
3684                 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3685
3686                 if (!playlist) {
3687                         // is this check necessary?
3688                         continue;
3689                 }
3690
3691                 vector<boost::shared_ptr<Playlist> >::iterator i;
3692
3693                 //only prep history if this is a new playlist.
3694                 for (i = playlists.begin(); i != playlists.end(); ++i) {
3695                         if ((*i) == playlist) {
3696                                 break;
3697                         }
3698                 }
3699
3700                 if (i == playlists.end()) {
3701
3702                         playlist->clear_changes ();
3703                         playlist->freeze ();
3704
3705                         playlists.push_back (playlist);
3706                 }
3707
3708                 playlist->remove_region (*rl);
3709         }
3710
3711         vector<boost::shared_ptr<Playlist> >::iterator pl;
3712
3713         for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3714                 (*pl)->thaw ();
3715                 _session->add_command(new StatefulDiffCommand (*pl));
3716         }
3717
3718         commit_reversible_command ();
3719 }
3720
3721 /** Cut, copy or clear selected regions.
3722  * @param op Operation (Cut, Copy or Clear)
3723  */
3724 void
3725 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
3726 {
3727         /* we can't use a std::map here because the ordering is important, and we can't trivially sort
3728            a map when we want ordered access to both elements. i think.
3729         */
3730
3731         vector<PlaylistMapping> pmap;
3732
3733         framepos_t first_position = max_framepos;
3734
3735         typedef set<boost::shared_ptr<Playlist> > FreezeList;
3736         FreezeList freezelist;
3737
3738         /* get ordering correct before we cut/copy */
3739
3740         rs.sort_by_position_and_track ();
3741
3742         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3743
3744                 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
3745
3746                 if (op == Cut || op == Clear) {
3747                         boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
3748
3749                         if (pl) {
3750                                 FreezeList::iterator fl;
3751
3752                                 //only take state if this is a new playlist.
3753                                 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
3754                                         if ((*fl) == pl) {
3755                                                 break;
3756                                         }
3757                                 }
3758
3759                                 if (fl == freezelist.end()) {
3760                                         pl->clear_changes();
3761                                         pl->freeze ();
3762                                         freezelist.insert (pl);
3763                                 }
3764                         }
3765                 }
3766
3767                 TimeAxisView* tv = &(*x)->get_time_axis_view();
3768                 vector<PlaylistMapping>::iterator z;
3769
3770                 for (z = pmap.begin(); z != pmap.end(); ++z) {
3771                         if ((*z).tv == tv) {
3772                                 break;
3773                         }
3774                 }
3775
3776                 if (z == pmap.end()) {
3777                         pmap.push_back (PlaylistMapping (tv));
3778                 }
3779         }
3780
3781         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
3782
3783                 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
3784
3785                 if (!pl) {
3786                         /* region not yet associated with a playlist (e.g. unfinished
3787                            capture pass.
3788                         */
3789                         ++x;
3790                         continue;
3791                 }
3792
3793                 TimeAxisView& tv = (*x)->get_time_axis_view();
3794                 boost::shared_ptr<Playlist> npl;
3795                 RegionSelection::iterator tmp;
3796
3797                 tmp = x;
3798                 ++tmp;
3799
3800                 vector<PlaylistMapping>::iterator z;
3801
3802                 for (z = pmap.begin(); z != pmap.end(); ++z) {
3803                         if ((*z).tv == &tv) {
3804                                 break;
3805                         }
3806                 }
3807
3808                 assert (z != pmap.end());
3809
3810                 if (!(*z).pl) {
3811                         npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
3812                         npl->freeze();
3813                         (*z).pl = npl;
3814                 } else {
3815                         npl = (*z).pl;
3816                 }
3817
3818                 boost::shared_ptr<Region> r = (*x)->region();
3819                 boost::shared_ptr<Region> _xx;
3820
3821                 assert (r != 0);
3822
3823                 switch (op) {
3824                 case Cut:
3825                         _xx = RegionFactory::create (r);
3826                         npl->add_region (_xx, r->position() - first_position);
3827                         pl->remove_region (r);
3828                         break;
3829
3830                 case Copy:
3831                         /* copy region before adding, so we're not putting same object into two different playlists */
3832                         npl->add_region (RegionFactory::create (r), r->position() - first_position);
3833                         break;
3834
3835                 case Clear:
3836                         pl->remove_region (r);
3837                         break;
3838                 }
3839
3840                 x = tmp;
3841         }
3842
3843         list<boost::shared_ptr<Playlist> > foo;
3844
3845         /* the pmap is in the same order as the tracks in which selected regions occured */
3846
3847         for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
3848                 if ((*i).pl) {
3849                         (*i).pl->thaw();
3850                         foo.push_back ((*i).pl);
3851                 }
3852         }
3853
3854         if (!foo.empty()) {
3855                 cut_buffer->set (foo);
3856         }
3857
3858         if (pmap.empty()) {
3859                 _last_cut_copy_source_track = 0;
3860         } else {
3861                 _last_cut_copy_source_track = pmap.front().tv;
3862         }
3863         
3864         for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
3865                 (*pl)->thaw ();
3866                 _session->add_command (new StatefulDiffCommand (*pl));
3867         }
3868 }
3869
3870 void
3871 Editor::cut_copy_ranges (CutCopyOp op)
3872 {
3873         TrackViewList* ts;
3874         TrackViewList entered;
3875
3876         if (selection->tracks.empty()) {
3877                 if (!entered_track) {
3878                         return;
3879                 }
3880                 entered.push_back (entered_track);
3881                 ts = &entered;
3882         } else {
3883                 ts = &selection->tracks;
3884         }
3885
3886         for (TrackSelection::iterator i = ts->begin(); i != ts->end(); ++i) {
3887                 (*i)->cut_copy_clear (*selection, op);
3888         }
3889 }
3890
3891 void
3892 Editor::paste (float times)
3893 {
3894         DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
3895         paste_internal (get_preferred_edit_position(), times);
3896 }
3897
3898 void
3899 Editor::mouse_paste ()
3900 {
3901         framepos_t where;
3902         bool ignored;
3903
3904         if (!mouse_frame (where, ignored)) {
3905                 return;
3906         }
3907
3908         snap_to (where);
3909         paste_internal (where, 1);
3910 }
3911
3912 void
3913 Editor::paste_internal (framepos_t position, float times)
3914 {
3915         DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
3916
3917         if (internal_editing()) {
3918                 if (cut_buffer->midi_notes.empty()) {
3919                         return;
3920                 }
3921         } else {
3922                 if (cut_buffer->empty()) {
3923                         return;
3924                 }
3925         }
3926
3927         if (position == max_framepos) {
3928                 position = get_preferred_edit_position();
3929                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
3930         }
3931
3932         TrackViewList ts;
3933         TrackViewList::iterator i;
3934         size_t nth;
3935
3936         /* get everything in the correct order */
3937
3938         if (!selection->tracks.empty()) {
3939                 /* there are some selected tracks, so paste to them */
3940                 sort_track_selection ();
3941                 ts = selection->tracks;
3942         } else if (_last_cut_copy_source_track) {
3943                 /* otherwise paste to the track that the cut/copy came from;
3944                    see discussion in mants #3333.
3945                 */
3946                 ts.push_back (_last_cut_copy_source_track);
3947         }
3948
3949         if (internal_editing ()) {
3950
3951                 /* undo/redo is handled by individual tracks/regions */
3952                 
3953                 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
3954                         
3955                         RegionSelection rs;
3956                         RegionSelection::iterator r;
3957                         MidiNoteSelection::iterator cb;
3958                         
3959                         get_regions_at (rs, position, ts);
3960                         
3961                         for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
3962                              cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
3963                                 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
3964                                 if (mrv) {
3965                                         mrv->paste (position, times, **cb);
3966                                         ++cb;
3967                                 }
3968                         }
3969                 }
3970                 
3971         } else {
3972
3973                 /* we do redo (do you do voodoo?) */
3974
3975                 begin_reversible_command (Operations::paste);
3976                 
3977                 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
3978                         (*i)->paste (position, times, *cut_buffer, nth);
3979                 }
3980                 
3981                 commit_reversible_command ();
3982         }
3983 }
3984
3985 void
3986 Editor::duplicate_some_regions (RegionSelection& regions, float times)
3987 {
3988         boost::shared_ptr<Playlist> playlist;
3989         RegionSelection sel = regions; // clear (below) may  clear the argument list if its the current region selection
3990         RegionSelection foo;
3991
3992         framepos_t const start_frame = regions.start ();
3993         framepos_t const end_frame = regions.end_frame ();
3994
3995         begin_reversible_command (Operations::duplicate_region);
3996
3997         selection->clear_regions ();
3998
3999         for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4000
4001                 boost::shared_ptr<Region> r ((*i)->region());
4002
4003                 TimeAxisView& tv = (*i)->get_time_axis_view();
4004                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4005                 latest_regionviews.clear ();
4006                 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4007
4008                 playlist = (*i)->region()->playlist();
4009                 playlist->clear_changes ();
4010                 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4011                 _session->add_command(new StatefulDiffCommand (playlist));
4012
4013                 c.disconnect ();
4014
4015                 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4016         }
4017
4018         commit_reversible_command ();
4019
4020         if (!foo.empty()) {
4021                 selection->set (foo);
4022         }
4023 }
4024
4025 void
4026 Editor::duplicate_selection (float times)
4027 {
4028         if (selection->time.empty() || selection->tracks.empty()) {
4029                 return;
4030         }
4031
4032         boost::shared_ptr<Playlist> playlist;
4033         vector<boost::shared_ptr<Region> > new_regions;
4034         vector<boost::shared_ptr<Region> >::iterator ri;
4035
4036         create_region_from_selection (new_regions);
4037
4038         if (new_regions.empty()) {
4039                 return;
4040         }
4041
4042         begin_reversible_command (_("duplicate selection"));
4043
4044         ri = new_regions.begin();
4045
4046         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4047                 if ((playlist = (*i)->playlist()) == 0) {
4048                         continue;
4049                 }
4050                 playlist->clear_changes ();
4051                 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4052                 _session->add_command (new StatefulDiffCommand (playlist));
4053
4054                 ++ri;
4055                 if (ri == new_regions.end()) {
4056                         --ri;
4057                 }
4058         }
4059
4060         commit_reversible_command ();
4061 }
4062
4063 void
4064 Editor::reset_point_selection ()
4065 {
4066         /* reset all selected points to the relevant default value */
4067
4068         for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4069
4070                 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>((*i).track);
4071
4072                 if (atv) {
4073                         atv->reset_objects (selection->points);
4074                 }
4075         }
4076 }
4077
4078 void
4079 Editor::center_playhead ()
4080 {
4081         float page = _canvas_width * frames_per_unit;
4082         center_screen_internal (playhead_cursor->current_frame, page);
4083 }
4084
4085 void
4086 Editor::center_edit_point ()
4087 {
4088         float page = _canvas_width * frames_per_unit;
4089         center_screen_internal (get_preferred_edit_position(), page);
4090 }
4091
4092 /** Caller must begin and commit a reversible command */
4093 void
4094 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4095 {
4096         playlist->clear_changes ();
4097         playlist->clear ();
4098         _session->add_command (new StatefulDiffCommand (playlist));
4099 }
4100
4101 void
4102 Editor::nudge_track (bool use_edit, bool forwards)
4103 {
4104         boost::shared_ptr<Playlist> playlist;
4105         framepos_t distance;
4106         framepos_t next_distance;
4107         framepos_t start;
4108
4109         if (use_edit) {
4110                 start = get_preferred_edit_position();
4111         } else {
4112                 start = 0;
4113         }
4114
4115         if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4116                 return;
4117         }
4118
4119         if (selection->tracks.empty()) {
4120                 return;
4121         }
4122
4123         begin_reversible_command (_("nudge track"));
4124
4125         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4126
4127                 if ((playlist = (*i)->playlist()) == 0) {
4128                         continue;
4129                 }
4130
4131                 playlist->clear_changes ();
4132                 playlist->clear_owned_changes ();
4133
4134                 playlist->nudge_after (start, distance, forwards);
4135                 
4136                 vector<Command*> cmds;
4137                 
4138                 playlist->rdiff (cmds);
4139                 _session->add_commands (cmds);
4140                 
4141                 _session->add_command (new StatefulDiffCommand (playlist));
4142         }
4143
4144         commit_reversible_command ();
4145 }
4146
4147 void
4148 Editor::remove_last_capture ()
4149 {
4150         vector<string> choices;
4151         string prompt;
4152
4153         if (!_session) {
4154                 return;
4155         }
4156
4157         if (Config->get_verify_remove_last_capture()) {
4158                 prompt  = _("Do you really want to destroy the last capture?"
4159                             "\n(This is destructive and cannot be undone)");
4160
4161                 choices.push_back (_("No, do nothing."));
4162                 choices.push_back (_("Yes, destroy it."));
4163
4164                 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4165
4166                 if (prompter.run () == 1) {
4167                         _session->remove_last_capture ();
4168                         _regions->redisplay ();
4169                 }
4170
4171         } else {
4172                 _session->remove_last_capture();
4173                 _regions->redisplay ();
4174         }
4175 }
4176
4177 void
4178 Editor::normalize_region ()
4179 {
4180         if (!_session) {
4181                 return;
4182         }
4183
4184         RegionSelection rs = get_regions_from_selection_and_entered ();
4185         
4186         if (rs.empty()) {
4187                 return;
4188         }
4189
4190         NormalizeDialog dialog (rs.size() > 1);
4191
4192         if (dialog.run () == RESPONSE_CANCEL) {
4193                 return;
4194         }
4195
4196         set_canvas_cursor (_cursors->wait);
4197         gdk_flush ();
4198
4199         /* XXX: should really only count audio regions here */
4200         int const regions = rs.size ();
4201
4202         /* Make a list of the selected audio regions' maximum amplitudes, and also
4203            obtain the maximum amplitude of them all.
4204         */
4205         list<double> max_amps;
4206         double max_amp = 0;
4207         for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4208                 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4209                 if (arv) {
4210                         dialog.descend (1.0 / regions);
4211                         double const a = arv->audio_region()->maximum_amplitude (&dialog);
4212
4213                         if (a == -1) {
4214                                 /* the user cancelled the operation */
4215                                 set_canvas_cursor (current_canvas_cursor);
4216                                 return;
4217                         }
4218                         
4219                         max_amps.push_back (a);
4220                         max_amp = max (max_amp, a);
4221                         dialog.ascend ();
4222                 }
4223         }
4224
4225         begin_reversible_command (_("normalize"));
4226
4227         list<double>::const_iterator a = max_amps.begin ();
4228         
4229         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4230                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4231                 if (!arv) {
4232                         continue;
4233                 }
4234
4235                 arv->region()->clear_changes ();
4236
4237                 double const amp = dialog.normalize_individually() ? *a : max_amp;
4238                 
4239                 arv->audio_region()->normalize (amp, dialog.target ());
4240                 _session->add_command (new StatefulDiffCommand (arv->region()));
4241
4242                 ++a;
4243         }
4244
4245         commit_reversible_command ();
4246         set_canvas_cursor (current_canvas_cursor);
4247 }
4248
4249
4250 void
4251 Editor::reset_region_scale_amplitude ()
4252 {
4253         if (!_session) {
4254                 return;
4255         }
4256
4257         RegionSelection rs = get_regions_from_selection_and_entered ();
4258
4259         if (rs.empty()) {
4260                 return;
4261         }
4262
4263         begin_reversible_command ("reset gain");
4264
4265         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4266                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4267                 if (!arv)
4268                         continue;
4269                 arv->region()->clear_changes ();
4270                 arv->audio_region()->set_scale_amplitude (1.0f);
4271                 _session->add_command (new StatefulDiffCommand (arv->region()));
4272         }
4273
4274         commit_reversible_command ();
4275 }
4276
4277 void
4278 Editor::adjust_region_gain (bool up)
4279 {
4280         RegionSelection rs = get_regions_from_selection_and_entered ();
4281
4282         if (!_session || rs.empty()) {
4283                 return;
4284         }
4285
4286         begin_reversible_command ("adjust region gain");
4287
4288         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4289                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4290                 if (!arv) {
4291                         continue;
4292                 }
4293
4294                 arv->region()->clear_changes ();
4295
4296                 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4297
4298                 if (up) {
4299                         dB += 1;
4300                 } else {
4301                         dB -= 1;
4302                 }
4303
4304                 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4305                 _session->add_command (new StatefulDiffCommand (arv->region()));
4306         }
4307
4308         commit_reversible_command ();
4309 }
4310
4311
4312 void
4313 Editor::reverse_region ()
4314 {
4315         if (!_session) {
4316                 return;
4317         }
4318
4319         Reverse rev (*_session);
4320         apply_filter (rev, _("reverse regions"));
4321 }
4322
4323 void
4324 Editor::strip_region_silence ()
4325 {
4326         if (!_session) {
4327                 return;
4328         }
4329
4330         RegionSelection rs = get_regions_from_selection_and_entered ();
4331
4332         if (rs.empty()) {
4333                 return;
4334         }
4335
4336         std::list<RegionView*> audio_only;
4337
4338         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4339                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4340                 if (arv) {
4341                         audio_only.push_back (arv);
4342                 }
4343         }
4344
4345         StripSilenceDialog d (_session, audio_only);
4346         int const r = d.run ();
4347
4348         d.drop_rects ();
4349         
4350         if (r == Gtk::RESPONSE_OK) {
4351                 ARDOUR::AudioIntervalMap silences;
4352                 d.silences (silences);
4353                 StripSilence s (*_session, silences, d.fade_length());
4354                 apply_filter (s, _("strip silence"), &d);
4355         } 
4356 }
4357
4358 Command*
4359 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4360 {
4361         Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4362         mrv.selection_as_notelist (selected, true);
4363
4364         vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4365         v.push_back (selected);
4366
4367         return op (mrv.midi_region()->model(), v);
4368 }
4369
4370 void
4371 Editor::apply_midi_note_edit_op (MidiOperator& op)
4372 {
4373         Command* cmd;
4374
4375         RegionSelection rs = get_regions_from_selection_and_entered ();
4376
4377         if (rs.empty()) {
4378                 return;
4379         }
4380
4381         begin_reversible_command (op.name ());
4382
4383         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4384                 RegionSelection::iterator tmp = r;
4385                 ++tmp;
4386
4387                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4388
4389                 if (mrv) {
4390                         cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4391                         if (cmd) {
4392                                 (*cmd)();
4393                                 _session->add_command (cmd);
4394                         }
4395                 }
4396
4397                 r = tmp;
4398         }
4399
4400         commit_reversible_command ();
4401 }
4402
4403 void
4404 Editor::fork_region ()
4405 {
4406         RegionSelection rs = get_regions_from_selection_and_entered ();
4407
4408         if (rs.empty()) {
4409                 return;
4410         }
4411
4412         begin_reversible_command (_("Fork Region(s)"));
4413
4414         set_canvas_cursor (_cursors->wait);
4415         gdk_flush ();
4416
4417         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4418                 RegionSelection::iterator tmp = r;
4419                 ++tmp;
4420
4421                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4422
4423                 if (mrv) {
4424                         boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4425                         boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone ();
4426                         
4427                         playlist->clear_changes ();
4428                         playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4429                         _session->add_command(new StatefulDiffCommand (playlist));
4430                 }
4431
4432                 r = tmp;
4433         }
4434
4435         commit_reversible_command ();
4436
4437         set_canvas_cursor (current_canvas_cursor);
4438 }
4439
4440 void
4441 Editor::quantize_region ()
4442 {
4443         int selected_midi_region_cnt = 0;
4444
4445         if (!_session) {
4446                 return;
4447         }
4448
4449         RegionSelection rs = get_regions_from_selection_and_entered ();
4450
4451         if (rs.empty()) {
4452                 return;
4453         }
4454
4455         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4456                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4457                 if (mrv) {
4458                         selected_midi_region_cnt++;
4459                 }
4460         }
4461
4462         if (selected_midi_region_cnt == 0) {
4463                 return;
4464         }
4465
4466         QuantizeDialog* qd = new QuantizeDialog (*this);
4467
4468         qd->present ();
4469         const int r = qd->run ();
4470         qd->hide ();
4471
4472         if (r == Gtk::RESPONSE_OK) {
4473                 Quantize quant (*_session, Plain,
4474                                 qd->snap_start(), qd->snap_end(),
4475                                 qd->start_grid_size(), qd->end_grid_size(),
4476                                 qd->strength(), qd->swing(), qd->threshold());
4477
4478                 apply_midi_note_edit_op (quant);
4479         }
4480 }
4481
4482 void
4483 Editor::insert_patch_change ()
4484 {
4485         RegionSelection rs = get_regions_from_selection_and_entered ();
4486         if (rs.empty ()) {
4487                 return;
4488         }
4489
4490         framepos_t const p = get_preferred_edit_position (false);
4491
4492         Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4493         PatchChangeDialog d (0, _session, empty, Gtk::Stock::ADD);
4494         
4495         if (d.run() == RESPONSE_CANCEL) {
4496                 return;
4497         }
4498
4499         for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4500                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4501                 if (mrv) {
4502                         if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4503                                 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4504                         }
4505                 }
4506         }
4507 }
4508
4509 void
4510 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4511 {
4512         RegionSelection rs = get_regions_from_selection_and_entered ();
4513
4514         if (rs.empty()) {
4515                 return;
4516         }
4517
4518         begin_reversible_command (command);
4519
4520         set_canvas_cursor (_cursors->wait);
4521         gdk_flush ();
4522
4523         int n = 0;
4524         int const N = rs.size ();
4525         
4526         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4527                 RegionSelection::iterator tmp = r;
4528                 ++tmp;
4529
4530                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4531                 if (arv) {
4532                         boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4533
4534                         if (progress) {
4535                                 progress->descend (1.0 / N);
4536                         }
4537
4538                         if (arv->audio_region()->apply (filter, progress) == 0) {
4539
4540                                 playlist->clear_changes ();
4541
4542                                 if (filter.results.empty ()) {
4543
4544                                         /* no regions returned; remove the old one */
4545                                         playlist->remove_region (arv->region ());
4546
4547                                 } else {
4548
4549                                         std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
4550
4551                                         /* first region replaces the old one */
4552                                         playlist->replace_region (arv->region(), *res, (*res)->position());
4553                                         ++res;
4554
4555                                         /* add the rest */
4556                                         while (res != filter.results.end()) {
4557                                                 playlist->add_region (*res, (*res)->position());
4558                                                 ++res;
4559                                         }
4560
4561                                 }
4562
4563                                 _session->add_command(new StatefulDiffCommand (playlist));
4564                         } else {
4565                                 goto out;
4566                         }
4567
4568                         if (progress) {
4569                                 progress->ascend ();
4570                         }
4571                 }
4572
4573                 r = tmp;
4574                 ++n;
4575         }
4576
4577         commit_reversible_command ();
4578
4579   out:
4580         set_canvas_cursor (current_canvas_cursor);
4581 }
4582
4583 void
4584 Editor::external_edit_region ()
4585 {
4586         /* more to come */
4587 }
4588
4589 void
4590 Editor::reset_region_gain_envelopes ()
4591 {
4592         RegionSelection rs = get_regions_from_selection_and_entered ();
4593
4594         if (!_session || rs.empty()) {
4595                 return;
4596         }
4597
4598         _session->begin_reversible_command (_("reset region gain"));
4599
4600         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4601                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
4602                 if (arv) {
4603                         boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
4604                         XMLNode& before (alist->get_state());
4605
4606                         arv->audio_region()->set_default_envelope ();
4607                         _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
4608                 }
4609         }
4610
4611         _session->commit_reversible_command ();
4612 }
4613
4614 void
4615 Editor::toggle_gain_envelope_visibility ()
4616 {
4617         if (_ignore_region_action) {
4618                 return;
4619         }
4620         
4621         RegionSelection rs = get_regions_from_selection_and_entered ();
4622
4623         if (!_session || rs.empty()) {
4624                 return;
4625         }
4626
4627         _session->begin_reversible_command (_("region gain envelope visible"));
4628
4629         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4630                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
4631                 if (arv) {
4632                         arv->region()->clear_changes ();
4633                         arv->set_envelope_visible (!arv->envelope_visible());
4634                         _session->add_command (new StatefulDiffCommand (arv->region()));
4635                 }
4636         }
4637
4638         _session->commit_reversible_command ();
4639 }
4640
4641 void
4642 Editor::toggle_gain_envelope_active ()
4643 {
4644         if (_ignore_region_action) {
4645                 return;
4646         }
4647         
4648         RegionSelection rs = get_regions_from_selection_and_entered ();
4649
4650         if (!_session || rs.empty()) {
4651                 return;
4652         }
4653
4654         _session->begin_reversible_command (_("region gain envelope active"));
4655
4656         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4657                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
4658                 if (arv) {
4659                         arv->region()->clear_changes ();
4660                         arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
4661                         _session->add_command (new StatefulDiffCommand (arv->region()));
4662                 }
4663         }
4664
4665         _session->commit_reversible_command ();
4666 }
4667
4668 void
4669 Editor::toggle_region_lock ()
4670 {
4671         if (_ignore_region_action) {
4672                 return;
4673         }
4674
4675         RegionSelection rs = get_regions_from_selection_and_entered ();
4676
4677         if (!_session || rs.empty()) {
4678                 return;
4679         }
4680
4681         _session->begin_reversible_command (_("toggle region lock"));
4682
4683         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4684                 (*i)->region()->clear_changes ();
4685                 (*i)->region()->set_locked (!(*i)->region()->locked());
4686                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
4687         }
4688
4689         _session->commit_reversible_command ();
4690 }
4691
4692 void
4693 Editor::toggle_region_lock_style ()
4694 {
4695         if (_ignore_region_action) {
4696                 return;
4697         }
4698         
4699         RegionSelection rs = get_regions_from_selection_and_entered ();
4700
4701         if (!_session || rs.empty()) {
4702                 return;
4703         }
4704
4705         _session->begin_reversible_command (_("region lock style"));
4706
4707         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4708                 (*i)->region()->clear_changes ();
4709                 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
4710                 (*i)->region()->set_position_lock_style (ns);
4711                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
4712         }
4713
4714         _session->commit_reversible_command ();
4715 }
4716
4717 void
4718 Editor::toggle_opaque_region ()
4719 {
4720         if (_ignore_region_action) {
4721                 return;
4722         }
4723         
4724         RegionSelection rs = get_regions_from_selection_and_entered ();
4725
4726         if (!_session || rs.empty()) {
4727                 return;
4728         }
4729
4730         _session->begin_reversible_command (_("change region opacity"));
4731
4732         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4733                 (*i)->region()->clear_changes ();
4734                 (*i)->region()->set_opaque (!(*i)->region()->opaque());
4735                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
4736         }
4737
4738         _session->commit_reversible_command ();
4739 }
4740
4741 void
4742 Editor::toggle_record_enable ()
4743 {
4744         bool new_state = false;
4745         bool first = true;
4746         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4747                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
4748                 if (!rtav)
4749                         continue;
4750                 if (!rtav->is_track())
4751                         continue;
4752
4753                 if (first) {
4754                         new_state = !rtav->track()->record_enabled();
4755                         first = false;
4756                 }
4757
4758                 rtav->track()->set_record_enabled (new_state, this);
4759         }
4760 }
4761
4762
4763 void
4764 Editor::set_fade_length (bool in)
4765 {
4766         RegionSelection rs = get_regions_from_selection_and_entered ();
4767
4768         if (rs.empty()) {
4769                 return;
4770         }
4771
4772         /* we need a region to measure the offset from the start */
4773
4774         RegionView* rv = rs.front ();
4775
4776         framepos_t pos = get_preferred_edit_position();
4777         framepos_t len;
4778         char const * cmd;
4779
4780         if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
4781                 /* edit point is outside the relevant region */
4782                 return;
4783         }
4784
4785         if (in) {
4786                 if (pos <= rv->region()->position()) {
4787                         /* can't do it */
4788                         return;
4789                 }
4790                 len = pos - rv->region()->position();
4791                 cmd = _("set fade in length");
4792         } else {
4793                 if (pos >= rv->region()->last_frame()) {
4794                         /* can't do it */
4795                         return;
4796                 }
4797                 len = rv->region()->last_frame() - pos;
4798                 cmd = _("set fade out length");
4799         }
4800
4801         begin_reversible_command (cmd);
4802
4803         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4804                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
4805
4806                 if (!tmp) {
4807                         return;
4808                 }
4809
4810                 boost::shared_ptr<AutomationList> alist;
4811                 if (in) {
4812                         alist = tmp->audio_region()->fade_in();
4813                 } else {
4814                         alist = tmp->audio_region()->fade_out();
4815                 }
4816
4817                 XMLNode &before = alist->get_state();
4818
4819                 if (in) {
4820                         tmp->audio_region()->set_fade_in_length (len);
4821                         tmp->audio_region()->set_fade_in_active (true);
4822                 } else {
4823                         tmp->audio_region()->set_fade_out_length (len);
4824                         tmp->audio_region()->set_fade_out_active (true);
4825                 }
4826
4827                 XMLNode &after = alist->get_state();
4828                 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
4829         }
4830
4831         commit_reversible_command ();
4832 }
4833
4834 void
4835 Editor::set_fade_in_shape (FadeShape shape)
4836 {
4837         RegionSelection rs = get_regions_from_selection_and_entered ();
4838
4839         if (rs.empty()) {
4840                 return;
4841         }
4842
4843         begin_reversible_command (_("set fade in shape"));
4844
4845         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4846                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
4847
4848                 if (!tmp) {
4849                         return;
4850                 }
4851
4852                 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
4853                 XMLNode &before = alist->get_state();
4854
4855                 tmp->audio_region()->set_fade_in_shape (shape);
4856
4857                 XMLNode &after = alist->get_state();
4858                 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
4859         }
4860
4861         commit_reversible_command ();
4862
4863 }
4864
4865 void
4866 Editor::set_fade_out_shape (FadeShape shape)
4867 {
4868         RegionSelection rs = get_regions_from_selection_and_entered ();
4869
4870         if (rs.empty()) {
4871                 return;
4872         }
4873
4874         begin_reversible_command (_("set fade out shape"));
4875
4876         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4877                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
4878
4879                 if (!tmp) {
4880                         return;
4881                 }
4882
4883                 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
4884                 XMLNode &before = alist->get_state();
4885
4886                 tmp->audio_region()->set_fade_out_shape (shape);
4887
4888                 XMLNode &after = alist->get_state();
4889                 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
4890         }
4891
4892         commit_reversible_command ();
4893 }
4894
4895 void
4896 Editor::set_fade_in_active (bool yn)
4897 {
4898         RegionSelection rs = get_regions_from_selection_and_entered ();
4899
4900         if (rs.empty()) {
4901                 return;
4902         }
4903
4904         begin_reversible_command (_("set fade in active"));
4905
4906         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4907                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
4908
4909                 if (!tmp) {
4910                         return;
4911                 }
4912
4913
4914                 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
4915                 
4916                 ar->clear_changes ();
4917                 ar->set_fade_in_active (yn);
4918                 _session->add_command (new StatefulDiffCommand (ar));
4919         }
4920
4921         commit_reversible_command ();
4922 }
4923
4924 void
4925 Editor::set_fade_out_active (bool yn)
4926 {
4927         RegionSelection rs = get_regions_from_selection_and_entered ();
4928
4929         if (rs.empty()) {
4930                 return;
4931         }
4932
4933         begin_reversible_command (_("set fade out active"));
4934
4935         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4936                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
4937
4938                 if (!tmp) {
4939                         return;
4940                 }
4941
4942                 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
4943
4944                 ar->clear_changes ();
4945                 ar->set_fade_out_active (yn);
4946                 _session->add_command(new StatefulDiffCommand (ar));
4947         }
4948
4949         commit_reversible_command ();
4950 }
4951
4952 void
4953 Editor::toggle_region_fades (int dir)
4954 {
4955         boost::shared_ptr<AudioRegion> ar;
4956         bool yn;
4957
4958         RegionSelection rs = get_regions_from_selection_and_entered ();
4959
4960         if (rs.empty()) {
4961                 return;
4962         }
4963
4964         RegionSelection::iterator i;    
4965         for (i = rs.begin(); i != rs.end(); ++i) {
4966                 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
4967                         if (dir == -1) {
4968                                 yn = ar->fade_out_active ();
4969                         } else {
4970                                 yn = ar->fade_in_active ();
4971                         }
4972                         break;
4973                 }
4974         }
4975
4976         if (i == rs.end()) {
4977                 return;
4978         }
4979
4980         /* XXX should this undo-able? */
4981
4982         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4983                 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
4984                         continue;
4985                 }
4986                 if (dir == 1 || dir == 0) {
4987                         ar->set_fade_in_active (!yn);
4988                 }
4989
4990                 if (dir == -1 || dir == 0) {
4991                         ar->set_fade_out_active (!yn);
4992                 }
4993         }
4994 }
4995
4996
4997 /** Update region fade visibility after its configuration has been changed */
4998 void
4999 Editor::update_region_fade_visibility ()
5000 {
5001         bool _fade_visibility = _session->config.get_show_region_fades ();
5002
5003         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5004                 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5005                 if (v) {
5006                         if (_fade_visibility) {
5007                                 v->audio_view()->show_all_fades ();
5008                         } else {
5009                                 v->audio_view()->hide_all_fades ();
5010                         }
5011                 }
5012         }
5013 }
5014
5015 /** Update crossfade visibility after its configuration has been changed */
5016 void
5017 Editor::update_xfade_visibility ()
5018 {
5019         _xfade_visibility = _session->config.get_xfades_visible ();
5020
5021         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5022                 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5023                 if (v) {
5024                         if (_xfade_visibility) {
5025                                 v->show_all_xfades ();
5026                         } else {
5027                                 v->hide_all_xfades ();
5028                         }
5029                 }
5030         }
5031 }
5032
5033 void
5034 Editor::set_edit_point ()
5035 {
5036         framepos_t where;
5037         bool ignored;
5038
5039         if (!mouse_frame (where, ignored)) {
5040                 return;
5041         }
5042
5043         snap_to (where);
5044
5045         if (selection->markers.empty()) {
5046
5047                 mouse_add_new_marker (where);
5048
5049         } else {
5050                 bool ignored;
5051
5052                 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5053
5054                 if (loc) {
5055                         loc->move_to (where);
5056                 }
5057         }
5058 }
5059
5060 void
5061 Editor::set_playhead_cursor ()
5062 {
5063         if (entered_marker) {
5064                 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5065         } else {
5066                 framepos_t where;
5067                 bool ignored;
5068
5069                 if (!mouse_frame (where, ignored)) {
5070                         return;
5071                 }
5072
5073                 snap_to (where);
5074
5075                 if (_session) {
5076                         _session->request_locate (where, _session->transport_rolling());
5077                 }
5078         }
5079 }
5080
5081 void
5082 Editor::split_region ()
5083 {
5084         if (((mouse_mode == MouseRange) || 
5085              (mouse_mode != MouseObject && _join_object_range_state == JOIN_OBJECT_RANGE_RANGE)) && 
5086             !selection->time.empty()) {
5087                 separate_regions_between (selection->time);
5088                 return;
5089         } 
5090
5091         RegionSelection rs = get_regions_from_selection_and_edit_point ();
5092
5093         framepos_t where = get_preferred_edit_position ();
5094
5095         if (rs.empty()) {
5096                 return;
5097         }
5098
5099         split_regions_at (where, rs);
5100 }
5101
5102 void
5103 Editor::ensure_entered_track_selected (bool op_really_wants_one_track_if_none_are_selected)
5104 {
5105         if (entered_track && mouse_mode == MouseObject) {
5106                 if (!selection->tracks.empty()) {
5107                         if (!selection->selected (entered_track)) {
5108                                 selection->add (entered_track);
5109                         }
5110                 } else {
5111                         /* there is no selection, but this operation requires/prefers selected objects */
5112
5113                         if (op_really_wants_one_track_if_none_are_selected) {
5114                                 selection->set (entered_track);
5115                         }
5116                 }
5117         }
5118 }
5119
5120 struct EditorOrderRouteSorter {
5121     bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5122             /* use of ">" forces the correct sort order */
5123             return a->order_key ("editor") < b->order_key ("editor");
5124     }
5125 };
5126
5127 void
5128 Editor::select_next_route()
5129 {
5130         if (selection->tracks.empty()) {
5131                 selection->set (track_views.front());
5132                 return;
5133         }
5134
5135         TimeAxisView* current = selection->tracks.front();
5136
5137         RouteUI *rui;
5138         do {
5139                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5140                         if (*i == current) {
5141                                 ++i;
5142                                 if (i != track_views.end()) {
5143                                         current = (*i);
5144                                 } else {
5145                                         current = (*(track_views.begin()));
5146                                         //selection->set (*(track_views.begin()));
5147                                 }
5148                                 break;
5149                         }
5150                 }
5151                 rui = dynamic_cast<RouteUI *>(current);
5152         } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5153
5154         selection->set(current);
5155
5156         ensure_track_visible(current);
5157 }
5158
5159 void
5160 Editor::select_prev_route()
5161 {
5162         if (selection->tracks.empty()) {
5163                 selection->set (track_views.front());
5164                 return;
5165         }
5166
5167         TimeAxisView* current = selection->tracks.front();
5168
5169         RouteUI *rui;
5170         do {
5171                 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5172                         if (*i == current) {
5173                                 ++i;
5174                                 if (i != track_views.rend()) {
5175                                         current = (*i);
5176                                 } else {
5177                                         current = *(track_views.rbegin());
5178                                 }
5179                                 break;
5180                         }
5181                 }
5182                 rui = dynamic_cast<RouteUI *>(current);
5183         } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5184
5185         selection->set (current);
5186
5187         ensure_track_visible(current);
5188 }
5189
5190 void
5191 Editor::ensure_track_visible(TimeAxisView *track)
5192 {
5193         if (track->hidden())
5194                 return;
5195
5196         double const current_view_min_y = vertical_adjustment.get_value();
5197         double const current_view_max_y = vertical_adjustment.get_value() + vertical_adjustment.get_page_size() - canvas_timebars_vsize;
5198
5199         double const track_min_y = track->y_position ();
5200         double const track_max_y = track->y_position () + track->effective_height ();
5201
5202         if (track_min_y >= current_view_min_y &&
5203             track_max_y <= current_view_max_y) {
5204                 return;
5205         }
5206
5207         double new_value;
5208
5209         if (track_min_y < current_view_min_y) {
5210                 // Track is above the current view
5211                 new_value = track_min_y;
5212         } else {
5213                 // Track is below the current view
5214                 new_value = track->y_position () + track->effective_height() + canvas_timebars_vsize - vertical_adjustment.get_page_size();
5215         }
5216
5217         vertical_adjustment.set_value(new_value);
5218 }
5219
5220 void
5221 Editor::set_loop_from_selection (bool play)
5222 {
5223         if (_session == 0 || selection->time.empty()) {
5224                 return;
5225         }
5226
5227         framepos_t start = selection->time[clicked_selection].start;
5228         framepos_t end = selection->time[clicked_selection].end;
5229
5230         set_loop_range (start, end,  _("set loop range from selection"));
5231
5232         if (play) {
5233                 _session->request_play_loop (true);
5234                 _session->request_locate (start, true);
5235         }
5236 }
5237
5238 void
5239 Editor::set_loop_from_edit_range (bool play)
5240 {
5241         if (_session == 0) {
5242                 return;
5243         }
5244
5245         framepos_t start;
5246         framepos_t end;
5247
5248         if (!get_edit_op_range (start, end)) {
5249                 return;
5250         }
5251
5252         set_loop_range (start, end,  _("set loop range from edit range"));
5253
5254         if (play) {
5255                 _session->request_play_loop (true);
5256                 _session->request_locate (start, true);
5257         }
5258 }
5259
5260 void
5261 Editor::set_loop_from_region (bool play)
5262 {
5263         framepos_t start = max_framepos;
5264         framepos_t end = 0;
5265
5266         RegionSelection rs = get_regions_from_selection_and_entered ();
5267
5268         if (rs.empty()) {
5269                 return;
5270         }
5271
5272         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5273                 if ((*i)->region()->position() < start) {
5274                         start = (*i)->region()->position();
5275                 }
5276                 if ((*i)->region()->last_frame() + 1 > end) {
5277                         end = (*i)->region()->last_frame() + 1;
5278                 }
5279         }
5280
5281         set_loop_range (start, end, _("set loop range from region"));
5282
5283         if (play) {
5284                 _session->request_play_loop (true);
5285                 _session->request_locate (start, true);
5286         }
5287 }
5288
5289 void
5290 Editor::set_punch_from_selection ()
5291 {
5292         if (_session == 0 || selection->time.empty()) {
5293                 return;
5294         }
5295
5296         framepos_t start = selection->time[clicked_selection].start;
5297         framepos_t end = selection->time[clicked_selection].end;
5298
5299         set_punch_range (start, end,  _("set punch range from selection"));
5300 }
5301
5302 void
5303 Editor::set_punch_from_edit_range ()
5304 {
5305         if (_session == 0) {
5306                 return;
5307         }
5308
5309         framepos_t start;
5310         framepos_t end;
5311
5312         if (!get_edit_op_range (start, end)) {
5313                 return;
5314         }
5315
5316         set_punch_range (start, end,  _("set punch range from edit range"));
5317 }
5318
5319 void
5320 Editor::set_punch_from_region ()
5321 {
5322         framepos_t start = max_framepos;
5323         framepos_t end = 0;
5324
5325         RegionSelection rs = get_regions_from_selection_and_entered ();
5326
5327         if (rs.empty()) {
5328                 return;
5329         }
5330
5331         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5332                 if ((*i)->region()->position() < start) {
5333                         start = (*i)->region()->position();
5334                 }
5335                 if ((*i)->region()->last_frame() + 1 > end) {
5336                         end = (*i)->region()->last_frame() + 1;
5337                 }
5338         }
5339
5340         set_punch_range (start, end, _("set punch range from region"));
5341 }
5342
5343 void
5344 Editor::pitch_shift_region ()
5345 {
5346         RegionSelection rs = get_regions_from_selection_and_entered ();
5347
5348         RegionSelection audio_rs;
5349         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5350                 if (dynamic_cast<AudioRegionView*> (*i)) {
5351                         audio_rs.push_back (*i);
5352                 }
5353         }
5354
5355         if (audio_rs.empty()) {
5356                 return;
5357         }
5358
5359         pitch_shift (audio_rs, 1.2);
5360 }
5361
5362 void
5363 Editor::transpose_region ()
5364 {
5365         RegionSelection rs = get_regions_from_selection_and_entered ();
5366
5367         list<MidiRegionView*> midi_region_views;
5368         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5369                 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5370                 if (mrv) {
5371                         midi_region_views.push_back (mrv);
5372                 }
5373         }
5374
5375         TransposeDialog d;
5376         int const r = d.run ();
5377         if (r != RESPONSE_ACCEPT) {
5378                 return;
5379         }
5380
5381         for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5382                 (*i)->midi_region()->transpose (d.semitones ());
5383         }
5384 }
5385
5386 void
5387 Editor::set_tempo_from_region ()
5388 {
5389         RegionSelection rs = get_regions_from_selection_and_entered ();
5390
5391         if (!_session || rs.empty()) {
5392                 return;
5393         }
5394
5395         RegionView* rv = rs.front();
5396
5397         define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5398 }
5399
5400 void
5401 Editor::use_range_as_bar ()
5402 {
5403         framepos_t start, end;
5404         if (get_edit_op_range (start, end)) {
5405                 define_one_bar (start, end);
5406         }
5407 }
5408
5409 void
5410 Editor::define_one_bar (framepos_t start, framepos_t end)
5411 {
5412         framepos_t length = end - start;
5413
5414         const Meter& m (_session->tempo_map().meter_at (start));
5415
5416         /* length = 1 bar */
5417
5418         /* now we want frames per beat.
5419            we have frames per bar, and beats per bar, so ...
5420         */
5421
5422         double frames_per_beat = length / m.beats_per_bar();
5423
5424         /* beats per minute = */
5425
5426         double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5427
5428         /* now decide whether to:
5429
5430             (a) set global tempo
5431             (b) add a new tempo marker
5432
5433         */
5434
5435         const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5436
5437         bool do_global = false;
5438
5439         if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5440
5441                 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5442                    at the start, or create a new marker
5443                 */
5444
5445                 vector<string> options;
5446                 options.push_back (_("Cancel"));
5447                 options.push_back (_("Add new marker"));
5448                 options.push_back (_("Set global tempo"));
5449
5450                 Choice c (
5451                         _("Define one bar"),
5452                         _("Do you want to set the global tempo or add a new tempo marker?"),
5453                         options
5454                         );
5455                 
5456                 c.set_default_response (2);
5457
5458                 switch (c.run()) {
5459                 case 0:
5460                         return;
5461
5462                 case 2:
5463                         do_global = true;
5464                         break;
5465
5466                 default:
5467                         do_global = false;
5468                 }
5469
5470         } else {
5471
5472                 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5473                    if the marker is at the region starter, change it, otherwise add
5474                    a new tempo marker
5475                 */
5476         }
5477
5478         begin_reversible_command (_("set tempo from region"));
5479         XMLNode& before (_session->tempo_map().get_state());
5480
5481         if (do_global) {
5482                 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5483         } else if (t.frame() == start) {
5484                 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5485         } else {
5486                 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), start);
5487         }
5488
5489         XMLNode& after (_session->tempo_map().get_state());
5490
5491         _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
5492         commit_reversible_command ();
5493 }
5494
5495 void
5496 Editor::split_region_at_transients ()
5497 {
5498         AnalysisFeatureList positions;
5499
5500         RegionSelection rs = get_regions_from_selection_and_entered ();
5501
5502         if (!_session || rs.empty()) {
5503                 return;
5504         }
5505
5506         _session->begin_reversible_command (_("split regions"));
5507
5508         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
5509
5510                 RegionSelection::iterator tmp;
5511
5512                 tmp = i;
5513                 ++tmp;
5514
5515                 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
5516
5517                 if (ar && (ar->get_transients (positions) == 0)) {
5518                         split_region_at_points ((*i)->region(), positions, true);
5519                         positions.clear ();
5520                 }
5521
5522                 i = tmp;
5523         }
5524
5525         _session->commit_reversible_command ();
5526
5527 }
5528
5529 void
5530 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
5531 {
5532         bool use_rhythmic_rodent = false;
5533         
5534         boost::shared_ptr<Playlist> pl = r->playlist();
5535         
5536         list<boost::shared_ptr<Region> > new_regions;
5537
5538         if (!pl) {
5539                 return;
5540         }
5541
5542         if (positions.empty()) {
5543                 return;
5544         }
5545
5546
5547         if (positions.size() > 20 && can_ferret) {
5548                 std::string msgstr = string_compose (_("You are about to split\n%1\ninto %2 pieces.\nThis could take a long time."), r->name(), positions.size() + 1);
5549                 MessageDialog msg (msgstr,
5550                                    false,
5551                                    Gtk::MESSAGE_INFO,
5552                                    Gtk::BUTTONS_OK_CANCEL);
5553
5554                 if (can_ferret) {
5555                         msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
5556                         msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
5557                 } else {
5558                         msg.set_secondary_text (_("Press OK to continue with this split operation"));
5559                 }
5560
5561                 msg.set_title (_("Excessive split?"));
5562                 msg.present ();
5563
5564                 int response = msg.run();
5565                 msg.hide ();
5566                 
5567                 switch (response) {
5568                 case RESPONSE_OK:
5569                         break;
5570                 case RESPONSE_APPLY:
5571                         use_rhythmic_rodent = true;
5572                         break;
5573                 default:
5574                         return;
5575                 }
5576         }
5577
5578         if (use_rhythmic_rodent) {
5579                 show_rhythm_ferret ();
5580                 return;
5581         }
5582
5583         AnalysisFeatureList::const_iterator x;
5584
5585         pl->clear_changes ();
5586
5587         x = positions.begin();
5588
5589         if (x == positions.end()) {
5590                 return;
5591         }
5592
5593         pl->freeze ();
5594         pl->remove_region (r);
5595
5596         framepos_t pos = 0;
5597
5598         while (x != positions.end()) {
5599           
5600                 /* deal with positons that are out of scope of present region bounds */
5601                 if (*x <= 0 || *x > r->length()) {
5602                         ++x;
5603                         continue;
5604                 }
5605
5606                 /* file start = original start + how far we from the initial position ?
5607                  */
5608
5609                 framepos_t file_start = r->start() + pos;
5610
5611                 /* length = next position - current position
5612                  */
5613
5614                 framepos_t len = (*x) - pos;
5615                 
5616                 /* XXX we do we really want to allow even single-sample regions?
5617                    shouldn't we have some kind of lower limit on region size?
5618                 */
5619
5620                 if (len <= 0) {
5621                         break;
5622                 }
5623
5624                 string new_name;
5625
5626                 if (RegionFactory::region_name (new_name, r->name())) {
5627                         break;
5628                 }
5629
5630                 /* do NOT announce new regions 1 by one, just wait till they are all done */
5631
5632                 PropertyList plist; 
5633                 
5634                 plist.add (ARDOUR::Properties::start, file_start);
5635                 plist.add (ARDOUR::Properties::length, len);
5636                 plist.add (ARDOUR::Properties::name, new_name);
5637                 plist.add (ARDOUR::Properties::layer, 0);
5638
5639                 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
5640
5641                 pl->add_region (nr, r->position() + pos);
5642
5643                 if (select_new) {
5644                         new_regions.push_front(nr);
5645                 }
5646
5647                 pos += len;
5648                 ++x;
5649         }
5650
5651         string new_name;
5652
5653         RegionFactory::region_name (new_name, r->name());
5654         
5655         /* Add the final region */
5656         PropertyList plist; 
5657                 
5658         plist.add (ARDOUR::Properties::start, r->start() + pos);
5659         plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
5660         plist.add (ARDOUR::Properties::name, new_name);
5661         plist.add (ARDOUR::Properties::layer, 0);
5662
5663         boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
5664         pl->add_region (nr, r->position() + pos);
5665         
5666         if (select_new) {
5667                 new_regions.push_front(nr);
5668         }
5669
5670         pl->thaw ();
5671
5672         _session->add_command (new StatefulDiffCommand (pl));
5673         
5674         if (select_new) {
5675
5676                 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
5677                         set_selected_regionview_from_region_list ((*i), Selection::Add);
5678                 }
5679         }
5680 }
5681
5682 void
5683 Editor::place_transient()
5684 {
5685         if (!_session) {
5686                 return;
5687         }
5688
5689         RegionSelection rs = get_regions_from_selection_and_edit_point ();
5690
5691         if (rs.empty()) {
5692                 return;
5693         }
5694         
5695         framepos_t where = get_preferred_edit_position();
5696
5697         _session->begin_reversible_command (_("place transient"));
5698         
5699         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5700                 framepos_t position = (*r)->region()->position();
5701                 (*r)->region()->add_transient(where - position);
5702         }
5703         
5704         _session->commit_reversible_command ();
5705 }
5706
5707 void
5708 Editor::remove_transient(ArdourCanvas::Item* item)
5709 {
5710         if (!_session) {
5711                 return;
5712         }
5713
5714         ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
5715         assert (_line);
5716
5717         AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
5718         _arv->remove_transient (*(float*) _line->get_data ("position"));
5719 }
5720
5721 void
5722 Editor::snap_regions_to_grid ()
5723 {
5724         list <boost::shared_ptr<Playlist > > used_playlists;
5725         
5726         RegionSelection rs = get_regions_from_selection_and_entered ();
5727
5728         if (!_session || rs.empty()) {
5729                 return;
5730         }
5731         
5732         _session->begin_reversible_command (_("snap regions to grid"));
5733         
5734         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5735           
5736                 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
5737           
5738                 if (!pl->frozen()) {
5739                         /* we haven't seen this playlist before */
5740
5741                         /* remember used playlists so we can thaw them later */
5742                         used_playlists.push_back(pl);
5743                         pl->freeze();
5744                 }
5745
5746                 framepos_t start_frame = (*r)->region()->first_frame ();
5747                 snap_to (start_frame);
5748                 (*r)->region()->set_position (start_frame, this);
5749         }
5750         
5751         while (used_playlists.size() > 0) {
5752                 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
5753                 (*i)->thaw();
5754                 used_playlists.pop_front();
5755         }
5756
5757         _session->commit_reversible_command ();
5758 }
5759
5760 void
5761 Editor::close_region_gaps ()
5762 {
5763         list <boost::shared_ptr<Playlist > > used_playlists;
5764         
5765         RegionSelection rs = get_regions_from_selection_and_entered ();
5766
5767         if (!_session || rs.empty()) {
5768                 return;
5769         }
5770
5771         Dialog dialog (_("Close Region Gaps"));
5772
5773         Table table (2, 3);
5774         table.set_spacings (12);
5775         table.set_border_width (12);
5776         Label* l = manage (new Label (_("Crossfade length")));
5777         l->set_alignment (0, 0.5);
5778         table.attach (*l, 0, 1, 0, 1);
5779         
5780         SpinButton spin_crossfade (1, 0);
5781         spin_crossfade.set_range (0, 15);
5782         spin_crossfade.set_increments (1, 1);
5783         spin_crossfade.set_value (5);
5784         table.attach (spin_crossfade, 1, 2, 0, 1);
5785
5786         table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
5787
5788         l = manage (new Label (_("Pull-back length")));
5789         l->set_alignment (0, 0.5);
5790         table.attach (*l, 0, 1, 1, 2);
5791         
5792         SpinButton spin_pullback (1, 0);
5793         spin_pullback.set_range (0, 100);
5794         spin_pullback.set_increments (1, 1);
5795         spin_pullback.set_value(30);
5796         table.attach (spin_pullback, 1, 2, 1, 2);
5797
5798         table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
5799         
5800         dialog.get_vbox()->pack_start (table);
5801         dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
5802         dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
5803         dialog.show_all ();
5804
5805         if (dialog.run () == RESPONSE_CANCEL) {
5806                 return;
5807         }
5808
5809         framepos_t crossfade_len = spin_crossfade.get_value(); 
5810         framepos_t pull_back_frames = spin_pullback.get_value();
5811
5812         crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
5813         pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
5814
5815         /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
5816         
5817         _session->begin_reversible_command (_("close region gaps"));
5818
5819         int idx = 0;
5820         boost::shared_ptr<Region> last_region;
5821         
5822         rs.sort_by_position_and_track();
5823         
5824         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5825           
5826                 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
5827                 
5828                 if (!pl->frozen()) {
5829                         /* we haven't seen this playlist before */
5830
5831                         /* remember used playlists so we can thaw them later */
5832                         used_playlists.push_back(pl);
5833                         pl->freeze();
5834                 }
5835
5836                 framepos_t position = (*r)->region()->position();
5837           
5838                 if (idx == 0 || position < last_region->position()){
5839                         last_region = (*r)->region();
5840                         idx++;
5841                         continue;
5842                 }
5843                 
5844                 (*r)->region()->trim_front( (position - pull_back_frames), this );
5845                 last_region->trim_end( (position - pull_back_frames + crossfade_len), this );
5846                 
5847                 last_region = (*r)->region();
5848                 
5849                 idx++;
5850         }
5851         
5852         while (used_playlists.size() > 0) {
5853                 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
5854                 (*i)->thaw();
5855                 used_playlists.pop_front();
5856         }
5857
5858         _session->commit_reversible_command ();
5859 }
5860
5861 void
5862 Editor::tab_to_transient (bool forward)
5863 {
5864         AnalysisFeatureList positions;
5865
5866         RegionSelection rs = get_regions_from_selection_and_entered ();
5867
5868         if (!_session) {
5869                 return;
5870         }
5871
5872         framepos_t pos = _session->audible_frame ();
5873
5874         if (!selection->tracks.empty()) {
5875
5876                 for (TrackSelection::iterator t = selection->tracks.begin(); t != selection->tracks.end(); ++t) {
5877
5878                         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
5879
5880                         if (rtv) {
5881                                 boost::shared_ptr<Track> tr = rtv->track();
5882                                 if (tr) {
5883                                         boost::shared_ptr<Playlist> pl = tr->playlist ();
5884                                         if (pl) {
5885                                                 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
5886
5887                                                 if (result >= 0) {
5888                                                         positions.push_back (result);
5889                                                 }
5890                                         }
5891                                 }
5892                         }
5893                 }
5894
5895         } else {
5896
5897                 if (rs.empty()) {
5898                         return;
5899                 }
5900
5901                 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5902                         (*r)->region()->get_transients (positions);
5903                 }
5904         }
5905
5906         TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
5907
5908         if (forward) {
5909                 AnalysisFeatureList::iterator x;
5910
5911                 for (x = positions.begin(); x != positions.end(); ++x) {
5912                         if ((*x) > pos) {
5913                                 break;
5914                         }
5915                 }
5916
5917                 if (x != positions.end ()) {
5918                         _session->request_locate (*x);
5919                 }
5920
5921         } else {
5922                 AnalysisFeatureList::reverse_iterator x;
5923
5924                 for (x = positions.rbegin(); x != positions.rend(); ++x) {
5925                         if ((*x) < pos) {
5926                                 break;
5927                         }
5928                 }
5929
5930                 if (x != positions.rend ()) {
5931                         _session->request_locate (*x);
5932                 }
5933         }
5934 }
5935
5936 void
5937 Editor::playhead_forward_to_grid ()
5938 {
5939         if (!_session) return;
5940         framepos_t pos = playhead_cursor->current_frame;
5941         if (pos < max_framepos - 1) {
5942                 pos += 2;
5943                 snap_to_internal (pos, 1, false);
5944                 _session->request_locate (pos);
5945         }
5946 }
5947
5948
5949 void
5950 Editor::playhead_backward_to_grid ()
5951 {
5952         if (!_session) return;
5953         framepos_t pos = playhead_cursor->current_frame;
5954         if (pos > 2) {
5955                 pos -= 2;
5956                 snap_to_internal (pos, -1, false);
5957                 _session->request_locate (pos);
5958         }
5959 }
5960
5961 void
5962 Editor::set_track_height (Height h)
5963 {
5964         TrackSelection& ts (selection->tracks);
5965
5966         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
5967                 (*x)->set_height_enum (h);
5968         }
5969 }
5970
5971 void
5972 Editor::toggle_tracks_active ()
5973 {
5974         TrackSelection& ts (selection->tracks);
5975         bool first = true;
5976         bool target = false;
5977
5978         if (ts.empty()) {
5979                 return;
5980         }
5981
5982         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
5983                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
5984
5985                 if (rtv) {
5986                         if (first) {
5987                                 target = !rtv->_route->active();
5988                                 first = false;
5989                         }
5990                         rtv->_route->set_active (target, this);
5991                 }
5992         }
5993 }
5994
5995 void
5996 Editor::remove_tracks ()
5997 {
5998         TrackSelection& ts (selection->tracks);
5999
6000         if (ts.empty()) {
6001                 return;
6002         }
6003
6004         vector<string> choices;
6005         string prompt;
6006         int ntracks = 0;
6007         int nbusses = 0;
6008         const char* trackstr;
6009         const char* busstr;
6010         vector<boost::shared_ptr<Route> > routes;
6011         bool special_bus = false;
6012
6013         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6014                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6015                 if (rtv) {
6016                         if (rtv->is_track()) {
6017                                 ntracks++;
6018                         } else {
6019                                 nbusses++;
6020                         }
6021                 }
6022                 routes.push_back (rtv->_route);
6023
6024                 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6025                         special_bus = true;
6026                 }
6027         }
6028
6029         if (special_bus && !Config->get_allow_special_bus_removal()) {
6030                 MessageDialog msg (_("That would be bad news ...."),
6031                                    false,
6032                                    Gtk::MESSAGE_INFO,
6033                                    Gtk::BUTTONS_OK);
6034                 msg.set_secondary_text (string_compose (_(
6035                                                                 "Removing the master or monitor bus is such a bad idea\n\
6036 that %1 is not going to allow it.\n\
6037 \n\
6038 If you really want to do this sort of thing\n\
6039 edit your ardour.rc file to set the\n\
6040 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6041
6042                 msg.present ();
6043                 msg.run ();
6044                 return;
6045         }
6046
6047         if (ntracks + nbusses == 0) {
6048                 return;
6049         }
6050
6051         if (ntracks > 1) {
6052                 trackstr = _("tracks");
6053         } else {
6054                 trackstr = _("track");
6055         }
6056
6057         if (nbusses > 1) {
6058                 busstr = _("busses");
6059         } else {
6060                 busstr = _("bus");
6061         }
6062
6063         if (ntracks) {
6064                 if (nbusses) {
6065                         prompt  = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6066                                                     "(You may also lose the playlists associated with the %2)\n\n"
6067                                                     "This action cannot be undone, and the session file will be overwritten!"),
6068                                                   ntracks, trackstr, nbusses, busstr);
6069                 } else {
6070                         prompt  = string_compose (_("Do you really want to remove %1 %2?\n"
6071                                                     "(You may also lose the playlists associated with the %2)\n\n"
6072                                                     "This action cannot be undone, and the session file will be overwritten!"),
6073                                                   ntracks, trackstr);
6074                 }
6075         } else if (nbusses) {
6076                 prompt  = string_compose (_("Do you really want to remove %1 %2?\n\n"
6077                                             "This action cannot be undon, and the session file will be overwritten"),
6078                                           nbusses, busstr);
6079         }
6080
6081         choices.push_back (_("No, do nothing."));
6082         if (ntracks + nbusses > 1) {
6083                 choices.push_back (_("Yes, remove them."));
6084         } else {
6085                 choices.push_back (_("Yes, remove it."));
6086         }
6087
6088         string title;
6089         if (ntracks) {
6090                 title = string_compose (_("Remove %1"), trackstr);
6091         } else {
6092                 title = string_compose (_("Remove %1"), busstr);
6093         }
6094
6095         Choice prompter (title, prompt, choices);
6096
6097         if (prompter.run () != 1) {
6098                 return;
6099         }
6100
6101         for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6102                 _session->remove_route (*x);
6103         }
6104 }
6105
6106 void
6107 Editor::do_insert_time ()
6108 {
6109         if (selection->tracks.empty()) {
6110                 return;
6111         }
6112
6113         InsertTimeDialog d (*this);
6114         int response = d.run ();
6115
6116         if (response != RESPONSE_OK) {
6117                 return;
6118         }
6119
6120         if (d.distance() == 0) {
6121                 return;
6122         }
6123
6124         InsertTimeOption opt = d.intersected_region_action ();
6125
6126         insert_time (
6127                 get_preferred_edit_position(),
6128                 d.distance(),
6129                 opt,
6130                 d.move_glued(),
6131                 d.move_markers(),
6132                 d.move_glued_markers(),
6133                 d.move_locked_markers(),
6134                 d.move_tempos()
6135                 );
6136 }
6137
6138 void
6139 Editor::insert_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6140                      bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
6141 {
6142         bool commit = false;
6143
6144         if (Config->get_edit_mode() == Lock) {
6145                 return;
6146         }
6147
6148         begin_reversible_command (_("insert time"));
6149
6150         for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
6151                 /* regions */
6152                 boost::shared_ptr<Playlist> pl = (*x)->playlist();
6153
6154                 if (pl) {
6155
6156                         pl->clear_changes ();
6157                         pl->clear_owned_changes ();
6158
6159                         if (opt == SplitIntersected) {
6160                                 pl->split (pos);
6161                         }
6162
6163                         pl->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6164
6165                         vector<Command*> cmds;
6166                         pl->rdiff (cmds);
6167                         _session->add_commands (cmds);
6168                         
6169                         _session->add_command (new StatefulDiffCommand (pl));
6170                         commit = true;
6171                 }
6172
6173                 /* automation */
6174                 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6175                 if (rtav) {
6176                         rtav->route ()->shift (pos, frames);
6177                         commit = true;
6178                 }
6179         }
6180
6181         /* markers */
6182         if (markers_too) {
6183                 bool moved = false;
6184                 XMLNode& before (_session->locations()->get_state());
6185                 Locations::LocationList copy (_session->locations()->list());
6186
6187                 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6188
6189                         Locations::LocationList::const_iterator tmp;
6190
6191                         bool const was_locked = (*i)->locked ();
6192                         if (locked_markers_too) {
6193                                 (*i)->unlock ();
6194                         }
6195
6196                         if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6197
6198                                 if ((*i)->start() >= pos) {
6199                                         (*i)->set_start ((*i)->start() + frames);
6200                                         if (!(*i)->is_mark()) {
6201                                                 (*i)->set_end ((*i)->end() + frames);
6202                                         }
6203                                         moved = true;
6204                                 }
6205                                 
6206                         }
6207
6208                         if (was_locked) {
6209                                 (*i)->lock ();
6210                         }
6211                 }
6212
6213                 if (moved) {
6214                         XMLNode& after (_session->locations()->get_state());
6215                         _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6216                 }
6217         }
6218
6219         if (tempo_too) {
6220                 _session->tempo_map().insert_time (pos, frames);
6221         }
6222
6223         if (commit) {
6224                 commit_reversible_command ();
6225         }
6226 }
6227
6228 void
6229 Editor::fit_selected_tracks ()
6230 {
6231         if (!selection->tracks.empty()) {
6232                 fit_tracks (selection->tracks);
6233         } else {
6234                 TrackViewList tvl;
6235
6236                 /* no selected tracks - use tracks with selected regions */
6237
6238                 if (!selection->regions.empty()) {
6239                         for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6240                                 tvl.push_back (&(*r)->get_time_axis_view ());
6241                         }
6242                         
6243                         if (!tvl.empty()) {
6244                                 fit_tracks (tvl);
6245                         }
6246                 } else if (internal_editing()) {
6247                         /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6248                            the entered track
6249                         */
6250                         if (entered_track) {
6251                                 tvl.push_back (entered_track);
6252                                 fit_tracks (tvl);
6253                         }
6254                 }
6255         }
6256 }
6257
6258 void
6259 Editor::fit_tracks (TrackViewList & tracks)
6260 {
6261         if (tracks.empty()) {
6262                 return;
6263         }
6264
6265         uint32_t child_heights = 0;
6266         int visible_tracks = 0;
6267
6268         for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6269
6270                 if (!(*t)->marked_for_display()) {
6271                         continue;
6272                 }
6273
6274                 child_heights += (*t)->effective_height() - (*t)->current_height();
6275                 ++visible_tracks;
6276         }
6277
6278         uint32_t h = (uint32_t) floor ((_canvas_height - child_heights - canvas_timebars_vsize) / visible_tracks);
6279         double first_y_pos = DBL_MAX;
6280
6281         if (h < TimeAxisView::preset_height (HeightSmall)) {
6282                 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6283                 /* too small to be displayed */
6284                 return;
6285         }
6286
6287         undo_visual_stack.push_back (current_visual_state());
6288
6289         /* build a list of all tracks, including children */
6290
6291         TrackViewList all;
6292         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6293                 all.push_back (*i);
6294                 TimeAxisView::Children c = (*i)->get_child_list ();
6295                 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6296                         all.push_back (j->get());
6297                 }
6298         }
6299
6300         /* operate on all tracks, hide unselected ones that are in the middle of selected ones */
6301
6302         bool prev_was_selected = false;
6303         bool is_selected = tracks.contains (all.front());
6304         bool next_is_selected;
6305
6306         for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6307
6308                 TrackViewList::iterator next;
6309
6310                 next = t;
6311                 ++next;
6312
6313                 if (next != all.end()) {
6314                         next_is_selected = tracks.contains (*next);
6315                 } else {
6316                         next_is_selected = false;
6317                 }
6318
6319                 if ((*t)->marked_for_display ()) {
6320                         if (is_selected) {
6321                                 (*t)->set_height (h);
6322                                 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6323                         } else {
6324                                 if (prev_was_selected && next_is_selected) {
6325                                         hide_track_in_display (*t);
6326                                 }
6327                         }
6328                 }
6329
6330                 prev_was_selected = is_selected;
6331                 is_selected = next_is_selected;
6332         }
6333
6334         /*
6335            set the controls_layout height now, because waiting for its size
6336            request signal handler will cause the vertical adjustment setting to fail
6337         */
6338
6339         controls_layout.property_height () = full_canvas_height - canvas_timebars_vsize;
6340         vertical_adjustment.set_value (first_y_pos);
6341
6342         redo_visual_stack.push_back (current_visual_state());
6343 }
6344
6345 void
6346 Editor::save_visual_state (uint32_t n)
6347 {
6348         while (visual_states.size() <= n) {
6349                 visual_states.push_back (0);
6350         }
6351
6352         delete visual_states[n];
6353
6354         visual_states[n] = current_visual_state (true);
6355         gdk_beep ();
6356 }
6357
6358 void
6359 Editor::goto_visual_state (uint32_t n)
6360 {
6361         if (visual_states.size() <= n) {
6362                 return;
6363         }
6364
6365         if (visual_states[n] == 0) {
6366                 return;
6367         }
6368
6369         use_visual_state (*visual_states[n]);
6370 }
6371
6372 void
6373 Editor::start_visual_state_op (uint32_t n)
6374 {
6375         if (visual_state_op_connection.empty()) {
6376                 visual_state_op_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::end_visual_state_op), n), 1000);
6377         }
6378 }
6379
6380 void
6381 Editor::cancel_visual_state_op (uint32_t n)
6382 {
6383         if (!visual_state_op_connection.empty()) {
6384                 visual_state_op_connection.disconnect();
6385                 goto_visual_state (n);
6386         }  else {
6387                 //we land here if called from the menu OR if end_visual_state_op has been called
6388                 //so check if we are already in visual state n
6389                 // XXX not yet checking it at all, but redoing does not hurt
6390                 goto_visual_state (n);
6391         }
6392 }
6393
6394 bool
6395 Editor::end_visual_state_op (uint32_t n)
6396 {
6397         visual_state_op_connection.disconnect();
6398         save_visual_state (n);
6399
6400         PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6401         char buf[32];
6402         snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6403         pup->set_text (buf);
6404         pup->touch();
6405
6406         return false; // do not call again
6407 }
6408
6409 void
6410 Editor::toggle_region_mute ()
6411 {
6412         if (_ignore_region_action) {
6413                 return;
6414         }
6415         
6416         RegionSelection rs = get_regions_from_selection_and_entered ();
6417
6418         if (rs.empty ()) {
6419                 return;
6420         }
6421
6422         if (rs.size() > 1) {
6423                 begin_reversible_command (_("mute regions"));
6424         } else {
6425                 begin_reversible_command (_("mute region"));
6426         }
6427         
6428         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6429                 
6430                 (*i)->region()->playlist()->clear_changes ();
6431                 (*i)->region()->set_muted (!(*i)->region()->muted ());
6432                 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
6433                 
6434         }
6435         
6436         commit_reversible_command ();
6437 }
6438