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