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