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