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