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