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