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