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