add some undo to previous selection stuff
[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     $Id$
19 */
20
21 #include <unistd.h>
22
23 #include <cstdlib>
24 #include <cmath>
25 #include <string>
26 #include <map>
27
28 #include <sndfile.h>
29
30 #include <pbd/error.h>
31 #include <pbd/basename.h>
32 #include <pbd/pthread_utils.h>
33
34 #include <gtkmm2ext/utils.h>
35 #include <gtkmm2ext/choice.h>
36
37 #include <ardour/audioengine.h>
38 #include <ardour/session.h>
39 #include <ardour/audioplaylist.h>
40 #include <ardour/audioregion.h>
41 #include <ardour/diskstream.h>
42 #include <ardour/filesource.h>
43 #include <ardour/sndfilesource.h>
44 #include <ardour/utils.h>
45 #include <ardour/location.h>
46 #include <ardour/named_selection.h>
47 #include <ardour/audio_track.h>
48 #include <ardour/audioplaylist.h>
49 #include <ardour/region_factory.h>
50 #include <ardour/reverse.h>
51
52 #include "ardour_ui.h"
53 #include "editor.h"
54 #include "time_axis_view.h"
55 #include "audio_time_axis.h"
56 #include "automation_time_axis.h"
57 #include "streamview.h"
58 #include "regionview.h"
59 #include "rgb_macros.h"
60 #include "selection_templates.h"
61 #include "selection.h"
62 #include "sfdb_ui.h"
63 #include "editing.h"
64 #include "gtk-custom-hruler.h"
65
66 #include "i18n.h"
67
68 using namespace std;
69 using namespace ARDOUR;
70 using namespace sigc;
71 using namespace Gtk;
72 using namespace Editing;
73
74 /***********************************************************************
75   Editor operations
76  ***********************************************************************/
77
78 void
79 Editor::undo (uint32_t n)
80 {
81         if (session) {
82                 session->undo (n);
83         }
84 }
85
86 void
87 Editor::redo (uint32_t n)
88 {
89         if (session) {
90                 session->redo (n);
91         }
92 }
93
94 void
95 Editor::set_meter_hold (int32_t cnt)
96 {
97         if (session) {
98                 session->set_meter_hold (cnt);
99         }
100 }
101
102 void
103 Editor::set_meter_falloff (float val)
104 {
105         if (session) {
106                 session->set_meter_falloff (val);
107         }
108 }
109
110
111 int
112 Editor::ensure_cursor (jack_nframes_t *pos)
113 {
114         *pos = edit_cursor->current_frame;
115         return 0;
116 }
117
118 void
119 Editor::split_region ()
120 {
121         split_region_at (edit_cursor->current_frame);
122 }
123
124 void
125 Editor::split_region_at (jack_nframes_t where)
126 {
127         split_regions_at (where, selection->audio_regions);
128 }
129
130 void
131 Editor::split_regions_at (jack_nframes_t where, AudioRegionSelection& regions)
132 {
133         begin_reversible_command (_("split"));
134
135         snap_to (where);
136         for (AudioRegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
137
138                 AudioRegionSelection::iterator tmp;
139                 
140                 tmp = a;
141                 ++tmp;
142
143                 Playlist* pl = (*a)->region.playlist();
144
145                 _new_regionviews_show_envelope = (*a)->envelope_visible();
146                 
147                 if (pl) {
148                         session->add_undo (pl->get_memento());
149                         pl->split_region ((*a)->region, where);
150                         session->add_redo_no_execute (pl->get_memento());
151                 }
152
153                 a = tmp;
154     }
155
156         commit_reversible_command ();
157         _new_regionviews_show_envelope = false;
158 }
159
160 void
161 Editor::remove_clicked_region ()
162 {
163         if (clicked_audio_trackview == 0 || clicked_regionview == 0) {
164                 return;
165         }
166
167         Playlist* playlist = clicked_audio_trackview->playlist();
168         
169         begin_reversible_command (_("remove region"));
170         session->add_undo (playlist->get_memento());
171         playlist->remove_region (&clicked_regionview->region);
172         session->add_redo_no_execute (playlist->get_memento());
173         commit_reversible_command ();
174 }
175
176 void
177 Editor::destroy_clicked_region ()
178 {
179         int32_t selected = selection->audio_regions.size();
180
181         if (!session || clicked_regionview == 0 && selected == 0) {
182                 return;
183         }
184
185         vector<string> choices;
186         string prompt;
187         
188         prompt  = string_compose (_(" This is destructive, will possibly delete audio files\n\
189 It cannot be undone\n\
190 Do you really want to destroy %1 ?"),
191                            (selected > 1 ? 
192                             _("these regions") : _("this region")));
193
194         if (selected > 1) {
195                 choices.push_back (_("Yes, destroy them."));
196         } else {
197                 choices.push_back (_("Yes, destroy it."));
198         }
199
200         choices.push_back (_("No, do nothing."));
201
202         Gtkmm2ext::Choice prompter (prompt, choices);
203
204         prompter.chosen.connect (ptr_fun (Main::quit));
205         prompter.show_all ();
206
207         Main::run ();
208                 
209         if (prompter.get_choice() != 0) {
210                 return;
211         }
212
213         if (selected > 0) {
214                 list<Region*> r;
215
216                 for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
217                         r.push_back (&(*i)->region);
218                 }
219
220                 session->destroy_regions (r);
221
222         } else if (clicked_regionview) {
223                 session->destroy_region (&clicked_regionview->region);
224         } 
225 }
226
227 AudioRegion *
228 Editor::select_region_for_operation (int dir, TimeAxisView **tv)
229 {
230         AudioRegionView* rv;
231         AudioRegion *region;
232         jack_nframes_t start = 0;
233
234         if (selection->time.start () == selection->time.end_frame ()) {
235                 
236                 /* no current selection-> is there a selected regionview? */
237
238                 if (selection->audio_regions.empty()) {
239                         return 0;
240                 }
241
242         } 
243
244         region = 0;
245
246         if (!selection->audio_regions.empty()) {
247
248                 rv = *(selection->audio_regions.begin());
249                 (*tv) = &rv->get_time_axis_view();
250                 region = &rv->region;
251
252         } else if (!selection->tracks.empty()) {
253
254                 (*tv) = selection->tracks.front();
255
256                 AudioTimeAxisView* atv;
257
258                 if ((atv = dynamic_cast<AudioTimeAxisView*> (*tv)) != 0) {
259                         Playlist *pl;
260                         
261                         if ((pl = atv->playlist()) == 0) {
262                                 return 0;
263                         }
264                         
265                         region = dynamic_cast<AudioRegion*> (pl->top_region_at (start));
266                 }
267         } 
268         
269         return region;
270 }
271         
272 void
273 Editor::extend_selection_to_end_of_region (bool next)
274 {
275         TimeAxisView *tv;
276         Region *region;
277         jack_nframes_t start;
278
279         if ((region = select_region_for_operation (next ? 1 : 0, &tv)) == 0) {
280                 return;
281         }
282
283         if (region && selection->time.start () == selection->time.end_frame ()) {
284                 start = region->position();
285         } else {
286                 start = selection->time.start ();
287         }
288
289         /* Try to leave the selection with the same route if possible */
290
291         if ((tv = selection->time.track) == 0) {
292                 return;
293         }
294
295         begin_reversible_command (_("extend selection"));
296         selection->set (tv, start, region->position() + region->length());
297         commit_reversible_command ();
298 }
299
300 void
301 Editor::extend_selection_to_start_of_region (bool previous)
302 {
303         TimeAxisView *tv;
304         Region *region;
305         jack_nframes_t end;
306
307         if ((region = select_region_for_operation (previous ? -1 : 0, &tv)) == 0) {
308                 return;
309         }
310
311         if (region && selection->time.start () == selection->time.end_frame ()) {
312                 end = region->position() + region->length();
313         } else {
314                 end = selection->time.end_frame ();
315         }
316
317         /* Try to leave the selection with the same route if possible */
318         
319         if ((tv = selection->time.track) == 0) {
320                 return;
321         }
322
323         begin_reversible_command (_("extend selection"));
324         selection->set (tv, region->position(), end);
325         commit_reversible_command ();
326 }
327
328
329 void
330 Editor::nudge_forward (bool next)
331 {
332         jack_nframes_t distance;
333         jack_nframes_t next_distance;
334
335         if (!session) return;
336         
337         if (!selection->audio_regions.empty()) {
338
339                 begin_reversible_command (_("nudge forward"));
340
341                 for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
342                         AudioRegion& r ((*i)->region);
343                         
344                         distance = get_nudge_distance (r.position(), next_distance);
345
346                         if (next) {
347                                 distance = next_distance;
348                         }
349
350                         session->add_undo (r.playlist()->get_memento());
351                         r.set_position (r.position() + distance, this);
352                         session->add_redo_no_execute (r.playlist()->get_memento());
353                 }
354
355                 commit_reversible_command ();
356
357         } else {
358                 distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
359                 session->request_locate (playhead_cursor->current_frame + distance);
360         }
361 }
362                 
363 void
364 Editor::nudge_backward (bool next)
365 {
366         jack_nframes_t distance;
367         jack_nframes_t next_distance;
368
369         if (!session) return;
370         
371         if (!selection->audio_regions.empty()) {
372
373                 begin_reversible_command (_("nudge forward"));
374
375                 for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
376                         AudioRegion& r ((*i)->region);
377
378                         distance = get_nudge_distance (r.position(), next_distance);
379                         
380                         if (next) {
381                                 distance = next_distance;
382                         }
383
384                         session->add_undo (r.playlist()->get_memento());
385                         
386                         if (r.position() > distance) {
387                                 r.set_position (r.position() - distance, this);
388                         } else {
389                                 r.set_position (0, this);
390                         }
391                         session->add_redo_no_execute (r.playlist()->get_memento());
392                 }
393
394                 commit_reversible_command ();
395
396         } else {
397
398                 distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
399
400                 if (playhead_cursor->current_frame > distance) {
401                         session->request_locate (playhead_cursor->current_frame - distance);
402                 } else {
403                         session->request_locate (0);
404                 }
405         }
406 }
407
408 void
409 Editor::nudge_forward_capture_offset ()
410 {
411         jack_nframes_t distance;
412
413         if (!session) return;
414         
415         if (!selection->audio_regions.empty()) {
416
417                 begin_reversible_command (_("nudge forward"));
418
419                 distance = session->worst_output_latency();
420
421                 for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
422                         AudioRegion& r ((*i)->region);
423                         
424                         session->add_undo (r.playlist()->get_memento());
425                         r.set_position (r.position() + distance, this);
426                         session->add_redo_no_execute (r.playlist()->get_memento());
427                 }
428
429                 commit_reversible_command ();
430
431         } 
432 }
433                 
434 void
435 Editor::nudge_backward_capture_offset ()
436 {
437         jack_nframes_t distance;
438
439         if (!session) return;
440         
441         if (!selection->audio_regions.empty()) {
442
443                 begin_reversible_command (_("nudge forward"));
444
445                 distance = session->worst_output_latency();
446
447                 for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
448                         AudioRegion& r ((*i)->region);
449
450                         session->add_undo (r.playlist()->get_memento());
451                         
452                         if (r.position() > distance) {
453                                 r.set_position (r.position() - distance, this);
454                         } else {
455                                 r.set_position (0, this);
456                         }
457                         session->add_redo_no_execute (r.playlist()->get_memento());
458                 }
459
460                 commit_reversible_command ();
461         }
462 }
463
464 /* DISPLAY MOTION */
465
466 void
467 Editor::move_to_start ()
468 {
469         session->request_locate (0);
470 }
471
472 void
473 Editor::move_to_end ()
474 {
475
476         session->request_locate (session->current_end_frame());
477 }
478
479 void
480 Editor::build_region_boundary_cache ()
481 {
482         jack_nframes_t pos = 0;
483         RegionPoint point;
484         Region *r;
485         TrackViewList tracks;
486
487         region_boundary_cache.clear ();
488
489         if (session == 0) {
490                 return;
491         }
492         
493         switch (snap_type) {
494         case SnapToRegionStart:
495                 point = Start;
496                 break;
497         case SnapToRegionEnd:
498                 point = End;
499                 break;  
500         case SnapToRegionSync:
501                 point = SyncPoint;
502                 break;  
503         case SnapToRegionBoundary:
504                 point = Start;
505                 break;  
506         default:
507                 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), snap_type) << endmsg;
508                 /*NOTREACHED*/
509                 return;
510         }
511         
512         TimeAxisView *ontrack = 0;
513
514         while (pos < session->current_end_frame()) {
515
516                 if (!selection->tracks.empty()) {
517
518                         if ((r = find_next_region (pos, point, 1, selection->tracks, &ontrack)) == 0) {
519                                 break;
520                         }
521
522                 } else if (clicked_trackview) {
523
524                         TrackViewList t;
525                         t.push_back (clicked_trackview);
526
527                         if ((r = find_next_region (pos, point, 1, t, &ontrack)) == 0) {
528                                 break;
529                         }
530
531                 } else {
532
533                         if ((r = find_next_region (pos, point, 1, track_views, &ontrack)) == 0) {
534                                 break;
535                         }
536                 }
537
538                 jack_nframes_t rpos;
539                 
540                 switch (snap_type) {
541                 case SnapToRegionStart:
542                         rpos = r->first_frame();
543                         break;
544                 case SnapToRegionEnd:
545                         rpos = r->last_frame();
546                         break;  
547                 case SnapToRegionSync:
548                         rpos = r->adjust_to_sync (r->first_frame());
549                         break;
550
551                 case SnapToRegionBoundary:
552                         rpos = r->last_frame();
553                         break;  
554                 default:
555                         break;
556                 }
557                 
558                 float speed = 1.0f;
559                 AudioTimeAxisView *atav;
560
561                 if ( ontrack != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(ontrack)) != 0 ) {
562                         if (atav->get_diskstream() != 0) {
563                                 speed = atav->get_diskstream()->speed();
564                         }
565                 }
566
567                 rpos = track_frame_to_session_frame(rpos, speed);
568
569                 if (region_boundary_cache.empty() || rpos != region_boundary_cache.back()) {
570                         if (snap_type == SnapToRegionBoundary) {
571                                 region_boundary_cache.push_back (r->first_frame());
572                         }
573                         region_boundary_cache.push_back (rpos);
574                 }
575
576                 pos = rpos + 1;
577         }
578 }
579
580 Region*
581 Editor::find_next_region (jack_nframes_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
582 {
583         TrackViewList::iterator i;
584         jack_nframes_t closest = max_frames;
585         Region* ret = 0;
586         jack_nframes_t rpos = 0;
587
588         float track_speed;
589         jack_nframes_t track_frame;
590         AudioTimeAxisView *atav;
591
592         for (i = tracks.begin(); i != tracks.end(); ++i) {
593
594                 jack_nframes_t distance;
595                 Region* r;
596
597                 track_speed = 1.0f;
598                 if ( (atav = dynamic_cast<AudioTimeAxisView*>(*i)) != 0 ) {
599                         if (atav->get_diskstream()!=0)
600                                 track_speed = atav->get_diskstream()->speed();
601                 }
602
603                 track_frame = session_frame_to_track_frame(frame, track_speed);
604
605                 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
606                         continue;
607                 }
608
609                 switch (point) {
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->adjust_to_sync (r->first_frame());
620                         break;
621                 }
622                 // rpos is a "track frame", converting it to "session frame"
623                 rpos = track_frame_to_session_frame(rpos, track_speed);
624
625                 if (rpos > frame) {
626                         distance = rpos - frame;
627                 } else {
628                         distance = frame - rpos;
629                 }
630
631                 if (distance < closest) {
632                         closest = distance;
633                         if (ontrack != 0)
634                                 *ontrack = (*i);
635                         ret = r;
636                 }
637         }
638
639         return ret;
640 }
641
642 void
643 Editor::cursor_to_region_point (Cursor* cursor, RegionPoint point, int32_t dir)
644 {
645         Region* r;
646         jack_nframes_t pos = cursor->current_frame;
647
648         if (!session) {
649                 return;
650         }
651
652         TimeAxisView *ontrack = 0;
653
654         // so we don't find the current region again..
655         if (dir>0 || pos>0)
656                 pos+=dir;
657
658         if (!selection->tracks.empty()) {
659                 
660                 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
661                 
662         } else if (clicked_trackview) {
663                 
664                 TrackViewList t;
665                 t.push_back (clicked_trackview);
666                 
667                 r = find_next_region (pos, point, dir, t, &ontrack);
668                 
669         } else {
670                 
671                 r = find_next_region (pos, point, dir, track_views, &ontrack);
672         }
673
674         if (r == 0) {
675                 return;
676         }
677         
678         switch (point){
679         case Start:
680                 pos = r->first_frame ();
681                 break;
682
683         case End:
684                 pos = r->last_frame ();
685                 break;
686
687         case SyncPoint:
688                 pos = r->adjust_to_sync (r->first_frame());
689                 break;  
690         }
691         
692         float speed = 1.0f;
693         AudioTimeAxisView *atav;
694
695         if ( ontrack != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(ontrack)) != 0 ) {
696                 if (atav->get_diskstream() != 0) {
697                         speed = atav->get_diskstream()->speed();
698                 }
699         }
700
701         pos = track_frame_to_session_frame(pos, speed);
702         
703         if (cursor == playhead_cursor) {
704                 session->request_locate (pos);
705         } else {
706                 cursor->set_position (pos);
707         }
708 }
709
710 void
711 Editor::cursor_to_next_region_point (Cursor* cursor, RegionPoint point)
712 {
713         cursor_to_region_point (cursor, point, 1);
714 }
715
716 void
717 Editor::cursor_to_previous_region_point (Cursor* cursor, RegionPoint point)
718 {
719         cursor_to_region_point (cursor, point, -1);
720 }
721
722 void
723 Editor::cursor_to_selection_start (Cursor *cursor)
724 {
725         jack_nframes_t pos = 0;
726         switch (mouse_mode) {
727         case MouseObject:
728                 if (!selection->audio_regions.empty()) {
729                         pos = selection->audio_regions.start();
730                 }
731                 break;
732
733         case MouseRange:
734                 if (!selection->time.empty()) {
735                         pos = selection->time.start ();
736                 }
737                 break;
738
739         default:
740                 return;
741         }
742
743         if (cursor == playhead_cursor) {
744                 session->request_locate (pos);
745         } else {
746                 cursor->set_position (pos);
747         }
748 }
749
750 void
751 Editor::cursor_to_selection_end (Cursor *cursor)
752 {
753         jack_nframes_t pos = 0;
754
755         switch (mouse_mode) {
756         case MouseObject:
757                 if (!selection->audio_regions.empty()) {
758                         pos = selection->audio_regions.end_frame();
759                 }
760                 break;
761
762         case MouseRange:
763                 if (!selection->time.empty()) {
764                         pos = selection->time.end_frame ();
765                 }
766                 break;
767
768         default:
769                 return;
770         }
771
772         if (cursor == playhead_cursor) {
773                 session->request_locate (pos);
774         } else {
775                 cursor->set_position (pos);
776         }
777 }
778
779 void
780 Editor::playhead_backward ()
781 {
782         jack_nframes_t pos;
783         jack_nframes_t cnt;
784         float prefix;
785         bool was_floating;
786
787         if (get_prefix (prefix, was_floating)) {
788                 cnt = 1;
789         } else {
790                 if (was_floating) {
791                         cnt = (jack_nframes_t) floor (prefix * session->frame_rate ());
792                 } else {
793                         cnt = (jack_nframes_t) prefix;
794                 }
795         }
796
797         pos = playhead_cursor->current_frame;
798
799         if ((jack_nframes_t) pos < cnt) {
800                 pos = 0;
801         } else {
802                 pos -= cnt;
803         }
804         
805         /* XXX this is completely insane. with the current buffering
806            design, we'll force a complete track buffer flush and
807            reload, just to move 1 sample !!!
808         */
809
810         session->request_locate (pos);
811 }
812
813 void
814 Editor::playhead_forward ()
815 {
816         jack_nframes_t pos;
817         jack_nframes_t cnt;
818         bool was_floating;
819         float prefix;
820
821         if (get_prefix (prefix, was_floating)) {
822                 cnt = 1;
823         } else {
824                 if (was_floating) {
825                         cnt = (jack_nframes_t) floor (prefix * session->frame_rate ());
826                 } else {
827                         cnt = (jack_nframes_t) floor (prefix);
828                 }
829         }
830
831         pos = playhead_cursor->current_frame;
832         
833         /* XXX this is completely insane. with the current buffering
834            design, we'll force a complete track buffer flush and
835            reload, just to move 1 sample !!!
836         */
837
838         session->request_locate (pos+cnt);
839 }
840
841 void
842 Editor::cursor_align (bool playhead_to_edit)
843 {
844         if (playhead_to_edit) {
845                 if (session) {
846                         session->request_locate (edit_cursor->current_frame);
847                 }
848         } else {
849                 edit_cursor->set_position (playhead_cursor->current_frame);
850         }
851 }
852
853 void
854 Editor::edit_cursor_backward ()
855 {
856         jack_nframes_t pos;
857         jack_nframes_t cnt;
858         float prefix;
859         bool was_floating;
860
861         if (get_prefix (prefix, was_floating)) {
862                 cnt = 1;
863         } else {
864                 if (was_floating) {
865                         cnt = (jack_nframes_t) floor (prefix * session->frame_rate ());
866                 } else {
867                         cnt = (jack_nframes_t) prefix;
868                 }
869         }
870
871         pos = edit_cursor->current_frame;
872
873         if ((jack_nframes_t) pos < cnt) {
874                 pos = 0;
875         } else {
876                 pos -= cnt;
877         }
878         
879         edit_cursor->set_position (pos);
880 }
881
882 void
883 Editor::edit_cursor_forward ()
884 {
885         jack_nframes_t pos;
886         jack_nframes_t cnt;
887         bool was_floating;
888         float prefix;
889
890         if (get_prefix (prefix, was_floating)) {
891                 cnt = 1;
892         } else {
893                 if (was_floating) {
894                         cnt = (jack_nframes_t) floor (prefix * session->frame_rate ());
895                 } else {
896                         cnt = (jack_nframes_t) floor (prefix);
897                 }
898         }
899
900         pos = edit_cursor->current_frame;
901         edit_cursor->set_position (pos+cnt);
902 }
903
904 void
905 Editor::goto_frame ()
906 {
907         float prefix;
908         bool was_floating;
909         jack_nframes_t frame;
910
911         if (get_prefix (prefix, was_floating)) {
912                 return;
913         }
914
915         if (was_floating) {
916                 frame = (jack_nframes_t) floor (prefix * session->frame_rate());
917         } else {
918                 frame = (jack_nframes_t) floor (prefix);
919         }
920
921         session->request_locate (frame);
922 }
923
924 void
925 Editor::scroll_backward (float pages)
926 {
927         jack_nframes_t frame;
928         jack_nframes_t one_page = (jack_nframes_t) rint (canvas_width * frames_per_unit);
929         bool was_floating;
930         float prefix;
931         jack_nframes_t cnt;
932         
933         if (get_prefix (prefix, was_floating)) {
934                 cnt = (jack_nframes_t) floor (pages * one_page);
935         } else {
936                 if (was_floating) {
937                         cnt = (jack_nframes_t) floor (prefix * session->frame_rate());
938                 } else {
939                         cnt = (jack_nframes_t) floor (prefix * one_page);
940                 }
941         }
942
943         if (leftmost_frame < cnt) {
944                 frame = 0;
945         } else {
946                 frame = leftmost_frame - cnt;
947         }
948
949         reposition_x_origin (frame);
950 }
951
952 void
953 Editor::scroll_forward (float pages)
954 {
955         jack_nframes_t frame;
956         jack_nframes_t one_page = (jack_nframes_t) rint (canvas_width * frames_per_unit);
957         bool was_floating;
958         float prefix;
959         jack_nframes_t cnt;
960         
961         if (get_prefix (prefix, was_floating)) {
962                 cnt = (jack_nframes_t) floor (pages * one_page);
963         } else {
964                 if (was_floating) {
965                         cnt = (jack_nframes_t) floor (prefix * session->frame_rate());
966                 } else {
967                         cnt = (jack_nframes_t) floor (prefix * one_page);
968                 }
969         }
970
971         if (ULONG_MAX - cnt < leftmost_frame) {
972                 frame = ULONG_MAX - cnt;
973         } else {
974                 frame = leftmost_frame + cnt;
975         }
976
977         reposition_x_origin (frame);
978 }
979
980 void
981 Editor::scroll_tracks_down ()
982 {
983         float prefix;
984         bool was_floating;
985         int cnt;
986
987         if (get_prefix (prefix, was_floating)) {
988                 cnt = 1;
989         } else {
990                 cnt = (int) floor (prefix);
991         }
992
993         vertical_adjustment.set_value (vertical_adjustment.get_value() + (cnt * vertical_adjustment.get_page_size()));
994 }
995
996 void
997 Editor::scroll_tracks_up ()
998 {
999         float prefix;
1000         bool was_floating;
1001         int cnt;
1002
1003         if (get_prefix (prefix, was_floating)) {
1004                 cnt = 1;
1005         } else {
1006                 cnt = (int) floor (prefix);
1007         }
1008
1009         vertical_adjustment.set_value (vertical_adjustment.get_value() - (cnt * vertical_adjustment.get_page_size()));
1010 }
1011
1012 void
1013 Editor::scroll_tracks_down_line ()
1014 {
1015         Gtk::Adjustment* adj = edit_vscrollbar.get_adjustment();
1016         adj->set_value (adj->get_value() + 10);
1017 }
1018
1019 void
1020 Editor::scroll_tracks_up_line ()
1021 {
1022         Gtk::Adjustment* adj = edit_vscrollbar.get_adjustment();
1023         adj->set_value (adj->get_value() - 10);
1024 }
1025
1026 /* ZOOM */
1027
1028 void
1029 Editor::temporal_zoom_step (bool coarser)
1030 {
1031         double nfpu;
1032
1033         nfpu = frames_per_unit;
1034         
1035         if (coarser) { 
1036                 nfpu *= 2.0;
1037         } else { 
1038                 nfpu = max(1.0,(nfpu/2.0));
1039         }
1040
1041         temporal_zoom (nfpu);
1042 }       
1043
1044 void
1045 Editor::temporal_zoom (gdouble fpu)
1046 {
1047         if (!session) return;
1048         
1049         jack_nframes_t current_page = current_page_frames();
1050         jack_nframes_t current_leftmost = leftmost_frame;
1051         jack_nframes_t current_rightmost;
1052         jack_nframes_t current_center;
1053         jack_nframes_t new_page;
1054         jack_nframes_t leftmost_after_zoom = 0;
1055         double nfpu;
1056
1057         nfpu = fpu;
1058         
1059         new_page = (jack_nframes_t) floor (canvas_width * nfpu);
1060
1061         switch (zoom_focus) {
1062         case ZoomFocusLeft:
1063                 leftmost_after_zoom = current_leftmost;
1064                 break;
1065                 
1066         case ZoomFocusRight:
1067                 current_rightmost = leftmost_frame + current_page;
1068                 if (current_rightmost > new_page) {
1069                         leftmost_after_zoom = current_rightmost - new_page;
1070                 } else {
1071                         leftmost_after_zoom = 0;
1072                 }
1073                 break;
1074                 
1075         case ZoomFocusCenter:
1076                 current_center = current_leftmost + (current_page/2); 
1077                 if (current_center > (new_page/2)) {
1078                         leftmost_after_zoom = current_center - (new_page / 2);
1079                 } else {
1080                         leftmost_after_zoom = 0;
1081                 }
1082                 break;
1083                 
1084         case ZoomFocusPlayhead:
1085                 /* try to keep the playhead in the center */
1086                 if (playhead_cursor->current_frame > new_page/2) {
1087                         leftmost_after_zoom = playhead_cursor->current_frame - (new_page/2);
1088                 } else {
1089                         leftmost_after_zoom = 0;
1090                 }
1091                 break;
1092
1093         case ZoomFocusEdit:
1094                 /* try to keep the edit cursor in the center */
1095                 if (edit_cursor->current_frame > leftmost_frame + (new_page/2)) {
1096                         leftmost_after_zoom = edit_cursor->current_frame - (new_page/2);
1097                 } else {
1098                         leftmost_after_zoom = 0;
1099                 }
1100                 break;
1101                 
1102         }
1103  
1104         // leftmost_after_zoom = min (leftmost_after_zoom, session->current_end_frame());
1105
1106 //      begin_reversible_command (_("zoom"));
1107 //      session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), current_leftmost, frames_per_unit));
1108 //      session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_after_zoom, nfpu));
1109 //      commit_reversible_command ();
1110
1111         reposition_and_zoom (leftmost_after_zoom, nfpu);
1112 }       
1113
1114 void
1115 Editor::temporal_zoom_selection ()
1116 {
1117         if (!selection) return;
1118         
1119         if (selection->time.empty()) {
1120                 return;
1121         }
1122
1123         jack_nframes_t start = selection->time[clicked_selection].start;
1124         jack_nframes_t end = selection->time[clicked_selection].end;
1125
1126         temporal_zoom_by_frame (start, end, "zoom to selection");
1127 }
1128
1129 void
1130 Editor::temporal_zoom_session ()
1131 {
1132         if (session) {
1133                 temporal_zoom_by_frame (0, session->current_end_frame(), "zoom to session");
1134         }
1135 }
1136
1137 void
1138 Editor::temporal_zoom_by_frame (jack_nframes_t start, jack_nframes_t end, const string & op)
1139 {
1140         if (!session) return;
1141
1142         if ((start == 0 && end == 0) || end < start) {
1143                 return;
1144         }
1145
1146         jack_nframes_t range = end - start;
1147
1148         double new_fpu = (double)range / (double)canvas_width;
1149 //      double p2 = 1.0;
1150
1151 //      while (p2 < new_fpu) {
1152 //              p2 *= 2.0;
1153 //      }
1154 //      new_fpu = p2;
1155         
1156         jack_nframes_t new_page = (jack_nframes_t) floor (canvas_width * new_fpu);
1157         jack_nframes_t middle = (jack_nframes_t) floor( (double)start + ((double)range / 2.0f ));
1158         jack_nframes_t new_leftmost = (jack_nframes_t) floor( (double)middle - ((double)new_page/2.0f));
1159
1160         if (new_leftmost > middle) new_leftmost = 0;
1161
1162 //      begin_reversible_command (op);
1163 //      session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit));
1164 //      session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu));
1165 //      commit_reversible_command ();
1166
1167         reposition_and_zoom (new_leftmost, new_fpu);
1168 }
1169
1170 void 
1171 Editor::temporal_zoom_to_frame (bool coarser, jack_nframes_t frame)
1172 {
1173         if (!session) return;
1174         
1175         jack_nframes_t range_before = frame - leftmost_frame;
1176         double new_fpu;
1177         
1178         new_fpu = frames_per_unit;
1179         
1180         if (coarser) { 
1181                 new_fpu *= 2.0;
1182                 range_before *= 2;
1183         } else { 
1184                 new_fpu = max(1.0,(new_fpu/2.0));
1185                 range_before /= 2;
1186         }
1187
1188         if (new_fpu == frames_per_unit) return;
1189
1190         jack_nframes_t new_leftmost = frame - range_before;
1191
1192         if (new_leftmost > frame) new_leftmost = 0;
1193
1194 //      begin_reversible_command (_("zoom to frame"));
1195 //      session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit));
1196 //      session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu));
1197 //      commit_reversible_command ();
1198
1199         reposition_and_zoom (new_leftmost, new_fpu);
1200 }
1201
1202 void
1203 Editor::select_all_in_track (bool add)
1204 {
1205         list<Selectable *> touched;
1206
1207         if (!clicked_trackview) {
1208                 return;
1209         }
1210         
1211         clicked_trackview->get_selectables (0, max_frames, 0, DBL_MAX, touched);
1212
1213         if (add) {
1214                 selection->add (touched);
1215         } else {
1216                 selection->set (touched);
1217         }
1218 }
1219
1220 void
1221 Editor::select_all (bool add)
1222 {
1223         list<Selectable *> touched;
1224         
1225         for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1226                 if ((*iter)->hidden()) {
1227                         continue;
1228                 }
1229                 (*iter)->get_selectables (0, max_frames, 0, DBL_MAX, touched);
1230         }
1231
1232         if (add) {
1233                 selection->add (touched);
1234         } else {
1235                 selection->set (touched);
1236         }
1237
1238 }
1239
1240 void
1241 Editor::invert_selection_in_track ()
1242 {
1243         list<Selectable *> touched;
1244
1245         if (!clicked_trackview) {
1246                 return;
1247         }
1248         
1249         clicked_trackview->get_inverted_selectables (*selection, touched);
1250         selection->set (touched);
1251 }
1252
1253 void
1254 Editor::invert_selection ()
1255 {
1256         list<Selectable *> touched;
1257         
1258         for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1259                 if ((*iter)->hidden()) {
1260                         continue;
1261                 }
1262                 (*iter)->get_inverted_selectables (*selection, touched);
1263         }
1264
1265         selection->set (touched);
1266 }
1267
1268 bool
1269 Editor::select_all_within (jack_nframes_t start, jack_nframes_t end, double top, double bot, bool add)
1270 {
1271         list<Selectable *> touched;
1272         
1273         for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1274                 if ((*iter)->hidden()) {
1275                         continue;
1276                 }
1277                 (*iter)->get_selectables (start, end, top, bot, touched);
1278         }
1279
1280         if (add) {
1281                 selection->add (touched);
1282         } else {
1283                 selection->set (touched);
1284         }
1285
1286         return !touched.empty();
1287 }
1288
1289 void
1290 Editor::set_selection_from_punch()
1291 {
1292         Location* location;
1293
1294         if ((location = session->locations()->auto_punch_location()) == 0)  {
1295                 return;
1296         }
1297
1298         set_selection_from_range (*location);
1299 }
1300
1301 void
1302 Editor::set_selection_from_loop()
1303 {
1304         Location* location;
1305
1306         if ((location = session->locations()->auto_loop_location()) == 0)  {
1307                 return;
1308         }
1309         set_selection_from_range (*location);
1310 }
1311
1312 void
1313 Editor::select_all_from_punch()
1314 {
1315         Location* location;
1316         list<Selectable *> touched;
1317         if ((location = session->locations()->auto_punch_location()) == 0)  {
1318                 return;
1319         }
1320
1321         for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1322                 if ((*iter)->hidden()) {
1323                         continue;
1324                 }
1325                 (*iter)->get_selectables (location->start(), location->end(), 0, DBL_MAX, touched);
1326         }
1327         begin_reversible_command (_("select all from punch"));
1328         selection->set (touched);
1329         commit_reversible_command ();
1330
1331 }
1332
1333 void
1334 Editor::select_all_from_loop()
1335 {
1336         Location* location;
1337         list<Selectable *> touched;
1338
1339         if ((location = session->locations()->auto_loop_location()) == 0)  {
1340                 return;
1341         }
1342         for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1343                 if ((*iter)->hidden()) {
1344                         continue;
1345                 }
1346                 (*iter)->get_selectables (location->start(), location->end(), 0, DBL_MAX, touched);
1347         }
1348         begin_reversible_command (_("select all from loop"));
1349         selection->set (touched);
1350         commit_reversible_command ();
1351
1352 }
1353
1354 void
1355 Editor::set_selection_from_range (Location& range)
1356 {
1357         if (clicked_trackview == 0) {
1358                 return;
1359         }
1360         
1361         begin_reversible_command (_("set selection from range"));
1362         selection->set (0, range.start(), range.end());
1363         commit_reversible_command ();
1364 }
1365
1366 void
1367 Editor::select_all_after_cursor (Cursor *cursor, bool after)
1368 {
1369         jack_nframes_t start;
1370         jack_nframes_t end;
1371         list<Selectable *> touched;
1372
1373         if (after) {
1374           begin_reversible_command (_("select all after cursor"));
1375           start = cursor->current_frame ;
1376           end = session->current_end_frame();
1377         } else {
1378           begin_reversible_command (_("select all before cursor"));
1379           start = 0;
1380           end = cursor->current_frame ;
1381         }
1382         for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1383                 if ((*iter)->hidden()) {
1384                         continue;
1385                 }
1386                 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1387         }
1388         selection->set (touched);
1389         commit_reversible_command ();
1390 }
1391
1392 void
1393 Editor::amplitude_zoom_step (bool in)
1394 {
1395         gdouble zoom = 1.0;
1396
1397         if (in) {
1398                 zoom *= 2.0;
1399         } else {
1400                 if (zoom > 2.0) {
1401                         zoom /= 2.0;
1402                 } else {
1403                         zoom = 1.0;
1404                 }
1405         }
1406
1407 #ifdef FIX_FOR_CANVAS
1408         /* XXX DO SOMETHING */
1409 #endif
1410 }       
1411
1412
1413 /* DELETION */
1414
1415
1416 void
1417 Editor::delete_sample_forward ()
1418 {
1419 }
1420
1421 void
1422 Editor::delete_sample_backward ()
1423 {
1424 }
1425
1426 void
1427 Editor::delete_screen ()
1428 {
1429 }
1430
1431 /* SEARCH */
1432
1433 void
1434 Editor::search_backwards ()
1435 {
1436         /* what ? */
1437 }
1438
1439 void
1440 Editor::search_forwards ()
1441 {
1442         /* what ? */
1443 }
1444
1445 /* MARKS */
1446
1447 void
1448 Editor::jump_forward_to_mark ()
1449 {
1450         if (!session) {
1451                 return;
1452         }
1453         
1454         Location *location = session->locations()->first_location_after (playhead_cursor->current_frame);
1455
1456         if (location) {
1457                 session->request_locate (location->start(), session->transport_rolling());
1458         } else {
1459                 session->request_locate (session->current_end_frame());
1460         }
1461 }
1462
1463 void
1464 Editor::jump_backward_to_mark ()
1465 {
1466         if (!session) {
1467                 return;
1468         }
1469
1470         Location *location = session->locations()->first_location_before (playhead_cursor->current_frame);
1471         
1472         if (location) {
1473                 session->request_locate (location->start(), session->transport_rolling());
1474         } else {
1475                 session->request_locate (0);
1476         }
1477 }
1478
1479 void
1480 Editor::set_mark ()
1481 {
1482         jack_nframes_t pos;
1483         float prefix;
1484         bool was_floating;
1485
1486         if (get_prefix (prefix, was_floating)) {
1487                 pos = session->audible_frame ();
1488         } else {
1489                 if (was_floating) {
1490                         pos = (jack_nframes_t) floor (prefix * session->frame_rate ());
1491                 } else {
1492                         pos = (jack_nframes_t) floor (prefix);
1493                 }
1494         }
1495
1496         session->locations()->add (new Location (pos, 0, "mark", Location::IsMark), true);
1497 }
1498
1499 void
1500 Editor::clear_markers ()
1501 {
1502         if (session) {
1503                 session->begin_reversible_command (_("clear markers"));
1504                 session->add_undo (session->locations()->get_memento());
1505                 session->locations()->clear_markers ();
1506                 session->add_redo_no_execute (session->locations()->get_memento());
1507                 session->commit_reversible_command ();
1508         }
1509 }
1510
1511 void
1512 Editor::clear_ranges ()
1513 {
1514         if (session) {
1515                 session->begin_reversible_command (_("clear ranges"));
1516                 session->add_undo (session->locations()->get_memento());
1517                 
1518                 Location * looploc = session->locations()->auto_loop_location();
1519                 Location * punchloc = session->locations()->auto_punch_location();
1520                 
1521                 session->locations()->clear_ranges ();
1522                 // re-add these
1523                 if (looploc) session->locations()->add (looploc);
1524                 if (punchloc) session->locations()->add (punchloc);
1525                 
1526                 session->add_redo_no_execute (session->locations()->get_memento());
1527                 session->commit_reversible_command ();
1528         }
1529 }
1530
1531 void
1532 Editor::clear_locations ()
1533 {
1534         session->begin_reversible_command (_("clear locations"));
1535         session->add_undo (session->locations()->get_memento());
1536         session->locations()->clear ();
1537         session->add_redo_no_execute (session->locations()->get_memento());
1538         session->commit_reversible_command ();
1539         session->locations()->clear ();
1540 }
1541
1542 /* INSERT/REPLACE */
1543
1544 void
1545 Editor::insert_region_list_drag (AudioRegion& region, int x, int y)
1546 {
1547         double wx, wy;
1548         double cx, cy;
1549         TimeAxisView *tv;
1550         jack_nframes_t where;
1551         AudioTimeAxisView *atv = 0;
1552         Playlist *playlist;
1553         
1554         track_canvas.window_to_world (x, y, wx, wy);
1555         wx += horizontal_adjustment.get_value();
1556         wy += vertical_adjustment.get_value();
1557
1558         GdkEvent event;
1559         event.type = GDK_BUTTON_RELEASE;
1560         event.button.x = wx;
1561         event.button.y = wy;
1562         
1563         where = event_frame (&event, &cx, &cy);
1564
1565         if (where < leftmost_frame || where > leftmost_frame + current_page_frames()) {
1566                 /* clearly outside canvas area */
1567                 return;
1568         }
1569         
1570         if ((tv = trackview_by_y_position (cy)) == 0) {
1571                 return;
1572         }
1573         
1574         if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) == 0) {
1575                 return;
1576         }
1577
1578         if ((playlist = atv->playlist()) == 0) {
1579                 return;
1580         }
1581         
1582         snap_to (where);
1583         
1584         begin_reversible_command (_("insert dragged region"));
1585         session->add_undo (playlist->get_memento());
1586         playlist->add_region (*(new AudioRegion (region)), where, 1.0);
1587         session->add_redo_no_execute (playlist->get_memento());
1588         commit_reversible_command ();
1589 }
1590
1591 void
1592 Editor::insert_region_list_selection (float times)
1593 {
1594         AudioTimeAxisView *tv = 0;
1595         Playlist *playlist;
1596
1597         if (clicked_audio_trackview != 0) {
1598                 tv = clicked_audio_trackview;
1599         } else if (!selection->tracks.empty()) {
1600                 if ((tv = dynamic_cast<AudioTimeAxisView*>(selection->tracks.front())) == 0) {
1601                         return;
1602                 }
1603         } else {
1604                 return;
1605         }
1606
1607         if ((playlist = tv->playlist()) == 0) {
1608                 return;
1609         }
1610         
1611         Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
1612         
1613         if (selected->count_selected_rows() != 1) {
1614                 return;
1615         }
1616         
1617         TreeModel::iterator i = region_list_display.get_selection()->get_selected();
1618         Region* region = (*i)[region_list_columns.region];
1619
1620         begin_reversible_command (_("insert region"));
1621         session->add_undo (playlist->get_memento());
1622         playlist->add_region (*(createRegion (*region)), edit_cursor->current_frame, times);
1623         session->add_redo_no_execute (playlist->get_memento());
1624         commit_reversible_command ();
1625 }
1626
1627
1628 /* BUILT-IN EFFECTS */
1629
1630 void
1631 Editor::reverse_selection ()
1632 {
1633
1634 }
1635
1636 /* GAIN ENVELOPE EDITING */
1637
1638 void
1639 Editor::edit_envelope ()
1640 {
1641 }
1642
1643 /* PLAYBACK */
1644
1645 void
1646 Editor::toggle_playback (bool with_abort)
1647 {
1648         if (!session) {
1649                 return;
1650         }
1651
1652         switch (session->slave_source()) {
1653         case Session::None:
1654         case Session::JACK:
1655                 break;
1656         default:
1657                 /* transport controlled by the master */
1658                 return;
1659         }
1660
1661         if (session->is_auditioning()) {
1662                 session->cancel_audition ();
1663                 return;
1664         }
1665         
1666         if (session->transport_rolling()) {
1667                 session->request_stop (with_abort);
1668                 if (session->get_auto_loop()) {
1669                         session->request_auto_loop (false);
1670                 }
1671         } else {
1672                 session->request_transport_speed (1.0f);
1673         }
1674 }
1675
1676 void
1677 Editor::play_from_start ()
1678 {
1679         session->request_locate (0, true);
1680 }
1681
1682 void
1683 Editor::play_selection ()
1684 {
1685         if (selection->time.empty()) {
1686                 return;
1687         }
1688
1689         session->request_play_range (true);
1690 }
1691
1692 void
1693 Editor::play_selected_region ()
1694 {
1695         if (!selection->audio_regions.empty()) {
1696                 AudioRegionView *rv = *(selection->audio_regions.begin());
1697
1698                 session->request_bounded_roll (rv->region.position(), rv->region.last_frame()); 
1699         }
1700 }
1701
1702 void
1703 Editor::loop_selected_region ()
1704 {
1705         if (!selection->audio_regions.empty()) {
1706                 AudioRegionView *rv = *(selection->audio_regions.begin());
1707                 Location* tll;
1708
1709                 if ((tll = transport_loop_location()) != 0)  {
1710
1711                         tll->set (rv->region.position(), rv->region.last_frame());
1712                         
1713                         // enable looping, reposition and start rolling
1714
1715                         session->request_auto_loop (true);
1716                         session->request_locate (tll->start(), false);
1717                         session->request_transport_speed (1.0f);
1718                 }
1719         }
1720 }
1721
1722 void
1723 Editor::play_location (Location& location)
1724 {
1725         if (location.start() <= location.end()) {
1726                 return;
1727         }
1728
1729         session->request_bounded_roll (location.start(), location.end());
1730 }
1731
1732 void
1733 Editor::loop_location (Location& location)
1734 {
1735         if (location.start() <= location.end()) {
1736                 return;
1737         }
1738
1739         Location* tll;
1740
1741         if ((tll = transport_loop_location()) != 0) {
1742                 tll->set (location.start(), location.end());
1743
1744                 // enable looping, reposition and start rolling
1745                 session->request_auto_loop (true);
1746                 session->request_locate (tll->start(), true);
1747         }
1748 }
1749
1750 void 
1751 Editor::toggle_region_mute ()
1752 {
1753         if (clicked_regionview) {
1754                 clicked_regionview->region.set_muted (!clicked_regionview->region.muted());
1755         } else if (!selection->audio_regions.empty()) {
1756                 bool yn = ! (*selection->audio_regions.begin())->region.muted();
1757                 selection->foreach_audio_region (&AudioRegion::set_muted, yn);
1758         }
1759 }
1760
1761 void
1762 Editor::toggle_region_opaque ()
1763 {
1764         if (clicked_regionview) {
1765                 clicked_regionview->region.set_opaque (!clicked_regionview->region.opaque());
1766         } else if (!selection->audio_regions.empty()) {
1767                 bool yn = ! (*selection->audio_regions.begin())->region.opaque();
1768                 selection->foreach_audio_region (&Region::set_opaque, yn);
1769         }
1770 }
1771
1772 void
1773 Editor::raise_region ()
1774 {
1775         selection->foreach_audio_region (&Region::raise);
1776 }
1777
1778 void
1779 Editor::raise_region_to_top ()
1780 {
1781         selection->foreach_audio_region (&Region::raise_to_top);
1782 }
1783
1784 void
1785 Editor::lower_region ()
1786 {
1787         selection->foreach_audio_region (&Region::lower);
1788 }
1789
1790 void
1791 Editor::lower_region_to_bottom ()
1792 {
1793         selection->foreach_audio_region (&Region::lower_to_bottom);
1794 }
1795
1796 void
1797 Editor::edit_region ()
1798 {
1799         if (clicked_regionview == 0) {
1800                 return;
1801         }
1802         
1803         clicked_regionview->show_region_editor ();
1804 }
1805
1806 void
1807 Editor::rename_region ()
1808 {
1809         Dialog dialog;
1810         Entry  entry;
1811         Button ok_button (_("OK"));
1812         Button cancel_button (_("Cancel"));
1813
1814         if (selection->audio_regions.empty()) {
1815                 return;
1816         }
1817
1818         dialog.set_title (_("ardour: rename region"));
1819         dialog.set_name ("RegionRenameWindow");
1820         dialog.set_size_request (300, -1);
1821         dialog.set_position (Gtk::WIN_POS_MOUSE);
1822         dialog.set_modal (true);
1823
1824         dialog.get_vbox()->set_border_width (10);
1825         dialog.get_vbox()->pack_start (entry);
1826         dialog.get_action_area()->pack_start (ok_button);
1827         dialog.get_action_area()->pack_start (cancel_button);
1828
1829         entry.set_name ("RegionNameDisplay");
1830         ok_button.set_name ("EditorGTKButton");
1831         cancel_button.set_name ("EditorGTKButton");
1832
1833         region_renamed = false;
1834
1835         entry.signal_activate().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
1836         ok_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
1837         cancel_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::rename_region_finished), false));
1838
1839         /* recurse */
1840
1841         dialog.show_all ();
1842         Main::run ();
1843
1844         if (region_renamed) {
1845                 (*selection->audio_regions.begin())->region.set_name (entry.get_text());
1846                 redisplay_regions ();
1847         }
1848 }
1849
1850 void
1851 Editor::rename_region_finished (bool status)
1852
1853 {
1854         region_renamed = status;
1855         Main::quit ();
1856 }
1857
1858 void
1859 Editor::audition_playlist_region_via_route (AudioRegion& region, Route& route)
1860 {
1861         if (session->is_auditioning()) {
1862                 session->cancel_audition ();
1863         } 
1864
1865         // note: some potential for creativity here, because region doesn't
1866         // have to belong to the playlist that Route is handling
1867
1868         // bool was_soloed = route.soloed();
1869
1870         route.set_solo (true, this);
1871         
1872         session->request_bounded_roll (region.position(), region.position() + region.length());
1873         
1874         /* XXX how to unset the solo state ? */
1875 }
1876
1877 void
1878 Editor::audition_selected_region ()
1879 {
1880         if (!selection->audio_regions.empty()) {
1881                 AudioRegionView* rv = *(selection->audio_regions.begin());
1882                 session->audition_region (rv->region);
1883         }
1884 }
1885
1886 void
1887 Editor::audition_playlist_region_standalone (AudioRegion& region)
1888 {
1889         session->audition_region (region);
1890 }
1891
1892 void
1893 Editor::build_interthread_progress_window ()
1894 {
1895         interthread_progress_window = new ArdourDialog (X_("interthread progress"), true);
1896
1897         interthread_progress_bar.set_orientation (Gtk::PROGRESS_LEFT_TO_RIGHT);
1898         
1899         interthread_progress_window->get_vbox()->pack_start (interthread_progress_label, false, false);
1900         interthread_progress_window->get_vbox()->pack_start (interthread_progress_bar,false, false);
1901
1902         // GTK2FIX: this button needs a modifiable label
1903
1904         Button* b = interthread_progress_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1905         b->signal_clicked().connect (mem_fun(*this, &Editor::interthread_cancel_clicked));
1906
1907         interthread_cancel_button.add (interthread_cancel_label);
1908
1909         interthread_progress_window->set_default_size (200, 100);
1910 }
1911
1912 void
1913 Editor::interthread_cancel_clicked ()
1914 {
1915         if (current_interthread_info) {
1916                 current_interthread_info->cancel = true;
1917         }
1918 }
1919
1920 void *
1921 Editor::_import_thread (void *arg)
1922 {
1923         PBD::ThreadCreated (pthread_self(), X_("Import"));
1924
1925         Editor *ed = (Editor *) arg;
1926         return ed->import_thread ();
1927 }
1928
1929 void *
1930 Editor::import_thread ()
1931 {
1932         session->import_audiofile (import_status);
1933         return 0;
1934 }
1935
1936 gint
1937 Editor::import_progress_timeout (void *arg)
1938 {
1939         interthread_progress_label.set_text (import_status.doing_what);
1940
1941         if (import_status.freeze) {
1942                 interthread_cancel_button.set_sensitive(false);
1943         } else {
1944                 interthread_cancel_button.set_sensitive(true);
1945         }
1946
1947         if (import_status.doing_what == "building peak files") {
1948                 interthread_progress_bar.pulse ();
1949                 return FALSE;
1950         } else {
1951                 interthread_progress_bar.set_fraction (import_status.progress/100);
1952         }
1953
1954         return !(import_status.done || import_status.cancel);
1955 }
1956
1957 void
1958 Editor::import_audio (bool as_tracks)
1959 {
1960         if (session == 0) {
1961                 warning << _("You can't import an audiofile until you have a session loaded.") << endmsg;
1962                 return;
1963         }
1964
1965         string str;
1966
1967         if (as_tracks) {
1968                 str =_("Import selected as tracks");
1969         } else {
1970                 str = _("Import selected to region list");
1971         }
1972
1973         SoundFileOmega sfdb (str);
1974         sfdb.Imported.connect (bind (mem_fun (*this, &Editor::do_import), as_tracks));
1975
1976         sfdb.run();
1977 }
1978
1979 void
1980 Editor::catch_new_audio_region (AudioRegion* ar)
1981 {
1982         last_audio_region = ar;
1983 }
1984
1985 void
1986 Editor::do_import (vector<string> paths, bool split, bool as_tracks)
1987 {
1988         sigc::connection c;
1989         
1990         /* SFDB sets "multichan" to true to indicate "split channels"
1991            so reverse the setting to match the way libardour
1992            interprets it.
1993         */
1994         
1995         import_status.multichan = !split;
1996
1997         if (interthread_progress_window == 0) {
1998                 build_interthread_progress_window ();
1999         }
2000         
2001         interthread_progress_window->set_title (_("ardour: audio import in progress"));
2002         interthread_progress_window->set_position (Gtk::WIN_POS_MOUSE);
2003         interthread_progress_window->show_all ();
2004         interthread_progress_bar.set_fraction (0.0f);
2005         interthread_cancel_label.set_text (_("Cancel Import"));
2006         current_interthread_info = &import_status;
2007
2008         c = session->AudioRegionAdded.connect (mem_fun(*this, &Editor::catch_new_audio_region));
2009
2010         for (vector<string>::iterator i = paths.begin(); i != paths.end(); ++i ) {
2011
2012                 interthread_progress_window->set_title (string_compose (_("ardour: importing %1"), (*i)));
2013         
2014                 import_status.pathname = (*i);
2015                 import_status.done = false;
2016                 import_status.cancel = false;
2017                 import_status.freeze = false;
2018                 import_status.done = 0.0;
2019                 
2020                 interthread_progress_connection = 
2021                   Glib::signal_timeout().connect (bind (mem_fun(*this, &Editor::import_progress_timeout), (gpointer) 0), 100);
2022                 
2023                 last_audio_region = 0;
2024                 
2025                 pthread_create_and_store ("import", &import_status.thread, 0, _import_thread, this);
2026                 pthread_detach (import_status.thread);
2027                 
2028                 while (!(import_status.done || import_status.cancel)) {
2029                         gtk_main_iteration ();
2030                 }
2031                 
2032                 import_status.done = true;
2033                 interthread_progress_connection.disconnect ();
2034
2035                 if (as_tracks && last_audio_region != 0) {
2036                         uint32_t channels = last_audio_region->n_channels();
2037
2038                         AudioTrack* at = session->new_audio_track (channels, channels);
2039                         AudioRegion* copy = new AudioRegion (*last_audio_region);
2040                         at->disk_stream().playlist()->add_region (*copy, 0);
2041                 }
2042         }
2043
2044         c.disconnect ();
2045         interthread_progress_window->hide_all ();
2046 }
2047
2048 int
2049 Editor::reject_because_rate_differs (const string & path, SF_INFO& finfo, const string & action, bool multiple_pending)
2050 {
2051         if (!session) {
2052                 return 1;
2053         }
2054
2055         if (finfo.samplerate != (int) session->frame_rate()) {
2056                 vector<string> choices;
2057
2058                 choices.push_back (string_compose (_("%1 it anyway"), action));
2059
2060                 if (multiple_pending) {
2061                         /* XXX assumptions about sentence structure
2062                            here for translators. Sorry.
2063                         */
2064                         choices.push_back (string_compose (_("Don't %1 it"), action));
2065                         choices.push_back (string_compose (_("%1 all without questions"), action));
2066                         choices.push_back (_("Cancel entire import"));
2067                 } else {
2068                         choices.push_back (_("Cancel"));
2069                 }
2070
2071                 Gtkmm2ext::Choice rate_choice (
2072                         string_compose (_("%1\nThis audiofile's sample rate doesn't match the session sample rate!"), path),
2073                         choices);
2074
2075                 rate_choice.chosen.connect (ptr_fun (Main::quit));
2076                 rate_choice.show_all ();
2077
2078                 Main::run ();
2079
2080                 switch (rate_choice.get_choice()) {
2081                 case 0: /* do it anyway */
2082                         return 0;
2083                 case 1: /* don't import this one */
2084                         return 1;
2085                 case 2: /* do the rest without asking */
2086                         return -1;
2087                 case 3: /* stop a multi-file import */
2088                 default:
2089                         return -2;
2090                 }
2091         }
2092
2093         return 0;
2094 }
2095
2096 void 
2097 Editor::embed_audio ()
2098 {
2099         if (session == 0) {
2100                 warning << _("You can't embed an audiofile until you have a session loaded.") << endmsg;
2101                 return;
2102         }
2103
2104         SoundFileOmega sfdb (_("Add to External Region list"));
2105         sfdb.Embedded.connect (mem_fun (*this, &Editor::do_embed_sndfiles));
2106
2107         sfdb.run ();
2108 }
2109
2110 void
2111 Editor::do_embed_sndfiles (vector<string> paths, bool split)
2112 {
2113         bool multiple_files = paths.size() > 1;
2114         bool check_sample_rate = true;
2115
2116         for (vector<string>::iterator i = paths.begin(); i != paths.end(); ++i) {
2117                 embed_sndfile (*i, split, multiple_files, check_sample_rate);
2118         }
2119
2120         session->save_state ("");
2121 }
2122
2123 void
2124 Editor::embed_sndfile (string path, bool split, bool multiple_files, bool& check_sample_rate)
2125 {
2126         SndFileSource *source = 0; /* keep g++ quiet */
2127         AudioRegion::SourceList sources;
2128         string idspec;
2129         string linked_path;
2130         SNDFILE *sf;
2131         SF_INFO finfo;
2132
2133         /* lets see if we can link it into the session */
2134         
2135         linked_path = session->sound_dir();
2136         linked_path += PBD::basename (path);
2137
2138         if (link (path.c_str(), linked_path.c_str()) == 0) {
2139
2140                 /* there are many reasons why link(2) might have failed.
2141                    but if it succeeds, we now have a link in the
2142                    session sound dir that will protect against
2143                    unlinking of the original path. nice.
2144                 */
2145
2146                 path = linked_path;
2147         }
2148
2149         memset (&finfo, 0, sizeof(finfo));
2150
2151         /* note that we temporarily truncated _id at the colon */
2152         
2153         if ((sf = sf_open (path.c_str(), SFM_READ, &finfo)) == 0) {
2154                 char errbuf[256];
2155                 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
2156                 error << string_compose(_("Editor: cannot open file \"%1\" (%2)"), selection, errbuf) << endmsg;
2157                 return;
2158         }
2159         sf_close (sf);
2160         sf = 0;
2161         
2162         if (check_sample_rate) {
2163                 switch (reject_because_rate_differs (path, finfo, "Embed", multiple_files)) {
2164                 case 0:
2165                         break;
2166                 case 1:
2167                         return;
2168                 case -1:
2169                         check_sample_rate = false;
2170                         break;
2171                         
2172                 case -2:
2173                 default:
2174                         return;
2175                 }
2176         }
2177
2178         track_canvas.get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
2179         ARDOUR_UI::instance()->flush_pending ();
2180
2181         /* make the proper number of channels in the region */
2182
2183         for (int n=0; n < finfo.channels; ++n)
2184         {
2185                 idspec = path;
2186                 idspec += string_compose(":%1", n);
2187                 
2188                 try {
2189                         source = new SndFileSource (idspec.c_str());
2190                         sources.push_back(source);
2191                 } 
2192
2193                 catch (failed_constructor& err) {
2194                         error << string_compose(_("could not open %1"), path) << endmsg;
2195                         goto out;
2196                 }
2197
2198                 ARDOUR_UI::instance()->flush_pending ();
2199         }
2200
2201         if (sources.size() > 0) {
2202
2203                 string region_name = PBD::basename_nosuffix (path);
2204                 region_name += "-0";
2205
2206                 /* The created region isn't dropped.  It emits a signal
2207                    that is picked up by the session. 
2208                 */
2209
2210                 new AudioRegion (sources, 0, sources[0]->length(), region_name, 0,
2211                                  Region::Flag (Region::DefaultFlags|Region::WholeFile|Region::External));
2212                 
2213                 /* make sure we can see it in the list */
2214
2215                 /* its the second node, always */
2216
2217                 // GTK2FIX ?? is it still always the 2nd node
2218
2219                 TreeModel::Path path ("2");
2220                 region_list_display.expand_row (path, true);
2221
2222                 ARDOUR_UI::instance()->flush_pending ();
2223         }
2224
2225   out:
2226         track_canvas.get_window()->set_cursor (*current_canvas_cursor);
2227 }
2228
2229 void
2230 Editor::insert_sndfile (bool as_tracks)
2231 {
2232 //      SoundFileSelector& sfdb (ARDOUR_UI::instance()->get_sfdb_window());
2233         sigc::connection c;
2234         string str;
2235
2236         if (as_tracks) {
2237
2238 //              c = sfdb.Action.connect (mem_fun(*this, &Editor::insert_paths_as_new_tracks));
2239                 str = _("Insert selected as new tracks");
2240
2241         } else {
2242
2243                 jack_nframes_t pos;
2244
2245                 if (clicked_audio_trackview == 0) {
2246                         return;
2247                 }
2248
2249                 if (ensure_cursor (&pos)) {
2250                         return;
2251                 }
2252
2253 //              c = sfdb.Action.connect (bind (mem_fun(*this, &Editor::do_insert_sndfile), pos));
2254                 str = _("Insert selected");
2255         }
2256
2257 //      sfdb.run (str, false);
2258 //      c.disconnect ();
2259 }
2260
2261 void
2262 Editor::insert_paths_as_new_tracks (vector<string> paths, bool split)
2263 {
2264         SNDFILE *sf;
2265         SF_INFO finfo;
2266         bool multiple_files;
2267         bool check_sample_rate = true;
2268
2269         multiple_files = paths.size() > 1;      
2270
2271         for (vector<string>::iterator p = paths.begin(); p != paths.end(); ++p) {
2272                 
2273                 memset (&finfo, 0, sizeof(finfo));
2274                 
2275                 if ((sf = sf_open ((*p).c_str(), SFM_READ, &finfo)) == 0) {
2276                         char errbuf[256];
2277                         sf_error_str (0, errbuf, sizeof (errbuf) - 1);
2278                         error << string_compose(_("Editor: cannot open file \"%1\" (%2)"), (*p), errbuf) << endmsg;
2279                         continue;
2280                 }
2281                 
2282                 sf_close (sf);
2283                 sf = 0;
2284                 
2285                 /* add a new track */
2286                 
2287                 if (check_sample_rate) {
2288                         switch (reject_because_rate_differs (*p, finfo, "Insert", multiple_files)) {
2289                         case 0:
2290                                 break;
2291                         case 1:
2292                                 continue;
2293                         case -1:
2294                                 check_sample_rate = false;
2295                                 break;
2296                                 
2297                         case -2:
2298                                 return;
2299                         }
2300                 }
2301                 
2302                 uint32_t input_chan = finfo.channels;
2303                 uint32_t output_chan;
2304                 
2305                 if (session->get_output_auto_connect() & Session::AutoConnectMaster) {
2306                         output_chan = (session->master_out() ? session->master_out()->n_inputs() : input_chan);
2307                 } else {
2308                         output_chan = input_chan;
2309                 }
2310                 
2311                 (void) session->new_audio_track (input_chan, output_chan);
2312
2313
2314                 /* get the last (most recently added) track view */
2315         
2316                 AudioTimeAxisView* tv;
2317         
2318                 if ((tv = dynamic_cast<AudioTimeAxisView*>(track_views.back())) == 0) {
2319                         fatal << _("programming error: ")
2320                               << X_("last trackview after new_audio_track is not an audio track!")
2321                               << endmsg;
2322                         /*NOTREACHED*/
2323                 }
2324                 
2325                 jack_nframes_t pos = 0;
2326                 insert_sndfile_into (*p, true, tv, pos, false);
2327         }
2328 }
2329
2330 void
2331 Editor::do_insert_sndfile (vector<string> paths, bool split, jack_nframes_t pos)
2332 {
2333         for (vector<string>::iterator x = paths.begin(); x != paths.end(); ++x) {
2334                 insert_sndfile_into (*x, !split, clicked_audio_trackview, pos);
2335         }
2336 }
2337
2338 void
2339 Editor::insert_sndfile_into (const string & path, bool multi, AudioTimeAxisView* tv, jack_nframes_t& pos, bool prompt)
2340 {
2341         SndFileSource *source = 0; /* keep g++ quiet */
2342         AudioRegion::SourceList sources;
2343         string idspec;
2344         SNDFILE *sf;
2345         SF_INFO finfo;
2346
2347         memset (&finfo, 0, sizeof(finfo));
2348
2349         /* note that we temporarily truncated _id at the colon */
2350         
2351         if ((sf = sf_open (path.c_str(), SFM_READ, &finfo)) == 0) {
2352                 char errbuf[256];
2353                 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
2354                 error << string_compose(_("Editor: cannot open file \"%1\" (%2)"), path, errbuf) << endmsg;
2355                 return;
2356         }
2357         sf_close (sf);
2358         sf = 0;
2359         
2360         if (prompt && (reject_because_rate_differs (path, finfo, "Insert", false) != 0)) {
2361                 return;
2362         }
2363
2364         track_canvas.get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
2365         ARDOUR_UI::instance()->flush_pending ();
2366
2367         /* make the proper number of channels in the region */
2368
2369         for (int n=0; n < finfo.channels; ++n)
2370         {
2371                 idspec = path;
2372                 idspec += string_compose(":%1", n);
2373
2374                 try {
2375                         source = new SndFileSource (idspec.c_str());
2376                         sources.push_back(source);
2377                 } 
2378
2379                 catch (failed_constructor& err) {
2380                         error << string_compose(_("could not open %1"), path) << endmsg;
2381                         goto out;
2382                 }
2383
2384                 ARDOUR_UI::instance()->flush_pending ();
2385         }
2386
2387         if (sources.size() > 0) {
2388
2389                 string region_name = region_name_from_path (PBD::basename (path));
2390                 
2391                 AudioRegion *region = new AudioRegion (sources, 0, sources[0]->length(), region_name, 
2392                                                        0, /* irrelevant these days */
2393                                                        Region::Flag (Region::DefaultFlags|Region::WholeFile|Region::External));
2394
2395                 begin_reversible_command (_("insert sndfile"));
2396                 session->add_undo (tv->playlist()->get_memento());
2397                 tv->playlist()->add_region (*region, pos);
2398                 session->add_redo_no_execute (tv->playlist()->get_memento());
2399                 commit_reversible_command ();
2400                 
2401                 pos += sources[0]->length();
2402
2403                 ARDOUR_UI::instance()->flush_pending ();
2404         }
2405
2406   out:
2407         track_canvas.get_window()->set_cursor (*current_canvas_cursor);
2408         return;
2409 }
2410
2411 void
2412 Editor::region_from_selection ()
2413 {
2414         if (clicked_trackview == 0) {
2415                 return;
2416         }
2417
2418         if (selection->time.empty()) {
2419                 return;
2420         }
2421
2422         jack_nframes_t start = selection->time[clicked_selection].start;
2423         jack_nframes_t end = selection->time[clicked_selection].end;
2424
2425         jack_nframes_t selection_cnt = end - start + 1;
2426         
2427         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2428
2429                 AudioRegion *region;
2430                 AudioRegion *current;
2431                 Region* current_r;
2432                 Playlist *pl;
2433
2434                 jack_nframes_t internal_start;
2435                 string new_name;
2436
2437                 if ((pl = (*i)->playlist()) == 0) {
2438                         continue;
2439                 }
2440
2441                 if ((current_r = pl->top_region_at (start)) == 0) {
2442                         continue;
2443                 }
2444
2445                 if ((current = dynamic_cast<AudioRegion*> (current_r)) != 0) {
2446                         internal_start = start - current->position();
2447                         session->region_name (new_name, current->name(), true);
2448                         region = new AudioRegion (*current, internal_start, selection_cnt, new_name);
2449                 }
2450         }
2451 }       
2452
2453 void
2454 Editor::create_region_from_selection (vector<AudioRegion *>& new_regions)
2455 {
2456         if (selection->time.empty() || selection->tracks.empty()) {
2457                 return;
2458         }
2459
2460         jack_nframes_t start = selection->time[clicked_selection].start;
2461         jack_nframes_t end = selection->time[clicked_selection].end;
2462         
2463         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2464
2465                 AudioRegion* current;
2466                 Region* current_r;
2467                 Playlist* playlist;
2468                 jack_nframes_t internal_start;
2469                 string new_name;
2470
2471                 if ((playlist = (*i)->playlist()) == 0) {
2472                         continue;
2473                 }
2474
2475                 if ((current_r = playlist->top_region_at(start)) == 0) {
2476                         continue;
2477                 }
2478
2479                 if ((current = dynamic_cast<AudioRegion*>(current_r)) == 0) {
2480                         continue;
2481                 }
2482         
2483                 internal_start = start - current->position();
2484                 session->region_name (new_name, current->name(), true);
2485                 
2486                 new_regions.push_back (new AudioRegion (*current, internal_start, end - start + 1, new_name));
2487         }
2488 }
2489
2490 void
2491 Editor::split_multichannel_region ()
2492 {
2493         vector<AudioRegion*> v;
2494
2495         if (!clicked_regionview || clicked_regionview->region.n_channels() < 2) {
2496                 return;
2497         }
2498
2499         clicked_regionview->region.separate_by_channel (*session, v);
2500
2501         /* nothing else to do, really */
2502 }
2503
2504 void
2505 Editor::new_region_from_selection ()
2506 {
2507         region_from_selection ();
2508         cancel_selection ();
2509 }
2510
2511 void
2512 Editor::separate_region_from_selection ()
2513 {
2514         bool doing_undo = false;
2515
2516         if (selection->time.empty()) {
2517                 return;
2518         }
2519
2520         Playlist *playlist;
2521                 
2522         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2523
2524                 AudioTimeAxisView* atv;
2525
2526                 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2527
2528                         if (atv->is_audio_track()) {
2529                                         
2530                                 if ((playlist = atv->playlist()) != 0) {
2531                                         if (!doing_undo) {
2532                                                 begin_reversible_command (_("separate"));
2533                                                 doing_undo = true;
2534                                         }
2535                                         if (doing_undo) session->add_undo ((playlist)->get_memento());
2536                         
2537                                         /* XXX need to consider musical time selections here at some point */
2538
2539                                         double speed = atv->get_diskstream()->speed();
2540
2541                                         for (list<AudioRange>::iterator t = selection->time.begin(); t != selection->time.end(); ++t) {
2542                                                 playlist->partition ((jack_nframes_t)((*t).start * speed), (jack_nframes_t)((*t).end * speed), true);
2543                                         }
2544
2545                                         if (doing_undo) session->add_redo_no_execute (playlist->get_memento());
2546                                 }
2547                         }
2548                 }
2549         }
2550
2551         if (doing_undo) commit_reversible_command ();
2552 }
2553
2554 void
2555 Editor::crop_region_to_selection ()
2556 {
2557         if (selection->time.empty()) {
2558                 return;
2559         }
2560
2561         vector<Playlist*> playlists;
2562         Playlist *playlist;
2563
2564         if (clicked_trackview != 0) {
2565
2566                 if ((playlist = clicked_trackview->playlist()) == 0) {
2567                         return;
2568                 }
2569
2570                 playlists.push_back (playlist);
2571
2572         } else {
2573                 
2574                 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2575
2576                         AudioTimeAxisView* atv;
2577
2578                         if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2579
2580                                 if (atv->is_audio_track()) {
2581                                         
2582                                         if ((playlist = atv->playlist()) != 0) {
2583                                                 playlists.push_back (playlist);
2584                                         }
2585                                 }
2586                         }
2587                 }
2588         }
2589
2590         if (!playlists.empty()) {
2591
2592                 jack_nframes_t start;
2593                 jack_nframes_t end;
2594                 jack_nframes_t cnt;
2595
2596                 begin_reversible_command (_("trim to selection"));
2597
2598                 for (vector<Playlist*>::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2599                         
2600                         Region *region;
2601                         
2602                         start = selection->time.start();
2603
2604                         if ((region = (*i)->top_region_at(start)) == 0) {
2605                                 continue;
2606                         }
2607                         
2608                         /* now adjust lengths to that we do the right thing
2609                            if the selection extends beyond the region
2610                         */
2611                         
2612                         start = max (start, region->position());
2613                         end = min (selection->time.end_frame(), start + region->length() - 1);
2614                         cnt = end - start + 1;
2615
2616                         session->add_undo ((*i)->get_memento());
2617                         region->trim_to (start, cnt, this);
2618                         session->add_redo_no_execute ((*i)->get_memento());
2619                 }
2620
2621                 commit_reversible_command ();
2622         }
2623 }               
2624
2625 void
2626 Editor::region_fill_track ()
2627 {
2628         jack_nframes_t end;
2629
2630         if (!session || selection->audio_regions.empty()) {
2631                 return;
2632         }
2633
2634         end = session->current_end_frame ();
2635
2636         begin_reversible_command (_("region fill"));
2637
2638         for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
2639
2640                 AudioRegion& region ((*i)->region);
2641                 Playlist* pl = region.playlist();
2642
2643                 if (end <= region.last_frame()) {
2644                         return;
2645                 }
2646
2647                 double times = (double) (end - region.last_frame()) / (double) region.length();
2648
2649                 if (times == 0) {
2650                         return;
2651                 }
2652
2653                 session->add_undo (pl->get_memento());
2654                 pl->add_region (*(new AudioRegion (region)), region.last_frame(), times);
2655                 session->add_redo_no_execute (pl->get_memento());
2656         }
2657
2658         commit_reversible_command ();
2659 }
2660
2661 void
2662 Editor::region_fill_selection ()
2663 {
2664         if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2665                 return;
2666         }
2667
2668         if (selection->time.empty()) {
2669                 return;
2670         }
2671
2672         Region *region;
2673
2674         Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
2675
2676         if (selected->count_selected_rows() != 1) {
2677                 return;
2678         }
2679
2680         TreeModel::iterator i = region_list_display.get_selection()->get_selected();
2681         region = (*i)[region_list_columns.region];
2682
2683         jack_nframes_t start = selection->time[clicked_selection].start;
2684         jack_nframes_t end = selection->time[clicked_selection].end;
2685
2686         Playlist *playlist; 
2687
2688         if (selection->tracks.empty()) {
2689                 return;
2690         }
2691
2692         jack_nframes_t selection_length = end - start;
2693         float times = (float)selection_length / region->length();
2694         
2695         begin_reversible_command (_("fill selection"));
2696         
2697         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2698
2699                 if ((playlist = (*i)->playlist()) == 0) {
2700                         continue;
2701                 }               
2702                 
2703                 session->add_undo (playlist->get_memento());
2704                 playlist->add_region (*(createRegion (*region)), start, times);
2705                 session->add_redo_no_execute (playlist->get_memento());
2706         }
2707         
2708         commit_reversible_command ();                   
2709 }
2710         
2711 void
2712 Editor::set_region_sync_from_edit_cursor ()
2713 {
2714         if (clicked_regionview == 0) {
2715                 return;
2716         }
2717
2718         if (!clicked_regionview->region.covers (edit_cursor->current_frame)) {
2719                 error << _("Place the edit cursor at the desired sync point") << endmsg;
2720                 return;
2721         }
2722
2723         Region& region (clicked_regionview->region);
2724         begin_reversible_command (_("set sync from edit cursor"));
2725         session->add_undo (region.playlist()->get_memento());
2726         region.set_sync_position (edit_cursor->current_frame);
2727         session->add_redo_no_execute (region.playlist()->get_memento());
2728         commit_reversible_command ();
2729 }
2730
2731 void
2732 Editor::remove_region_sync ()
2733 {
2734         if (clicked_regionview) {
2735                 Region& region (clicked_regionview->region);
2736                 begin_reversible_command (_("remove sync"));
2737                 session->add_undo (region.playlist()->get_memento());
2738                 region.clear_sync_position ();
2739                 session->add_redo_no_execute (region.playlist()->get_memento());
2740                 commit_reversible_command ();
2741         }
2742 }
2743
2744 void
2745 Editor::naturalize ()
2746 {
2747         if (selection->audio_regions.empty()) {
2748                 return;
2749         }
2750         begin_reversible_command (_("naturalize"));
2751         for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
2752                 session->add_undo ((*i)->region.get_memento());
2753                 (*i)->region.move_to_natural_position (this);
2754                 session->add_redo_no_execute ((*i)->region.get_memento());
2755         }
2756         commit_reversible_command ();
2757 }
2758
2759 void
2760 Editor::align (RegionPoint what)
2761 {
2762         align_selection (what, edit_cursor->current_frame);
2763 }
2764
2765 void
2766 Editor::align_relative (RegionPoint what)
2767 {
2768         align_selection_relative (what, edit_cursor->current_frame);
2769 }
2770
2771 struct RegionSortByTime {
2772     bool operator() (const AudioRegionView* a, const AudioRegionView* b) {
2773             return a->region.position() < b->region.position();
2774     }
2775 };
2776
2777 void
2778 Editor::align_selection_relative (RegionPoint point, jack_nframes_t position)
2779 {
2780         if (selection->audio_regions.empty()) {
2781                 return;
2782         }
2783
2784         jack_nframes_t distance;
2785         jack_nframes_t pos = 0;
2786         int dir;
2787
2788         list<AudioRegionView*> sorted;
2789         selection->audio_regions.by_position (sorted);
2790         Region& r ((*sorted.begin())->region);
2791
2792         switch (point) {
2793         case Start:
2794                 pos = r.first_frame ();
2795                 break;
2796
2797         case End:
2798                 pos = r.last_frame();
2799                 break;
2800
2801         case SyncPoint:
2802                 pos = r.adjust_to_sync (r.first_frame());
2803                 break;  
2804         }
2805
2806         if (pos > position) {
2807                 distance = pos - position;
2808                 dir = -1;
2809         } else {
2810                 distance = position - pos;
2811                 dir = 1;
2812         }
2813
2814         begin_reversible_command (_("align selection (relative)"));
2815
2816         for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
2817
2818                 Region& region ((*i)->region);
2819
2820                 session->add_undo (region.playlist()->get_memento());
2821                 
2822                 if (dir > 0) {
2823                         region.set_position (region.position() + distance, this);
2824                 } else {
2825                         region.set_position (region.position() - distance, this);
2826                 }
2827
2828                 session->add_redo_no_execute (region.playlist()->get_memento());
2829
2830         }
2831
2832         commit_reversible_command ();
2833 }
2834
2835 void
2836 Editor::align_selection (RegionPoint point, jack_nframes_t position)
2837 {
2838         if (selection->audio_regions.empty()) {
2839                 return;
2840         }
2841
2842         begin_reversible_command (_("align selection"));
2843
2844         for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
2845                 align_region_internal ((*i)->region, point, position);
2846         }
2847
2848         commit_reversible_command ();
2849 }
2850
2851 void
2852 Editor::align_region (Region& region, RegionPoint point, jack_nframes_t position)
2853 {
2854         begin_reversible_command (_("align region"));
2855         align_region_internal (region, point, position);
2856         commit_reversible_command ();
2857 }
2858
2859 void
2860 Editor::align_region_internal (Region& region, RegionPoint point, jack_nframes_t position)
2861 {
2862         session->add_undo (region.playlist()->get_memento());
2863
2864         switch (point) {
2865         case SyncPoint:
2866                 region.set_position (region.adjust_to_sync (position), this);
2867                 break;
2868
2869         case End:
2870                 if (position > region.length()) {
2871                         region.set_position (position - region.length(), this);
2872                 }
2873                 break;
2874
2875         case Start:
2876                 region.set_position (position, this);
2877                 break;
2878         }
2879
2880         session->add_redo_no_execute (region.playlist()->get_memento());
2881 }       
2882
2883 void
2884 Editor::trim_region_to_edit_cursor ()
2885 {
2886         if (clicked_regionview == 0) {
2887                 return;
2888         }
2889
2890         Region& region (clicked_regionview->region);
2891
2892         float speed = 1.0f;
2893         AudioTimeAxisView *atav;
2894
2895         if ( clicked_trackview != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(clicked_trackview)) != 0 ) {
2896                 if (atav->get_diskstream() != 0) {
2897                         speed = atav->get_diskstream()->speed();
2898                 }
2899         }
2900
2901         begin_reversible_command (_("trim to edit"));
2902         session->add_undo (region.playlist()->get_memento());
2903         region.trim_end( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
2904         session->add_redo_no_execute (region.playlist()->get_memento());
2905         commit_reversible_command ();
2906 }
2907
2908 void
2909 Editor::trim_region_from_edit_cursor ()
2910 {
2911         if (clicked_regionview == 0) {
2912                 return;
2913         }
2914
2915         Region& region (clicked_regionview->region);
2916
2917         float speed = 1.0f;
2918         AudioTimeAxisView *atav;
2919
2920         if ( clicked_trackview != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(clicked_trackview)) != 0 ) {
2921                 if (atav->get_diskstream() != 0) {
2922                         speed = atav->get_diskstream()->speed();
2923                 }
2924         }
2925
2926         begin_reversible_command (_("trim to edit"));
2927         session->add_undo (region.playlist()->get_memento());
2928         region.trim_end( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
2929         session->add_redo_no_execute (region.playlist()->get_memento());
2930         commit_reversible_command ();
2931 }
2932
2933 void
2934 Editor::unfreeze_route ()
2935 {
2936         if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2937                 return;
2938         }
2939         
2940         clicked_audio_trackview->audio_track()->unfreeze ();
2941 }
2942
2943 void*
2944 Editor::_freeze_thread (void* arg)
2945 {
2946         PBD::ThreadCreated (pthread_self(), X_("Freeze"));
2947         return static_cast<Editor*>(arg)->freeze_thread ();
2948 }
2949
2950 void*
2951 Editor::freeze_thread ()
2952 {
2953         clicked_audio_trackview->audio_track()->freeze (*current_interthread_info);
2954         return 0;
2955 }
2956
2957 gint
2958 Editor::freeze_progress_timeout (void *arg)
2959 {
2960         interthread_progress_bar.set_fraction (current_interthread_info->progress/100);
2961         return !(current_interthread_info->done || current_interthread_info->cancel);
2962 }
2963
2964 void
2965 Editor::freeze_route ()
2966 {
2967         if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2968                 return;
2969         }
2970         
2971         InterThreadInfo itt;
2972
2973         if (interthread_progress_window == 0) {
2974                 build_interthread_progress_window ();
2975         }
2976         
2977         interthread_progress_window->set_title (_("ardour: freeze"));
2978         interthread_progress_window->set_position (Gtk::WIN_POS_MOUSE);
2979         interthread_progress_window->show_all ();
2980         interthread_progress_bar.set_fraction (0.0f);
2981         interthread_progress_label.set_text ("");
2982         interthread_cancel_label.set_text (_("Cancel Freeze"));
2983         current_interthread_info = &itt;
2984
2985         interthread_progress_connection = 
2986           Glib::signal_timeout().connect (bind (mem_fun(*this, &Editor::freeze_progress_timeout), (gpointer) 0), 100);
2987
2988         itt.done = false;
2989         itt.cancel = false;
2990         itt.progress = 0.0f;
2991
2992         pthread_create (&itt.thread, 0, _freeze_thread, this);
2993
2994         track_canvas.get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
2995
2996         while (!itt.done && !itt.cancel) {
2997                 gtk_main_iteration ();
2998         }
2999
3000         interthread_progress_connection.disconnect ();
3001         interthread_progress_window->hide_all ();
3002         current_interthread_info = 0;
3003         track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3004 }
3005
3006 void
3007 Editor::bounce_range_selection ()
3008 {
3009         if (selection->time.empty()) {
3010                 return;
3011         }
3012
3013         TrackViewList *views = get_valid_views (selection->time.track, selection->time.group);
3014
3015         jack_nframes_t start = selection->time[clicked_selection].start;
3016         jack_nframes_t end = selection->time[clicked_selection].end;
3017         jack_nframes_t cnt = end - start + 1;
3018         
3019         begin_reversible_command (_("bounce range"));
3020
3021         for (TrackViewList::iterator i = views->begin(); i != views->end(); ++i) {
3022
3023                 AudioTimeAxisView* atv;
3024
3025                 if ((atv = dynamic_cast<AudioTimeAxisView*> (*i)) == 0) {
3026                         continue;
3027                 }
3028                 
3029                 Playlist* playlist;
3030                 
3031                 if ((playlist = atv->playlist()) == 0) {
3032                         return;
3033                 }
3034
3035                 InterThreadInfo itt;
3036                 
3037                 itt.done = false;
3038                 itt.cancel = false;
3039                 itt.progress = false;
3040                 
3041                 session->add_undo (playlist->get_memento());
3042                 atv->audio_track()->bounce_range (start, cnt, itt);
3043                 session->add_redo_no_execute (playlist->get_memento());
3044         }
3045         
3046         commit_reversible_command ();
3047         
3048         delete views;
3049 }
3050
3051 void
3052 Editor::cut ()
3053 {
3054         cut_copy (Cut);
3055 }
3056
3057 void
3058 Editor::copy ()
3059 {
3060         cut_copy (Copy);
3061 }
3062
3063 void 
3064 Editor::cut_copy (CutCopyOp op)
3065 {
3066         /* only cancel selection if cut/copy is successful.*/
3067
3068         string opname;
3069
3070         switch (op) {
3071         case Cut:
3072                 opname = _("cut");
3073                 break;
3074         case Copy:
3075                 opname = _("copy");
3076                 break;
3077         case Clear:
3078                 opname = _("clear");
3079                 break;
3080         }
3081         
3082         cut_buffer->clear ();
3083
3084         switch (current_mouse_mode()) {
3085         case MouseObject: 
3086                 if (!selection->audio_regions.empty() || !selection->points.empty()) {
3087
3088                         begin_reversible_command (opname + _(" objects"));
3089
3090                         if (!selection->audio_regions.empty()) {
3091                                 
3092                                 cut_copy_regions (op);
3093                                 
3094                                 if (op == Cut) {
3095                                         selection->clear_audio_regions ();
3096                                 }
3097                         }
3098
3099                         if (!selection->points.empty()) {
3100                                 cut_copy_points (op);
3101
3102                                 if (op == Cut) {
3103                                         selection->clear_points ();
3104                                 }
3105                         }
3106
3107                         commit_reversible_command ();   
3108                 }
3109                 break;
3110                 
3111         case MouseRange:
3112                 if (!selection->time.empty()) {
3113
3114                         begin_reversible_command (opname + _(" range"));
3115                         cut_copy_ranges (op);
3116                         commit_reversible_command ();
3117
3118                         if (op == Cut) {
3119                                 selection->clear_time ();
3120                         }
3121                         
3122                 }
3123                 break;
3124                 
3125         default:
3126                 break;
3127         }
3128 }
3129
3130 void
3131 Editor::cut_copy_points (CutCopyOp op)
3132 {
3133         for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3134
3135                 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
3136
3137                 if (atv) {
3138                         atv->cut_copy_clear_objects (selection->points, op);
3139                 } 
3140         }
3141 }
3142
3143 void
3144 Editor::cut_copy_regions (CutCopyOp op)
3145 {
3146         typedef std::map<AudioPlaylist*,AudioPlaylist*> PlaylistMapping;
3147         PlaylistMapping pmap;
3148         jack_nframes_t first_position = max_frames;
3149         set<Playlist*> freezelist;
3150         pair<set<Playlist*>::iterator,bool> insert_result;
3151
3152         for (AudioRegionSelection::iterator x = selection->audio_regions.begin(); x != selection->audio_regions.end(); ++x) {
3153                 first_position = min ((*x)->region.position(), first_position);
3154
3155                 if (op == Cut || op == Clear) {
3156                         AudioPlaylist *pl = dynamic_cast<AudioPlaylist*>((*x)->region.playlist());
3157                         if (pl) {
3158                                 insert_result = freezelist.insert (pl);
3159                                 if (insert_result.second) {
3160                                         pl->freeze ();
3161                                         session->add_undo (pl->get_memento());
3162                                 }
3163                         }
3164                 }
3165         }
3166
3167         for (AudioRegionSelection::iterator x = selection->audio_regions.begin(); x != selection->audio_regions.end(); ) {
3168
3169                 AudioPlaylist *pl = dynamic_cast<AudioPlaylist*>((*x)->region.playlist());
3170                 AudioPlaylist* npl;
3171                 AudioRegionSelection::iterator tmp;
3172                 
3173                 tmp = x;
3174                 ++tmp;
3175
3176                 if (pl) {
3177
3178                         PlaylistMapping::iterator pi = pmap.find (pl);
3179                         
3180                         if (pi == pmap.end()) {
3181                                 npl = new AudioPlaylist (*session, "cutlist", true);
3182                                 npl->freeze();
3183                                 pmap[pl] = npl;
3184                         } else {
3185                                 npl = pi->second;
3186                         }
3187
3188                         switch (op) {
3189                         case Cut:
3190                                 npl->add_region (*(new AudioRegion ((*x)->region)), (*x)->region.position() - first_position);
3191                                 pl->remove_region (&((*x)->region));
3192                                 break;
3193
3194                         case Copy:
3195                                 npl->add_region (*(new AudioRegion ((*x)->region)), (*x)->region.position() - first_position);
3196                                 break;
3197
3198                         case Clear:
3199                                 pl->remove_region (&((*x)->region));
3200                                 break;
3201                         }
3202                 }
3203
3204                 x = tmp;
3205         }
3206
3207         list<Playlist*> foo;
3208
3209         for (PlaylistMapping::iterator i = pmap.begin(); i != pmap.end(); ++i) {
3210                 foo.push_back (i->second);
3211         }
3212
3213         if (!foo.empty()) {
3214                 cut_buffer->set (foo);
3215         }
3216         
3217         for (set<Playlist*>::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
3218                 (*pl)->thaw ();
3219                 session->add_redo_no_execute ((*pl)->get_memento());
3220         }
3221 }
3222
3223 void
3224 Editor::cut_copy_ranges (CutCopyOp op)
3225 {
3226         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3227                 (*i)->cut_copy_clear (*selection, op);
3228         }
3229 }
3230
3231 void
3232 Editor::paste (float times)
3233 {
3234         paste_internal (edit_cursor->current_frame, times);
3235 }
3236
3237 void
3238 Editor::mouse_paste ()
3239 {
3240         int x, y;
3241         double wx, wy;
3242
3243         track_canvas.get_pointer (x, y);
3244         track_canvas.window_to_world (x, y, wx, wy);
3245         wx += horizontal_adjustment.get_value();
3246         wy += vertical_adjustment.get_value();
3247
3248         GdkEvent event;
3249         event.type = GDK_BUTTON_RELEASE;
3250         event.button.x = wx;
3251         event.button.y = wy;
3252         
3253         jack_nframes_t where = event_frame (&event, 0, 0);
3254         snap_to (where);
3255         paste_internal (where, 1);
3256 }
3257
3258 void
3259 Editor::paste_internal (jack_nframes_t position, float times)
3260 {
3261         bool commit = false;
3262
3263         if (cut_buffer->empty() || selection->tracks.empty()) {
3264                 return;
3265         }
3266
3267         if (position == max_frames) {
3268                 position = edit_cursor->current_frame;
3269         }
3270
3271         begin_reversible_command (_("paste"));
3272
3273         TrackSelection::iterator i;
3274         size_t nth;
3275
3276         for (nth = 0, i = selection->tracks.begin(); i != selection->tracks.end(); ++i, ++nth) {
3277                 
3278                 /* undo/redo is handled by individual tracks */
3279
3280                 if ((*i)->paste (position, times, *cut_buffer, nth)) {
3281                         commit = true;
3282                 }
3283         }
3284
3285         if (commit) {
3286                 commit_reversible_command ();
3287         }
3288 }
3289
3290 void
3291 Editor::paste_named_selection (float times)
3292 {
3293         TrackSelection::iterator t;
3294
3295         Glib::RefPtr<TreeSelection> selected = named_selection_display.get_selection();
3296
3297         if (selected->count_selected_rows() != 1 || selection->tracks.empty()) {
3298                 return;
3299         }
3300
3301         TreeModel::iterator i = selected->get_selected();
3302         NamedSelection* ns = (*i)[named_selection_columns.selection];
3303
3304         list<Playlist*>::iterator chunk;
3305         list<Playlist*>::iterator tmp;
3306
3307         chunk = ns->playlists.begin();
3308                 
3309         begin_reversible_command (_("paste chunk"));
3310
3311         for (t = selection->tracks.begin(); t != selection->tracks.end(); ++t) {
3312                 
3313                 AudioTimeAxisView* atv;
3314                 Playlist* pl;
3315                 AudioPlaylist* apl;
3316
3317                 if ((atv = dynamic_cast<AudioTimeAxisView*> (*t)) == 0) {
3318                         continue;
3319                 }
3320
3321                 if ((pl = atv->playlist()) == 0) {
3322                         continue;
3323                 }
3324
3325                 if ((apl = dynamic_cast<AudioPlaylist*> (pl)) == 0) {
3326                         continue;
3327                 }
3328
3329                 tmp = chunk;
3330                 ++tmp;
3331
3332                 session->add_undo (apl->get_memento());
3333                 apl->paste (**chunk, edit_cursor->current_frame, times);
3334                 session->add_redo_no_execute (apl->get_memento());
3335
3336                 if (tmp != ns->playlists.end()) {
3337                         chunk = tmp;
3338                 }
3339         }
3340
3341         commit_reversible_command();
3342 }
3343
3344 void
3345 Editor::duplicate_some_regions (AudioRegionSelection& regions, float times)
3346 {
3347         Playlist *playlist; 
3348         AudioRegionSelection sel = regions; // clear (below) will clear the argument list
3349                 
3350         begin_reversible_command (_("duplicate region"));
3351
3352         selection->clear_audio_regions ();
3353
3354         for (AudioRegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
3355
3356                 Region& r ((*i)->region);
3357
3358                 TimeAxisView& tv = (*i)->get_time_axis_view();
3359                 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&tv);
3360                 sigc::connection c = atv->view->AudioRegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3361                 
3362                 playlist = (*i)->region.playlist();
3363                 session->add_undo (playlist->get_memento());
3364                 playlist->duplicate (r, r.last_frame(), times);
3365                 session->add_redo_no_execute (playlist->get_memento());
3366
3367                 c.disconnect ();
3368
3369                 if (latest_regionview) {
3370                         selection->add (latest_regionview);
3371                 }
3372         }
3373                 
3374
3375         commit_reversible_command ();
3376 }
3377
3378 void
3379 Editor::duplicate_selection (float times)
3380 {
3381         if (selection->time.empty() || selection->tracks.empty()) {
3382                 return;
3383         }
3384
3385         Playlist *playlist; 
3386         vector<AudioRegion*> new_regions;
3387         vector<AudioRegion*>::iterator ri;
3388                 
3389         create_region_from_selection (new_regions);
3390
3391         if (new_regions.empty()) {
3392                 return;
3393         }
3394         
3395         begin_reversible_command (_("duplicate selection"));
3396
3397         ri = new_regions.begin();
3398
3399         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3400                 if ((playlist = (*i)->playlist()) == 0) {
3401                         continue;
3402                 }
3403                 session->add_undo (playlist->get_memento());
3404                 playlist->duplicate (**ri, selection->time[clicked_selection].end, times);
3405                 session->add_redo_no_execute (playlist->get_memento());
3406
3407                 ++ri;
3408                 if (ri == new_regions.end()) {
3409                         --ri;
3410                 }
3411         }
3412
3413         commit_reversible_command ();
3414 }
3415
3416 void
3417 Editor::center_playhead ()
3418 {
3419         float page = canvas_width * frames_per_unit;
3420
3421         center_screen_internal (playhead_cursor->current_frame, page);
3422 }
3423
3424 void
3425 Editor::center_edit_cursor ()
3426 {
3427         float page = canvas_width * frames_per_unit;
3428
3429         center_screen_internal (edit_cursor->current_frame, page);
3430 }
3431
3432 void
3433 Editor::clear_playlist (Playlist& playlist)
3434 {
3435         begin_reversible_command (_("clear playlist"));
3436         session->add_undo (playlist.get_memento());
3437         playlist.clear ();
3438         session->add_redo_no_execute (playlist.get_memento());
3439         commit_reversible_command ();
3440 }
3441
3442 void
3443 Editor::nudge_track (bool use_edit_cursor, bool forwards)
3444 {
3445         Playlist *playlist; 
3446         jack_nframes_t distance;
3447         jack_nframes_t next_distance;
3448         jack_nframes_t start;
3449
3450         if (use_edit_cursor) {
3451                 start = edit_cursor->current_frame;
3452         } else {
3453                 start = 0;
3454         }
3455
3456         if ((distance = get_nudge_distance (start, next_distance)) == 0) {
3457                 return;
3458         }
3459         
3460         if (selection->tracks.empty()) {
3461                 return;
3462         }
3463         
3464         begin_reversible_command (_("nudge track"));
3465         
3466         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3467
3468                 if ((playlist = (*i)->playlist()) == 0) {
3469                         continue;
3470                 }               
3471                 
3472                 session->add_undo (playlist->get_memento());
3473                 playlist->nudge_after (start, distance, forwards);
3474                 session->add_redo_no_execute (playlist->get_memento());
3475         }
3476         
3477         commit_reversible_command ();                   
3478 }
3479
3480 void
3481 Editor::toggle_xfades_active ()
3482 {
3483         if (session) {
3484                 session->set_crossfades_active (!session->get_crossfades_active());
3485         }
3486 }
3487
3488 void
3489 Editor::set_xfade_visibility (bool yn)
3490 {
3491         
3492 }
3493
3494 void
3495 Editor::toggle_xfade_visibility ()
3496 {
3497         set_xfade_visibility (!xfade_visibility());
3498 }
3499
3500 void
3501 Editor::remove_last_capture ()
3502 {
3503         vector<string> choices;
3504         string prompt;
3505         
3506         if (!session) {
3507                 return;
3508         }
3509
3510         if (Config->get_verify_remove_last_capture()) {
3511                 prompt  = _("Do you really want to destroy the last capture?"
3512                             "\n(This is destructive and cannot be undone)");
3513
3514                 choices.push_back (_("Yes, destroy it."));
3515                 choices.push_back (_("No, do nothing."));
3516                 
3517                 Gtkmm2ext::Choice prompter (prompt, choices);
3518                 prompter.chosen.connect (ptr_fun (Main::quit));
3519                 prompter.show_all ();
3520
3521                 Main::run ();
3522                 
3523                 if (prompter.get_choice() == 0) {
3524                         session->remove_last_capture ();
3525                 }
3526
3527         } else {
3528                 session->remove_last_capture();
3529         }
3530 }
3531
3532 void
3533 Editor::normalize_region ()
3534 {
3535         if (!session) {
3536                 return;
3537         }
3538
3539         if (selection->audio_regions.empty()) {
3540                 return;
3541         }
3542
3543         begin_reversible_command (_("normalize"));
3544
3545         track_canvas.get_window()->set_cursor (*wait_cursor);
3546         gdk_flush ();
3547
3548         for (AudioRegionSelection::iterator r = selection->audio_regions.begin(); r != selection->audio_regions.end(); ++r) {
3549                 session->add_undo ((*r)->region.get_memento());
3550                 (*r)->region.normalize_to (0.0f);
3551                 session->add_redo_no_execute ((*r)->region.get_memento());
3552         }
3553
3554         commit_reversible_command ();
3555         track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3556 }
3557
3558
3559 void
3560 Editor::denormalize_region ()
3561 {
3562         if (!session) {
3563                 return;
3564         }
3565
3566         if (selection->audio_regions.empty()) {
3567                 return;
3568         }
3569
3570         begin_reversible_command ("denormalize");
3571
3572         for (AudioRegionSelection::iterator r = selection->audio_regions.begin(); r != selection->audio_regions.end(); ++r) {
3573                 session->add_undo ((*r)->region.get_memento());
3574                 (*r)->region.set_scale_amplitude (1.0f);
3575                 session->add_redo_no_execute ((*r)->region.get_memento());
3576         }
3577
3578         commit_reversible_command ();
3579 }
3580
3581
3582 void
3583 Editor::reverse_region ()
3584 {
3585         if (!session) {
3586                 return;
3587         }
3588
3589         Reverse rev (*session);
3590         apply_filter (rev, _("reverse regions"));
3591 }
3592
3593 void
3594 Editor::apply_filter (AudioFilter& filter, string command)
3595 {
3596         if (selection->audio_regions.empty()) {
3597                 return;
3598         }
3599
3600         begin_reversible_command (command);
3601
3602         track_canvas.get_window()->set_cursor (*wait_cursor);
3603         gdk_flush ();
3604
3605         for (AudioRegionSelection::iterator r = selection->audio_regions.begin(); r != selection->audio_regions.end(); ) {
3606
3607                 AudioRegion& region ((*r)->region);
3608                 Playlist* playlist = region.playlist();
3609
3610                 AudioRegionSelection::iterator tmp;
3611                 
3612                 tmp = r;
3613                 ++tmp;
3614
3615                 if (region.apply (filter) == 0) {
3616
3617                         session->add_undo (playlist->get_memento());
3618                         playlist->replace_region (region, *(filter.results.front()), region.position());
3619                         session->add_redo_no_execute (playlist->get_memento());
3620                 } else {
3621                         goto out;
3622                 }
3623
3624                 r = tmp;
3625         }
3626
3627         commit_reversible_command ();
3628         selection->audio_regions.clear ();
3629
3630   out:
3631         track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3632 }
3633
3634 void
3635 Editor::region_selection_op (void (Region::*pmf)(void))
3636 {
3637         for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
3638                 ((*i)->region.*pmf)();
3639         }
3640 }
3641
3642
3643 void
3644 Editor::region_selection_op (void (Region::*pmf)(void*), void *arg)
3645 {
3646         for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
3647                 ((*i)->region.*pmf)(arg);
3648         }
3649 }
3650
3651 void
3652 Editor::region_selection_op (void (Region::*pmf)(bool), bool yn)
3653 {
3654         for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
3655                 ((*i)->region.*pmf)(yn);
3656         }
3657 }
3658
3659 void
3660 Editor::external_edit_region ()
3661 {
3662         if (!clicked_regionview) {
3663                 return;
3664         }
3665
3666         /* more to come */
3667 }
3668
3669 void
3670 Editor::brush (jack_nframes_t pos)
3671 {
3672         AudioRegionSelection sel;
3673         snap_to (pos);
3674
3675         if (selection->audio_regions.empty()) {
3676                 /* XXX get selection from region list */
3677         } else { 
3678                 sel = selection->audio_regions;
3679         }
3680
3681         if (sel.empty()) {
3682                 return;
3683         }
3684
3685         for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
3686                 mouse_brush_insert_region ((*i), pos);
3687         }
3688 }
3689
3690 void
3691 Editor::toggle_gain_envelope_visibility ()
3692 {
3693         for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
3694                 (*i)->set_envelope_visible (!(*i)->envelope_visible());
3695         }
3696 }
3697
3698 void
3699 Editor::toggle_gain_envelope_active ()
3700 {
3701         for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
3702                 AudioRegion* ar = dynamic_cast<AudioRegion*>(&(*i)->region);
3703                 if (ar) {
3704                         ar->set_envelope_active (true);
3705                 }
3706         }
3707 }