dramatic change in logic and naming for operations related to adding a MIDI region...
[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                         try {
4822                                 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4823                                 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4824                                 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4825                                 
4826                                 playlist->clear_changes ();
4827                                 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4828                                 _session->add_command(new StatefulDiffCommand (playlist));
4829                         } catch (...) {
4830                                 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4831                         }
4832                 }
4833
4834                 r = tmp;
4835         }
4836
4837         commit_reversible_command ();
4838
4839         set_canvas_cursor (current_canvas_cursor);
4840 }
4841
4842 void
4843 Editor::quantize_region ()
4844 {
4845         int selected_midi_region_cnt = 0;
4846
4847         if (!_session) {
4848                 return;
4849         }
4850
4851         RegionSelection rs = get_regions_from_selection_and_entered ();
4852
4853         if (rs.empty()) {
4854                 return;
4855         }
4856
4857         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4858                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4859                 if (mrv) {
4860                         selected_midi_region_cnt++;
4861                 }
4862         }
4863
4864         if (selected_midi_region_cnt == 0) {
4865                 return;
4866         }
4867
4868         QuantizeDialog* qd = new QuantizeDialog (*this);
4869
4870         qd->present ();
4871         const int r = qd->run ();
4872         qd->hide ();
4873
4874         if (r == Gtk::RESPONSE_OK) {
4875                 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4876                                 qd->start_grid_size(), qd->end_grid_size(),
4877                                 qd->strength(), qd->swing(), qd->threshold());
4878
4879                 apply_midi_note_edit_op (quant);
4880         }
4881 }
4882
4883 void
4884 Editor::insert_patch_change (bool from_context)
4885 {
4886         RegionSelection rs = get_regions_from_selection_and_entered ();
4887
4888         if (rs.empty ()) {
4889                 return;
4890         }
4891
4892         const framepos_t p = get_preferred_edit_position (false, from_context);
4893
4894         /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4895            there may be more than one, but the PatchChangeDialog can only offer
4896            one set of patch menus.
4897         */
4898         MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4899
4900         Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4901         PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4902
4903         if (d.run() == RESPONSE_CANCEL) {
4904                 return;
4905         }
4906
4907         for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4908                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4909                 if (mrv) {
4910                         if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4911                                 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4912                         }
4913                 }
4914         }
4915 }
4916
4917 void
4918 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4919 {
4920         RegionSelection rs = get_regions_from_selection_and_entered ();
4921
4922         if (rs.empty()) {
4923                 return;
4924         }
4925
4926         begin_reversible_command (command);
4927
4928         set_canvas_cursor (_cursors->wait);
4929         gdk_flush ();
4930
4931         int n = 0;
4932         int const N = rs.size ();
4933
4934         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4935                 RegionSelection::iterator tmp = r;
4936                 ++tmp;
4937
4938                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4939                 if (arv) {
4940                         boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4941
4942                         if (progress) {
4943                                 progress->descend (1.0 / N);
4944                         }
4945
4946                         if (arv->audio_region()->apply (filter, progress) == 0) {
4947
4948                                 playlist->clear_changes ();
4949                                 playlist->clear_owned_changes ();
4950
4951                                 if (filter.results.empty ()) {
4952
4953                                         /* no regions returned; remove the old one */
4954                                         playlist->remove_region (arv->region ());
4955
4956                                 } else {
4957
4958                                         std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
4959
4960                                         /* first region replaces the old one */
4961                                         playlist->replace_region (arv->region(), *res, (*res)->position());
4962                                         ++res;
4963
4964                                         /* add the rest */
4965                                         while (res != filter.results.end()) {
4966                                                 playlist->add_region (*res, (*res)->position());
4967                                                 ++res;
4968                                         }
4969
4970                                 }
4971
4972                                 /* We might have removed regions, which alters other regions' layering_index,
4973                                    so we need to do a recursive diff here.
4974                                 */
4975                                 vector<Command*> cmds;
4976                                 playlist->rdiff (cmds);
4977                                 _session->add_commands (cmds);
4978                                 
4979                                 _session->add_command(new StatefulDiffCommand (playlist));
4980                         } else {
4981                                 goto out;
4982                         }
4983
4984                         if (progress) {
4985                                 progress->ascend ();
4986                         }
4987                 }
4988
4989                 r = tmp;
4990                 ++n;
4991         }
4992
4993         commit_reversible_command ();
4994
4995   out:
4996         set_canvas_cursor (current_canvas_cursor);
4997 }
4998
4999 void
5000 Editor::external_edit_region ()
5001 {
5002         /* more to come */
5003 }
5004
5005 void
5006 Editor::reset_region_gain_envelopes ()
5007 {
5008         RegionSelection rs = get_regions_from_selection_and_entered ();
5009
5010         if (!_session || rs.empty()) {
5011                 return;
5012         }
5013
5014         _session->begin_reversible_command (_("reset region gain"));
5015
5016         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5017                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5018                 if (arv) {
5019                         boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5020                         XMLNode& before (alist->get_state());
5021
5022                         arv->audio_region()->set_default_envelope ();
5023                         _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5024                 }
5025         }
5026
5027         _session->commit_reversible_command ();
5028 }
5029
5030 void
5031 Editor::set_region_gain_visibility (RegionView* rv)
5032 {
5033         AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5034         if (arv) {
5035                 arv->update_envelope_visibility();
5036         }
5037 }
5038
5039 void
5040 Editor::set_gain_envelope_visibility ()
5041 {
5042         if (!_session) {
5043                 return;
5044         }
5045
5046         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5047                 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5048                 if (v) {
5049                         v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5050                 }
5051         }
5052 }
5053
5054 void
5055 Editor::toggle_gain_envelope_active ()
5056 {
5057         if (_ignore_region_action) {
5058                 return;
5059         }
5060
5061         RegionSelection rs = get_regions_from_selection_and_entered ();
5062
5063         if (!_session || rs.empty()) {
5064                 return;
5065         }
5066
5067         _session->begin_reversible_command (_("region gain envelope active"));
5068
5069         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5070                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5071                 if (arv) {
5072                         arv->region()->clear_changes ();
5073                         arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5074                         _session->add_command (new StatefulDiffCommand (arv->region()));
5075                 }
5076         }
5077
5078         _session->commit_reversible_command ();
5079 }
5080
5081 void
5082 Editor::toggle_region_lock ()
5083 {
5084         if (_ignore_region_action) {
5085                 return;
5086         }
5087
5088         RegionSelection rs = get_regions_from_selection_and_entered ();
5089
5090         if (!_session || rs.empty()) {
5091                 return;
5092         }
5093
5094         _session->begin_reversible_command (_("toggle region lock"));
5095
5096         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5097                 (*i)->region()->clear_changes ();
5098                 (*i)->region()->set_locked (!(*i)->region()->locked());
5099                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5100         }
5101
5102         _session->commit_reversible_command ();
5103 }
5104
5105 void
5106 Editor::toggle_region_video_lock ()
5107 {
5108         if (_ignore_region_action) {
5109                 return;
5110         }
5111
5112         RegionSelection rs = get_regions_from_selection_and_entered ();
5113
5114         if (!_session || rs.empty()) {
5115                 return;
5116         }
5117
5118         _session->begin_reversible_command (_("Toggle Video Lock"));
5119
5120         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5121                 (*i)->region()->clear_changes ();
5122                 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5123                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5124         }
5125
5126         _session->commit_reversible_command ();
5127 }
5128
5129 void
5130 Editor::toggle_region_lock_style ()
5131 {
5132         if (_ignore_region_action) {
5133                 return;
5134         }
5135
5136         RegionSelection rs = get_regions_from_selection_and_entered ();
5137
5138         if (!_session || rs.empty()) {
5139                 return;
5140         }
5141
5142         _session->begin_reversible_command (_("region lock style"));
5143
5144         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5145                 (*i)->region()->clear_changes ();
5146                 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5147                 (*i)->region()->set_position_lock_style (ns);
5148                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5149         }
5150
5151         _session->commit_reversible_command ();
5152 }
5153
5154 void
5155 Editor::toggle_opaque_region ()
5156 {
5157         if (_ignore_region_action) {
5158                 return;
5159         }
5160
5161         RegionSelection rs = get_regions_from_selection_and_entered ();
5162
5163         if (!_session || rs.empty()) {
5164                 return;
5165         }
5166
5167         _session->begin_reversible_command (_("change region opacity"));
5168
5169         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5170                 (*i)->region()->clear_changes ();
5171                 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5172                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5173         }
5174
5175         _session->commit_reversible_command ();
5176 }
5177
5178 void
5179 Editor::toggle_record_enable ()
5180 {
5181         bool new_state = false;
5182         bool first = true;
5183         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5184                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5185                 if (!rtav)
5186                         continue;
5187                 if (!rtav->is_track())
5188                         continue;
5189
5190                 if (first) {
5191                         new_state = !rtav->track()->record_enabled();
5192                         first = false;
5193                 }
5194
5195                 rtav->track()->set_record_enabled (new_state, this);
5196         }
5197 }
5198
5199 void
5200 Editor::toggle_solo ()
5201 {
5202         bool new_state = false;
5203         bool first = true;
5204         boost::shared_ptr<RouteList> rl (new RouteList);
5205
5206         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5207                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5208
5209                 if (!rtav) {
5210                         continue;
5211                 }
5212
5213                 if (first) {
5214                         new_state = !rtav->route()->soloed ();
5215                         first = false;
5216                 }
5217
5218                 rl->push_back (rtav->route());
5219         }
5220
5221         _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5222 }
5223
5224 void
5225 Editor::toggle_mute ()
5226 {
5227         bool new_state = false;
5228         bool first = true;
5229         boost::shared_ptr<RouteList> rl (new RouteList);
5230
5231         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5232                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5233
5234                 if (!rtav) {
5235                         continue;
5236                 }
5237
5238                 if (first) {
5239                         new_state = !rtav->route()->muted();
5240                         first = false;
5241                 }
5242
5243                 rl->push_back (rtav->route());
5244         }
5245
5246         _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5247 }
5248
5249 void
5250 Editor::toggle_solo_isolate ()
5251 {
5252 }
5253
5254 void
5255 Editor::set_fade_length (bool in)
5256 {
5257         RegionSelection rs = get_regions_from_selection_and_entered ();
5258
5259         if (rs.empty()) {
5260                 return;
5261         }
5262
5263         /* we need a region to measure the offset from the start */
5264
5265         RegionView* rv = rs.front ();
5266
5267         framepos_t pos = get_preferred_edit_position();
5268         framepos_t len;
5269         char const * cmd;
5270
5271         if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5272                 /* edit point is outside the relevant region */
5273                 return;
5274         }
5275
5276         if (in) {
5277                 if (pos <= rv->region()->position()) {
5278                         /* can't do it */
5279                         return;
5280                 }
5281                 len = pos - rv->region()->position();
5282                 cmd = _("set fade in length");
5283         } else {
5284                 if (pos >= rv->region()->last_frame()) {
5285                         /* can't do it */
5286                         return;
5287                 }
5288                 len = rv->region()->last_frame() - pos;
5289                 cmd = _("set fade out length");
5290         }
5291
5292         begin_reversible_command (cmd);
5293
5294         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5295                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5296
5297                 if (!tmp) {
5298                         return;
5299                 }
5300
5301                 boost::shared_ptr<AutomationList> alist;
5302                 if (in) {
5303                         alist = tmp->audio_region()->fade_in();
5304                 } else {
5305                         alist = tmp->audio_region()->fade_out();
5306                 }
5307
5308                 XMLNode &before = alist->get_state();
5309
5310                 if (in) {
5311                         tmp->audio_region()->set_fade_in_length (len);
5312                         tmp->audio_region()->set_fade_in_active (true);
5313                 } else {
5314                         tmp->audio_region()->set_fade_out_length (len);
5315                         tmp->audio_region()->set_fade_out_active (true);
5316                 }
5317
5318                 XMLNode &after = alist->get_state();
5319                 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5320         }
5321
5322         commit_reversible_command ();
5323 }
5324
5325 void
5326 Editor::set_fade_in_shape (FadeShape shape)
5327 {
5328         RegionSelection rs = get_regions_from_selection_and_entered ();
5329
5330         if (rs.empty()) {
5331                 return;
5332         }
5333
5334         begin_reversible_command (_("set fade in shape"));
5335
5336         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5337                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5338
5339                 if (!tmp) {
5340                         return;
5341                 }
5342
5343                 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5344                 XMLNode &before = alist->get_state();
5345
5346                 tmp->audio_region()->set_fade_in_shape (shape);
5347
5348                 XMLNode &after = alist->get_state();
5349                 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5350         }
5351
5352         commit_reversible_command ();
5353
5354 }
5355
5356 void
5357 Editor::set_fade_out_shape (FadeShape shape)
5358 {
5359         RegionSelection rs = get_regions_from_selection_and_entered ();
5360
5361         if (rs.empty()) {
5362                 return;
5363         }
5364
5365         begin_reversible_command (_("set fade out shape"));
5366
5367         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5368                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5369
5370                 if (!tmp) {
5371                         return;
5372                 }
5373
5374                 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5375                 XMLNode &before = alist->get_state();
5376
5377                 tmp->audio_region()->set_fade_out_shape (shape);
5378
5379                 XMLNode &after = alist->get_state();
5380                 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5381         }
5382
5383         commit_reversible_command ();
5384 }
5385
5386 void
5387 Editor::set_fade_in_active (bool yn)
5388 {
5389         RegionSelection rs = get_regions_from_selection_and_entered ();
5390
5391         if (rs.empty()) {
5392                 return;
5393         }
5394
5395         begin_reversible_command (_("set fade in active"));
5396
5397         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5398                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5399
5400                 if (!tmp) {
5401                         return;
5402                 }
5403
5404
5405                 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5406
5407                 ar->clear_changes ();
5408                 ar->set_fade_in_active (yn);
5409                 _session->add_command (new StatefulDiffCommand (ar));
5410         }
5411
5412         commit_reversible_command ();
5413 }
5414
5415 void
5416 Editor::set_fade_out_active (bool yn)
5417 {
5418         RegionSelection rs = get_regions_from_selection_and_entered ();
5419
5420         if (rs.empty()) {
5421                 return;
5422         }
5423
5424         begin_reversible_command (_("set fade out active"));
5425
5426         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5427                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5428
5429                 if (!tmp) {
5430                         return;
5431                 }
5432
5433                 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5434
5435                 ar->clear_changes ();
5436                 ar->set_fade_out_active (yn);
5437                 _session->add_command(new StatefulDiffCommand (ar));
5438         }
5439
5440         commit_reversible_command ();
5441 }
5442
5443 void
5444 Editor::toggle_region_fades (int dir)
5445 {
5446         if (_ignore_region_action) {
5447                 return;
5448         }
5449         
5450         boost::shared_ptr<AudioRegion> ar;
5451         bool yn = false;
5452
5453         RegionSelection rs = get_regions_from_selection_and_entered ();
5454
5455         if (rs.empty()) {
5456                 return;
5457         }
5458
5459         RegionSelection::iterator i;
5460         for (i = rs.begin(); i != rs.end(); ++i) {
5461                 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5462                         if (dir == -1) {
5463                                 yn = ar->fade_out_active ();
5464                         } else {
5465                                 yn = ar->fade_in_active ();
5466                         }
5467                         break;
5468                 }
5469         }
5470
5471         if (i == rs.end()) {
5472                 return;
5473         }
5474
5475         /* XXX should this undo-able? */
5476
5477         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5478                 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5479                         continue;
5480                 }
5481                 if (dir == 1 || dir == 0) {
5482                         ar->set_fade_in_active (!yn);
5483                 }
5484
5485                 if (dir == -1 || dir == 0) {
5486                         ar->set_fade_out_active (!yn);
5487                 }
5488         }
5489 }
5490
5491
5492 /** Update region fade visibility after its configuration has been changed */
5493 void
5494 Editor::update_region_fade_visibility ()
5495 {
5496         bool _fade_visibility = _session->config.get_show_region_fades ();
5497
5498         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5499                 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5500                 if (v) {
5501                         if (_fade_visibility) {
5502                                 v->audio_view()->show_all_fades ();
5503                         } else {
5504                                 v->audio_view()->hide_all_fades ();
5505                         }
5506                 }
5507         }
5508 }
5509
5510 void
5511 Editor::set_edit_point ()
5512 {
5513         framepos_t where;
5514         bool ignored;
5515
5516         if (!mouse_frame (where, ignored)) {
5517                 return;
5518         }
5519
5520         snap_to (where);
5521
5522         if (selection->markers.empty()) {
5523
5524                 mouse_add_new_marker (where);
5525
5526         } else {
5527                 bool ignored;
5528
5529                 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5530
5531                 if (loc) {
5532                         loc->move_to (where);
5533                 }
5534         }
5535 }
5536
5537 void
5538 Editor::set_playhead_cursor ()
5539 {
5540         if (entered_marker) {
5541                 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5542         } else {
5543                 framepos_t where;
5544                 bool ignored;
5545
5546                 if (!mouse_frame (where, ignored)) {
5547                         return;
5548                 }
5549
5550                 snap_to (where);
5551
5552                 if (_session) {
5553                         _session->request_locate (where, _session->transport_rolling());
5554                 }
5555         }
5556
5557         if ( Config->get_always_play_range() )
5558                 cancel_time_selection();
5559 }
5560
5561 void
5562 Editor::split_region ()
5563 {
5564         if ( !selection->time.empty()) {
5565                 separate_regions_between (selection->time);
5566                 return;
5567         }
5568
5569         RegionSelection rs = get_regions_from_selection_and_edit_point ();
5570
5571         framepos_t where = get_preferred_edit_position ();
5572
5573         if (rs.empty()) {
5574                 return;
5575         }
5576
5577         split_regions_at (where, rs);
5578 }
5579
5580 struct EditorOrderRouteSorter {
5581     bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5582             return a->order_key () < b->order_key ();
5583     }
5584 };
5585
5586 void
5587 Editor::select_next_route()
5588 {
5589         if (selection->tracks.empty()) {
5590                 selection->set (track_views.front());
5591                 return;
5592         }
5593
5594         TimeAxisView* current = selection->tracks.front();
5595
5596         RouteUI *rui;
5597         do {
5598                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5599                         if (*i == current) {
5600                                 ++i;
5601                                 if (i != track_views.end()) {
5602                                         current = (*i);
5603                                 } else {
5604                                         current = (*(track_views.begin()));
5605                                         //selection->set (*(track_views.begin()));
5606                                 }
5607                                 break;
5608                         }
5609                 }
5610                 rui = dynamic_cast<RouteUI *>(current);
5611         } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5612
5613         selection->set(current);
5614
5615         ensure_track_visible(current);
5616 }
5617
5618 void
5619 Editor::select_prev_route()
5620 {
5621         if (selection->tracks.empty()) {
5622                 selection->set (track_views.front());
5623                 return;
5624         }
5625
5626         TimeAxisView* current = selection->tracks.front();
5627
5628         RouteUI *rui;
5629         do {
5630                 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5631                         if (*i == current) {
5632                                 ++i;
5633                                 if (i != track_views.rend()) {
5634                                         current = (*i);
5635                                 } else {
5636                                         current = *(track_views.rbegin());
5637                                 }
5638                                 break;
5639                         }
5640                 }
5641                 rui = dynamic_cast<RouteUI *>(current);
5642         } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5643
5644         selection->set (current);
5645
5646         ensure_track_visible(current);
5647 }
5648
5649 void
5650 Editor::ensure_track_visible(TimeAxisView *track)
5651 {
5652         if (track->hidden())
5653                 return;
5654
5655         double const current_view_min_y = vertical_adjustment.get_value();
5656         double const current_view_max_y = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
5657
5658         double const track_min_y = track->y_position ();
5659         double const track_max_y = track->y_position () + track->effective_height ();
5660
5661         if (track_min_y >= current_view_min_y &&
5662             track_max_y <= current_view_max_y) {
5663                 return;
5664         }
5665
5666         double new_value;
5667
5668         if (track_min_y < current_view_min_y) {
5669                 // Track is above the current view
5670                 new_value = track_min_y;
5671         } else {
5672                 // Track is below the current view
5673                 new_value = track->y_position () + track->effective_height() - vertical_adjustment.get_page_size();
5674         }
5675
5676         vertical_adjustment.set_value(new_value);
5677 }
5678
5679 void
5680 Editor::set_loop_from_selection (bool play)
5681 {
5682         if (_session == 0 || selection->time.empty()) {
5683                 return;
5684         }
5685
5686         framepos_t start = selection->time[clicked_selection].start;
5687         framepos_t end = selection->time[clicked_selection].end;
5688
5689         set_loop_range (start, end,  _("set loop range from selection"));
5690
5691         if (play) {
5692                 _session->request_play_loop (true);
5693                 _session->request_locate (start, true);
5694         }
5695 }
5696
5697 void
5698 Editor::set_loop_from_edit_range (bool play)
5699 {
5700         if (_session == 0) {
5701                 return;
5702         }
5703
5704         framepos_t start;
5705         framepos_t end;
5706
5707         if (!get_edit_op_range (start, end)) {
5708                 return;
5709         }
5710
5711         set_loop_range (start, end,  _("set loop range from edit range"));
5712
5713         if (play) {
5714                 _session->request_play_loop (true);
5715                 _session->request_locate (start, true);
5716         }
5717 }
5718
5719 void
5720 Editor::set_loop_from_region (bool play)
5721 {
5722         framepos_t start = max_framepos;
5723         framepos_t end = 0;
5724
5725         RegionSelection rs = get_regions_from_selection_and_entered ();
5726
5727         if (rs.empty()) {
5728                 return;
5729         }
5730
5731         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5732                 if ((*i)->region()->position() < start) {
5733                         start = (*i)->region()->position();
5734                 }
5735                 if ((*i)->region()->last_frame() + 1 > end) {
5736                         end = (*i)->region()->last_frame() + 1;
5737                 }
5738         }
5739
5740         set_loop_range (start, end, _("set loop range from region"));
5741
5742         if (play) {
5743                 _session->request_play_loop (true);
5744                 _session->request_locate (start, true);
5745         }
5746 }
5747
5748 void
5749 Editor::set_punch_from_selection ()
5750 {
5751         if (_session == 0 || selection->time.empty()) {
5752                 return;
5753         }
5754
5755         framepos_t start = selection->time[clicked_selection].start;
5756         framepos_t end = selection->time[clicked_selection].end;
5757
5758         set_punch_range (start, end,  _("set punch range from selection"));
5759 }
5760
5761 void
5762 Editor::set_punch_from_edit_range ()
5763 {
5764         if (_session == 0) {
5765                 return;
5766         }
5767
5768         framepos_t start;
5769         framepos_t end;
5770
5771         if (!get_edit_op_range (start, end)) {
5772                 return;
5773         }
5774
5775         set_punch_range (start, end,  _("set punch range from edit range"));
5776 }
5777
5778 void
5779 Editor::set_punch_from_region ()
5780 {
5781         framepos_t start = max_framepos;
5782         framepos_t end = 0;
5783
5784         RegionSelection rs = get_regions_from_selection_and_entered ();
5785
5786         if (rs.empty()) {
5787                 return;
5788         }
5789
5790         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5791                 if ((*i)->region()->position() < start) {
5792                         start = (*i)->region()->position();
5793                 }
5794                 if ((*i)->region()->last_frame() + 1 > end) {
5795                         end = (*i)->region()->last_frame() + 1;
5796                 }
5797         }
5798
5799         set_punch_range (start, end, _("set punch range from region"));
5800 }
5801
5802 void
5803 Editor::pitch_shift_region ()
5804 {
5805         RegionSelection rs = get_regions_from_selection_and_entered ();
5806
5807         RegionSelection audio_rs;
5808         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5809                 if (dynamic_cast<AudioRegionView*> (*i)) {
5810                         audio_rs.push_back (*i);
5811                 }
5812         }
5813
5814         if (audio_rs.empty()) {
5815                 return;
5816         }
5817
5818         pitch_shift (audio_rs, 1.2);
5819 }
5820
5821 void
5822 Editor::transpose_region ()
5823 {
5824         RegionSelection rs = get_regions_from_selection_and_entered ();
5825
5826         list<MidiRegionView*> midi_region_views;
5827         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5828                 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5829                 if (mrv) {
5830                         midi_region_views.push_back (mrv);
5831                 }
5832         }
5833
5834         TransposeDialog d;
5835         int const r = d.run ();
5836         if (r != RESPONSE_ACCEPT) {
5837                 return;
5838         }
5839
5840         for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5841                 (*i)->midi_region()->transpose (d.semitones ());
5842         }
5843 }
5844
5845 void
5846 Editor::set_tempo_from_region ()
5847 {
5848         RegionSelection rs = get_regions_from_selection_and_entered ();
5849
5850         if (!_session || rs.empty()) {
5851                 return;
5852         }
5853
5854         RegionView* rv = rs.front();
5855
5856         define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5857 }
5858
5859 void
5860 Editor::use_range_as_bar ()
5861 {
5862         framepos_t start, end;
5863         if (get_edit_op_range (start, end)) {
5864                 define_one_bar (start, end);
5865         }
5866 }
5867
5868 void
5869 Editor::define_one_bar (framepos_t start, framepos_t end)
5870 {
5871         framepos_t length = end - start;
5872
5873         const Meter& m (_session->tempo_map().meter_at (start));
5874
5875         /* length = 1 bar */
5876
5877         /* now we want frames per beat.
5878            we have frames per bar, and beats per bar, so ...
5879         */
5880
5881         /* XXXX METER MATH */
5882
5883         double frames_per_beat = length / m.divisions_per_bar();
5884
5885         /* beats per minute = */
5886
5887         double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5888
5889         /* now decide whether to:
5890
5891             (a) set global tempo
5892             (b) add a new tempo marker
5893
5894         */
5895
5896         const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5897
5898         bool do_global = false;
5899
5900         if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5901
5902                 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5903                    at the start, or create a new marker
5904                 */
5905
5906                 vector<string> options;
5907                 options.push_back (_("Cancel"));
5908                 options.push_back (_("Add new marker"));
5909                 options.push_back (_("Set global tempo"));
5910
5911                 Choice c (
5912                         _("Define one bar"),
5913                         _("Do you want to set the global tempo or add a new tempo marker?"),
5914                         options
5915                         );
5916
5917                 c.set_default_response (2);
5918
5919                 switch (c.run()) {
5920                 case 0:
5921                         return;
5922
5923                 case 2:
5924                         do_global = true;
5925                         break;
5926
5927                 default:
5928                         do_global = false;
5929                 }
5930
5931         } else {
5932
5933                 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5934                    if the marker is at the region starter, change it, otherwise add
5935                    a new tempo marker
5936                 */
5937         }
5938
5939         begin_reversible_command (_("set tempo from region"));
5940         XMLNode& before (_session->tempo_map().get_state());
5941
5942         if (do_global) {
5943                 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5944         } else if (t.frame() == start) {
5945                 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5946         } else {
5947                 Timecode::BBT_Time bbt;
5948                 _session->tempo_map().bbt_time (start, bbt);
5949                 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
5950         }
5951
5952         XMLNode& after (_session->tempo_map().get_state());
5953
5954         _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
5955         commit_reversible_command ();
5956 }
5957
5958 void
5959 Editor::split_region_at_transients ()
5960 {
5961         AnalysisFeatureList positions;
5962
5963         RegionSelection rs = get_regions_from_selection_and_entered ();
5964
5965         if (!_session || rs.empty()) {
5966                 return;
5967         }
5968
5969         _session->begin_reversible_command (_("split regions"));
5970
5971         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
5972
5973                 RegionSelection::iterator tmp;
5974
5975                 tmp = i;
5976                 ++tmp;
5977
5978                 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
5979
5980                 if (ar && (ar->get_transients (positions) == 0)) {
5981                         split_region_at_points ((*i)->region(), positions, true);
5982                         positions.clear ();
5983                 }
5984
5985                 i = tmp;
5986         }
5987
5988         _session->commit_reversible_command ();
5989
5990 }
5991
5992 void
5993 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
5994 {
5995         bool use_rhythmic_rodent = false;
5996
5997         boost::shared_ptr<Playlist> pl = r->playlist();
5998
5999         list<boost::shared_ptr<Region> > new_regions;
6000
6001         if (!pl) {
6002                 return;
6003         }
6004
6005         if (positions.empty()) {
6006                 return;
6007         }
6008
6009
6010         if (positions.size() > 20 && can_ferret) {
6011                 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);
6012                 MessageDialog msg (msgstr,
6013                                    false,
6014                                    Gtk::MESSAGE_INFO,
6015                                    Gtk::BUTTONS_OK_CANCEL);
6016
6017                 if (can_ferret) {
6018                         msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6019                         msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6020                 } else {
6021                         msg.set_secondary_text (_("Press OK to continue with this split operation"));
6022                 }
6023
6024                 msg.set_title (_("Excessive split?"));
6025                 msg.present ();
6026
6027                 int response = msg.run();
6028                 msg.hide ();
6029
6030                 switch (response) {
6031                 case RESPONSE_OK:
6032                         break;
6033                 case RESPONSE_APPLY:
6034                         use_rhythmic_rodent = true;
6035                         break;
6036                 default:
6037                         return;
6038                 }
6039         }
6040
6041         if (use_rhythmic_rodent) {
6042                 show_rhythm_ferret ();
6043                 return;
6044         }
6045
6046         AnalysisFeatureList::const_iterator x;
6047
6048         pl->clear_changes ();
6049         pl->clear_owned_changes ();
6050
6051         x = positions.begin();
6052
6053         if (x == positions.end()) {
6054                 return;
6055         }
6056
6057         pl->freeze ();
6058         pl->remove_region (r);
6059
6060         framepos_t pos = 0;
6061
6062         while (x != positions.end()) {
6063
6064                 /* deal with positons that are out of scope of present region bounds */
6065                 if (*x <= 0 || *x > r->length()) {
6066                         ++x;
6067                         continue;
6068                 }
6069
6070                 /* file start = original start + how far we from the initial position ?
6071                  */
6072
6073                 framepos_t file_start = r->start() + pos;
6074
6075                 /* length = next position - current position
6076                  */
6077
6078                 framepos_t len = (*x) - pos;
6079
6080                 /* XXX we do we really want to allow even single-sample regions?
6081                    shouldn't we have some kind of lower limit on region size?
6082                 */
6083
6084                 if (len <= 0) {
6085                         break;
6086                 }
6087
6088                 string new_name;
6089
6090                 if (RegionFactory::region_name (new_name, r->name())) {
6091                         break;
6092                 }
6093
6094                 /* do NOT announce new regions 1 by one, just wait till they are all done */
6095
6096                 PropertyList plist;
6097
6098                 plist.add (ARDOUR::Properties::start, file_start);
6099                 plist.add (ARDOUR::Properties::length, len);
6100                 plist.add (ARDOUR::Properties::name, new_name);
6101                 plist.add (ARDOUR::Properties::layer, 0);
6102
6103                 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6104                 /* because we set annouce to false, manually add the new region to the
6105                    RegionFactory map
6106                 */
6107                 RegionFactory::map_add (nr);
6108
6109                 pl->add_region (nr, r->position() + pos);
6110
6111                 if (select_new) {
6112                         new_regions.push_front(nr);
6113                 }
6114
6115                 pos += len;
6116                 ++x;
6117         }
6118
6119         string new_name;
6120
6121         RegionFactory::region_name (new_name, r->name());
6122
6123         /* Add the final region */
6124         PropertyList plist;
6125
6126         plist.add (ARDOUR::Properties::start, r->start() + pos);
6127         plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6128         plist.add (ARDOUR::Properties::name, new_name);
6129         plist.add (ARDOUR::Properties::layer, 0);
6130
6131         boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6132         /* because we set annouce to false, manually add the new region to the
6133            RegionFactory map
6134         */
6135         RegionFactory::map_add (nr);
6136         pl->add_region (nr, r->position() + pos);
6137
6138         if (select_new) {
6139                 new_regions.push_front(nr);
6140         }
6141
6142         pl->thaw ();
6143
6144         /* We might have removed regions, which alters other regions' layering_index,
6145            so we need to do a recursive diff here.
6146         */
6147         vector<Command*> cmds;
6148         pl->rdiff (cmds);
6149         _session->add_commands (cmds);
6150         
6151         _session->add_command (new StatefulDiffCommand (pl));
6152
6153         if (select_new) {
6154
6155                 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6156                         set_selected_regionview_from_region_list ((*i), Selection::Add);
6157                 }
6158         }
6159 }
6160
6161 void
6162 Editor::place_transient()
6163 {
6164         if (!_session) {
6165                 return;
6166         }
6167
6168         RegionSelection rs = get_regions_from_selection_and_edit_point ();
6169
6170         if (rs.empty()) {
6171                 return;
6172         }
6173
6174         framepos_t where = get_preferred_edit_position();
6175
6176         _session->begin_reversible_command (_("place transient"));
6177
6178         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6179                 framepos_t position = (*r)->region()->position();
6180                 (*r)->region()->add_transient(where - position);
6181         }
6182
6183         _session->commit_reversible_command ();
6184 }
6185
6186 void
6187 Editor::remove_transient(ArdourCanvas::Item* item)
6188 {
6189         if (!_session) {
6190                 return;
6191         }
6192
6193         ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6194         assert (_line);
6195
6196         AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6197         _arv->remove_transient (*(float*) _line->get_data ("position"));
6198 }
6199
6200 void
6201 Editor::snap_regions_to_grid ()
6202 {
6203         list <boost::shared_ptr<Playlist > > used_playlists;
6204
6205         RegionSelection rs = get_regions_from_selection_and_entered ();
6206
6207         if (!_session || rs.empty()) {
6208                 return;
6209         }
6210
6211         _session->begin_reversible_command (_("snap regions to grid"));
6212
6213         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6214
6215                 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6216
6217                 if (!pl->frozen()) {
6218                         /* we haven't seen this playlist before */
6219
6220                         /* remember used playlists so we can thaw them later */
6221                         used_playlists.push_back(pl);
6222                         pl->freeze();
6223                 }
6224
6225                 framepos_t start_frame = (*r)->region()->first_frame ();
6226                 snap_to (start_frame);
6227                 (*r)->region()->set_position (start_frame);
6228         }
6229
6230         while (used_playlists.size() > 0) {
6231                 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6232                 (*i)->thaw();
6233                 used_playlists.pop_front();
6234         }
6235
6236         _session->commit_reversible_command ();
6237 }
6238
6239 void
6240 Editor::close_region_gaps ()
6241 {
6242         list <boost::shared_ptr<Playlist > > used_playlists;
6243
6244         RegionSelection rs = get_regions_from_selection_and_entered ();
6245
6246         if (!_session || rs.empty()) {
6247                 return;
6248         }
6249
6250         Dialog dialog (_("Close Region Gaps"));
6251
6252         Table table (2, 3);
6253         table.set_spacings (12);
6254         table.set_border_width (12);
6255         Label* l = manage (left_aligned_label (_("Crossfade length")));
6256         table.attach (*l, 0, 1, 0, 1);
6257
6258         SpinButton spin_crossfade (1, 0);
6259         spin_crossfade.set_range (0, 15);
6260         spin_crossfade.set_increments (1, 1);
6261         spin_crossfade.set_value (5);
6262         table.attach (spin_crossfade, 1, 2, 0, 1);
6263
6264         table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6265
6266         l = manage (left_aligned_label (_("Pull-back length")));
6267         table.attach (*l, 0, 1, 1, 2);
6268
6269         SpinButton spin_pullback (1, 0);
6270         spin_pullback.set_range (0, 100);
6271         spin_pullback.set_increments (1, 1);
6272         spin_pullback.set_value(30);
6273         table.attach (spin_pullback, 1, 2, 1, 2);
6274
6275         table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6276
6277         dialog.get_vbox()->pack_start (table);
6278         dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6279         dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6280         dialog.show_all ();
6281
6282         if (dialog.run () == RESPONSE_CANCEL) {
6283                 return;
6284         }
6285
6286         framepos_t crossfade_len = spin_crossfade.get_value();
6287         framepos_t pull_back_frames = spin_pullback.get_value();
6288
6289         crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6290         pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6291
6292         /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6293
6294         _session->begin_reversible_command (_("close region gaps"));
6295
6296         int idx = 0;
6297         boost::shared_ptr<Region> last_region;
6298
6299         rs.sort_by_position_and_track();
6300
6301         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6302
6303                 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6304
6305                 if (!pl->frozen()) {
6306                         /* we haven't seen this playlist before */
6307
6308                         /* remember used playlists so we can thaw them later */
6309                         used_playlists.push_back(pl);
6310                         pl->freeze();
6311                 }
6312
6313                 framepos_t position = (*r)->region()->position();
6314
6315                 if (idx == 0 || position < last_region->position()){
6316                         last_region = (*r)->region();
6317                         idx++;
6318                         continue;
6319                 }
6320
6321                 (*r)->region()->trim_front( (position - pull_back_frames));
6322                 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6323
6324                 last_region = (*r)->region();
6325
6326                 idx++;
6327         }
6328
6329         while (used_playlists.size() > 0) {
6330                 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6331                 (*i)->thaw();
6332                 used_playlists.pop_front();
6333         }
6334
6335         _session->commit_reversible_command ();
6336 }
6337
6338 void
6339 Editor::tab_to_transient (bool forward)
6340 {
6341         AnalysisFeatureList positions;
6342
6343         RegionSelection rs = get_regions_from_selection_and_entered ();
6344
6345         if (!_session) {
6346                 return;
6347         }
6348
6349         framepos_t pos = _session->audible_frame ();
6350
6351         if (!selection->tracks.empty()) {
6352
6353                 /* don't waste time searching for transients in duplicate playlists.
6354                  */
6355
6356                 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6357
6358                 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6359
6360                         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6361
6362                         if (rtv) {
6363                                 boost::shared_ptr<Track> tr = rtv->track();
6364                                 if (tr) {
6365                                         boost::shared_ptr<Playlist> pl = tr->playlist ();
6366                                         if (pl) {
6367                                                 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6368
6369                                                 if (result >= 0) {
6370                                                         positions.push_back (result);
6371                                                 }
6372                                         }
6373                                 }
6374                         }
6375                 }
6376
6377         } else {
6378
6379                 if (rs.empty()) {
6380                         return;
6381                 }
6382
6383                 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6384                         (*r)->region()->get_transients (positions);
6385                 }
6386         }
6387
6388         TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6389
6390         if (forward) {
6391                 AnalysisFeatureList::iterator x;
6392
6393                 for (x = positions.begin(); x != positions.end(); ++x) {
6394                         if ((*x) > pos) {
6395                                 break;
6396                         }
6397                 }
6398
6399                 if (x != positions.end ()) {
6400                         _session->request_locate (*x);
6401                 }
6402
6403         } else {
6404                 AnalysisFeatureList::reverse_iterator x;
6405
6406                 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6407                         if ((*x) < pos) {
6408                                 break;
6409                         }
6410                 }
6411
6412                 if (x != positions.rend ()) {
6413                         _session->request_locate (*x);
6414                 }
6415         }
6416 }
6417
6418 void
6419 Editor::playhead_forward_to_grid ()
6420 {
6421         if (!_session) {
6422                 return;
6423         }
6424         
6425         framepos_t pos = playhead_cursor->current_frame ();
6426         if (pos < max_framepos - 1) {
6427                 pos += 2;
6428                 snap_to_internal (pos, 1, false);
6429                 _session->request_locate (pos);
6430         }
6431 }
6432
6433
6434 void
6435 Editor::playhead_backward_to_grid ()
6436 {
6437         if (!_session) {
6438                 return;
6439         }
6440         
6441         framepos_t pos = playhead_cursor->current_frame ();
6442         if (pos > 2) {
6443                 pos -= 2;
6444                 snap_to_internal (pos, -1, false);
6445                 _session->request_locate (pos);
6446         }
6447 }
6448
6449 void
6450 Editor::set_track_height (Height h)
6451 {
6452         TrackSelection& ts (selection->tracks);
6453
6454         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6455                 (*x)->set_height_enum (h);
6456         }
6457 }
6458
6459 void
6460 Editor::toggle_tracks_active ()
6461 {
6462         TrackSelection& ts (selection->tracks);
6463         bool first = true;
6464         bool target = false;
6465
6466         if (ts.empty()) {
6467                 return;
6468         }
6469
6470         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6471                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6472
6473                 if (rtv) {
6474                         if (first) {
6475                                 target = !rtv->_route->active();
6476                                 first = false;
6477                         }
6478                         rtv->_route->set_active (target, this);
6479                 }
6480         }
6481 }
6482
6483 void
6484 Editor::remove_tracks ()
6485 {
6486         TrackSelection& ts (selection->tracks);
6487
6488         if (ts.empty()) {
6489                 return;
6490         }
6491
6492         vector<string> choices;
6493         string prompt;
6494         int ntracks = 0;
6495         int nbusses = 0;
6496         const char* trackstr;
6497         const char* busstr;
6498         vector<boost::shared_ptr<Route> > routes;
6499         bool special_bus = false;
6500
6501         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6502                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6503                 if (!rtv) {
6504                         continue;
6505                 }
6506                 if (rtv->is_track()) {
6507                         ntracks++;
6508                 } else {
6509                         nbusses++;
6510                 }
6511                 routes.push_back (rtv->_route);
6512
6513                 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6514                         special_bus = true;
6515                 }
6516         }
6517
6518         if (special_bus && !Config->get_allow_special_bus_removal()) {
6519                 MessageDialog msg (_("That would be bad news ...."),
6520                                    false,
6521                                    Gtk::MESSAGE_INFO,
6522                                    Gtk::BUTTONS_OK);
6523                 msg.set_secondary_text (string_compose (_(
6524                                                                 "Removing the master or monitor bus is such a bad idea\n\
6525 that %1 is not going to allow it.\n\
6526 \n\
6527 If you really want to do this sort of thing\n\
6528 edit your ardour.rc file to set the\n\
6529 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6530
6531                 msg.present ();
6532                 msg.run ();
6533                 return;
6534         }
6535
6536         if (ntracks + nbusses == 0) {
6537                 return;
6538         }
6539
6540         if (ntracks > 1) {
6541                 trackstr = _("tracks");
6542         } else {
6543                 trackstr = _("track");
6544         }
6545
6546         if (nbusses > 1) {
6547                 busstr = _("busses");
6548         } else {
6549                 busstr = _("bus");
6550         }
6551
6552         if (ntracks) {
6553                 if (nbusses) {
6554                         prompt  = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6555                                                     "(You may also lose the playlists associated with the %2)\n\n"
6556                                                     "This action cannot be undone, and the session file will be overwritten!"),
6557                                                   ntracks, trackstr, nbusses, busstr);
6558                 } else {
6559                         prompt  = string_compose (_("Do you really want to remove %1 %2?\n"
6560                                                     "(You may also lose the playlists associated with the %2)\n\n"
6561                                                     "This action cannot be undone, and the session file will be overwritten!"),
6562                                                   ntracks, trackstr);
6563                 }
6564         } else if (nbusses) {
6565                 prompt  = string_compose (_("Do you really want to remove %1 %2?\n\n"
6566                                             "This action cannot be undon, and the session file will be overwritten"),
6567                                           nbusses, busstr);
6568         }
6569
6570         choices.push_back (_("No, do nothing."));
6571         if (ntracks + nbusses > 1) {
6572                 choices.push_back (_("Yes, remove them."));
6573         } else {
6574                 choices.push_back (_("Yes, remove it."));
6575         }
6576
6577         string title;
6578         if (ntracks) {
6579                 title = string_compose (_("Remove %1"), trackstr);
6580         } else {
6581                 title = string_compose (_("Remove %1"), busstr);
6582         }
6583
6584         Choice prompter (title, prompt, choices);
6585
6586         if (prompter.run () != 1) {
6587                 return;
6588         }
6589
6590         for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6591                 _session->remove_route (*x);
6592         }
6593 }
6594
6595 void
6596 Editor::do_insert_time ()
6597 {
6598         if (selection->tracks.empty()) {
6599                 return;
6600         }
6601
6602         InsertTimeDialog d (*this);
6603         int response = d.run ();
6604
6605         if (response != RESPONSE_OK) {
6606                 return;
6607         }
6608
6609         if (d.distance() == 0) {
6610                 return;
6611         }
6612
6613         InsertTimeOption opt = d.intersected_region_action ();
6614
6615         insert_time (
6616                 get_preferred_edit_position(),
6617                 d.distance(),
6618                 opt,
6619                 d.all_playlists(),
6620                 d.move_glued(),
6621                 d.move_markers(),
6622                 d.move_glued_markers(),
6623                 d.move_locked_markers(),
6624                 d.move_tempos()
6625                 );
6626 }
6627
6628 void
6629 Editor::insert_time (
6630         framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6631         bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6632         )
6633 {
6634         bool commit = false;
6635
6636         if (Config->get_edit_mode() == Lock) {
6637                 return;
6638         }
6639
6640         begin_reversible_command (_("insert time"));
6641
6642         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6643
6644         for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6645
6646                 /* regions */
6647
6648                 /* don't operate on any playlist more than once, which could
6649                  * happen if "all playlists" is enabled, but there is more
6650                  * than 1 track using playlists "from" a given track.
6651                  */
6652
6653                 set<boost::shared_ptr<Playlist> > pl;
6654
6655                 if (all_playlists) {
6656                         RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6657                         if (rtav) {
6658                                 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6659                                 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6660                                         pl.insert (*p);
6661                                 }
6662                         }
6663                 } else {
6664                         if ((*x)->playlist ()) {
6665                                 pl.insert ((*x)->playlist ());
6666                         }
6667                 }
6668                 
6669                 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6670
6671                         (*i)->clear_changes ();
6672                         (*i)->clear_owned_changes ();
6673
6674                         if (opt == SplitIntersected) {
6675                                 (*i)->split (pos);
6676                         }
6677
6678                         (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6679
6680                         vector<Command*> cmds;
6681                         (*i)->rdiff (cmds);
6682                         _session->add_commands (cmds);
6683
6684                         _session->add_command (new StatefulDiffCommand (*i));
6685                         commit = true;
6686                 }
6687
6688                 /* automation */
6689                 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6690                 if (rtav) {
6691                         rtav->route ()->shift (pos, frames);
6692                         commit = true;
6693                 }
6694         }
6695
6696         /* markers */
6697         if (markers_too) {
6698                 bool moved = false;
6699                 XMLNode& before (_session->locations()->get_state());
6700                 Locations::LocationList copy (_session->locations()->list());
6701
6702                 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6703
6704                         Locations::LocationList::const_iterator tmp;
6705
6706                         bool const was_locked = (*i)->locked ();
6707                         if (locked_markers_too) {
6708                                 (*i)->unlock ();
6709                         }
6710
6711                         if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6712
6713                                 if ((*i)->start() >= pos) {
6714                                         (*i)->set_start ((*i)->start() + frames);
6715                                         if (!(*i)->is_mark()) {
6716                                                 (*i)->set_end ((*i)->end() + frames);
6717                                         }
6718                                         moved = true;
6719                                 }
6720
6721                         }
6722
6723                         if (was_locked) {
6724                                 (*i)->lock ();
6725                         }
6726                 }
6727
6728                 if (moved) {
6729                         XMLNode& after (_session->locations()->get_state());
6730                         _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6731                 }
6732         }
6733
6734         if (tempo_too) {
6735                 _session->tempo_map().insert_time (pos, frames);
6736         }
6737
6738         if (commit) {
6739                 commit_reversible_command ();
6740         }
6741 }
6742
6743 void
6744 Editor::fit_selected_tracks ()
6745 {
6746         if (!selection->tracks.empty()) {
6747                 fit_tracks (selection->tracks);
6748         } else {
6749                 TrackViewList tvl;
6750
6751                 /* no selected tracks - use tracks with selected regions */
6752
6753                 if (!selection->regions.empty()) {
6754                         for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6755                                 tvl.push_back (&(*r)->get_time_axis_view ());
6756                         }
6757
6758                         if (!tvl.empty()) {
6759                                 fit_tracks (tvl);
6760                         }
6761                 } else if (internal_editing()) {
6762                         /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6763                            the entered track
6764                         */
6765                         if (entered_track) {
6766                                 tvl.push_back (entered_track);
6767                                 fit_tracks (tvl);
6768                         }
6769                 }
6770         }
6771 }
6772
6773 void
6774 Editor::fit_tracks (TrackViewList & tracks)
6775 {
6776         if (tracks.empty()) {
6777                 return;
6778         }
6779
6780         uint32_t child_heights = 0;
6781         int visible_tracks = 0;
6782
6783         for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6784
6785                 if (!(*t)->marked_for_display()) {
6786                         continue;
6787                 }
6788
6789                 child_heights += (*t)->effective_height() - (*t)->current_height();
6790                 ++visible_tracks;
6791         }
6792
6793         uint32_t h = (uint32_t) floor ((_visible_canvas_height - child_heights) / visible_tracks);
6794         double first_y_pos = DBL_MAX;
6795
6796         if (h < TimeAxisView::preset_height (HeightSmall)) {
6797                 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6798                 /* too small to be displayed */
6799                 return;
6800         }
6801
6802         undo_visual_stack.push_back (current_visual_state (true));
6803         no_save_visual = true;
6804
6805         /* build a list of all tracks, including children */
6806
6807         TrackViewList all;
6808         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6809                 all.push_back (*i);
6810                 TimeAxisView::Children c = (*i)->get_child_list ();
6811                 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6812                         all.push_back (j->get());
6813                 }
6814         }
6815
6816         /* operate on all tracks, hide unselected ones that are in the middle of selected ones */
6817
6818         bool prev_was_selected = false;
6819         bool is_selected = tracks.contains (all.front());
6820         bool next_is_selected;
6821
6822         for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6823
6824                 TrackViewList::iterator next;
6825
6826                 next = t;
6827                 ++next;
6828
6829                 if (next != all.end()) {
6830                         next_is_selected = tracks.contains (*next);
6831                 } else {
6832                         next_is_selected = false;
6833                 }
6834
6835                 if ((*t)->marked_for_display ()) {
6836                         if (is_selected) {
6837                                 (*t)->set_height (h);
6838                                 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6839                         } else {
6840                                 if (prev_was_selected && next_is_selected) {
6841                                         hide_track_in_display (*t);
6842                                 }
6843                         }
6844                 }
6845
6846                 prev_was_selected = is_selected;
6847                 is_selected = next_is_selected;
6848         }
6849
6850         /*
6851            set the controls_layout height now, because waiting for its size
6852            request signal handler will cause the vertical adjustment setting to fail
6853         */
6854
6855         controls_layout.property_height () = _full_canvas_height;
6856         vertical_adjustment.set_value (first_y_pos);
6857
6858         redo_visual_stack.push_back (current_visual_state (true));
6859 }
6860
6861 void
6862 Editor::save_visual_state (uint32_t n)
6863 {
6864         while (visual_states.size() <= n) {
6865                 visual_states.push_back (0);
6866         }
6867
6868         if (visual_states[n] != 0) {
6869                 delete visual_states[n];
6870         }
6871
6872         visual_states[n] = current_visual_state (true);
6873         gdk_beep ();
6874 }
6875
6876 void
6877 Editor::goto_visual_state (uint32_t n)
6878 {
6879         if (visual_states.size() <= n) {
6880                 return;
6881         }
6882
6883         if (visual_states[n] == 0) {
6884                 return;
6885         }
6886
6887         use_visual_state (*visual_states[n]);
6888 }
6889
6890 void
6891 Editor::start_visual_state_op (uint32_t n)
6892 {
6893         save_visual_state (n);
6894         
6895         PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6896         char buf[32];
6897         snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6898         pup->set_text (buf);
6899         pup->touch();
6900 }
6901
6902 void
6903 Editor::cancel_visual_state_op (uint32_t n)
6904 {
6905         goto_visual_state (n);
6906 }
6907
6908 void
6909 Editor::toggle_region_mute ()
6910 {
6911         if (_ignore_region_action) {
6912                 return;
6913         }
6914
6915         RegionSelection rs = get_regions_from_selection_and_entered ();
6916
6917         if (rs.empty ()) {
6918                 return;
6919         }
6920
6921         if (rs.size() > 1) {
6922                 begin_reversible_command (_("mute regions"));
6923         } else {
6924                 begin_reversible_command (_("mute region"));
6925         }
6926
6927         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6928
6929                 (*i)->region()->playlist()->clear_changes ();
6930                 (*i)->region()->set_muted (!(*i)->region()->muted ());
6931                 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
6932
6933         }
6934
6935         commit_reversible_command ();
6936 }
6937
6938 void
6939 Editor::combine_regions ()
6940 {
6941         /* foreach track with selected regions, take all selected regions
6942            and join them into a new region containing the subregions (as a
6943            playlist)
6944         */
6945
6946         typedef set<RouteTimeAxisView*> RTVS;
6947         RTVS tracks;
6948
6949         if (selection->regions.empty()) {
6950                 return;
6951         }
6952
6953         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6954                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6955
6956                 if (rtv) {
6957                         tracks.insert (rtv);
6958                 }
6959         }
6960
6961         begin_reversible_command (_("combine regions"));
6962
6963         vector<RegionView*> new_selection;
6964
6965         for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6966                 RegionView* rv;
6967
6968                 if ((rv = (*i)->combine_regions ()) != 0) {
6969                         new_selection.push_back (rv);
6970                 }
6971         }
6972
6973         selection->clear_regions ();
6974         for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
6975                 selection->add (*i);
6976         }
6977
6978         commit_reversible_command ();
6979 }
6980
6981 void
6982 Editor::uncombine_regions ()
6983 {
6984         typedef set<RouteTimeAxisView*> RTVS;
6985         RTVS tracks;
6986
6987         if (selection->regions.empty()) {
6988                 return;
6989         }
6990
6991         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6992                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6993
6994                 if (rtv) {
6995                         tracks.insert (rtv);
6996                 }
6997         }
6998
6999         begin_reversible_command (_("uncombine regions"));
7000
7001         for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7002                 (*i)->uncombine_regions ();
7003         }
7004
7005         commit_reversible_command ();
7006 }
7007
7008 void
7009 Editor::toggle_midi_input_active (bool flip_others)
7010 {
7011         bool onoff = false;
7012         boost::shared_ptr<RouteList> rl (new RouteList);
7013
7014         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7015                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7016
7017                 if (!rtav) {
7018                         continue;
7019                 }
7020
7021                 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7022
7023                 if (mt) {
7024                         rl->push_back (rtav->route());
7025                         onoff = !mt->input_active();
7026                 }
7027         }
7028         
7029         _session->set_exclusive_input_active (rl, onoff, flip_others);
7030 }