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