2 Copyright (C) 2000-2004 Paul Davis
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.
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.
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.
28 #include <pbd/error.h>
29 #include <pbd/basename.h>
30 #include <pbd/pthread_utils.h>
31 #include <pbd/memento_command.h>
33 #include <gtkmm2ext/utils.h>
34 #include <gtkmm2ext/choice.h>
36 #include <ardour/audioengine.h>
37 #include <ardour/session.h>
38 #include <ardour/audioplaylist.h>
39 #include <ardour/audioregion.h>
40 #include <ardour/audio_diskstream.h>
41 #include <ardour/utils.h>
42 #include <ardour/location.h>
43 #include <ardour/named_selection.h>
44 #include <ardour/audio_track.h>
45 #include <ardour/audioplaylist.h>
46 #include <ardour/region_factory.h>
47 #include <ardour/reverse.h>
49 #include "ardour_ui.h"
51 #include "time_axis_view.h"
52 #include "audio_time_axis.h"
53 #include "automation_time_axis.h"
54 #include "streamview.h"
55 #include "audio_region_view.h"
56 #include "rgb_macros.h"
57 #include "selection_templates.h"
58 #include "selection.h"
61 #include "gtk-custom-hruler.h"
62 #include "gui_thread.h"
67 using namespace ARDOUR;
71 using namespace Editing;
73 /***********************************************************************
75 ***********************************************************************/
78 Editor::undo (uint32_t n)
86 Editor::redo (uint32_t n)
94 Editor::set_meter_hold (int32_t cnt)
96 Config->set_meter_hold_off(false);
97 Config->set_meter_hold_short(false);
98 Config->set_meter_hold_medium(false);
99 Config->set_meter_hold_long(false);
104 Config->set_meter_hold_off(true);
107 Config->set_meter_hold_short(true);
110 Config->set_meter_hold_medium(true);
113 Config->set_meter_hold_long(true);
118 session->set_meter_hold (cnt);
123 Editor::set_meter_falloff (int intval)
125 float val = 0.0f; /* off */
128 Config->set_meter_falloff_off(false);
129 Config->set_meter_falloff_slowest(false);
130 Config->set_meter_falloff_slow(false);
131 Config->set_meter_falloff_medium(false);
132 Config->set_meter_falloff_fast(false);
133 Config->set_meter_falloff_faster(false);
134 Config->set_meter_falloff_fastest(false);
140 Config->set_meter_falloff_off(true);
144 Config->set_meter_falloff_slowest(true);
148 Config->set_meter_falloff_slow(true);
152 Config->set_meter_falloff_medium(true);
156 Config->set_meter_falloff_fast(true);
160 Config->set_meter_falloff_faster(true);
164 Config->set_meter_falloff_fastest(true);
169 session->set_meter_falloff (val);
175 Editor::ensure_cursor (jack_nframes_t *pos)
177 *pos = edit_cursor->current_frame;
182 Editor::split_region ()
184 split_region_at (edit_cursor->current_frame);
188 Editor::split_region_at (jack_nframes_t where)
190 split_regions_at (where, selection->regions);
194 Editor::split_regions_at (jack_nframes_t where, RegionSelection& regions)
196 begin_reversible_command (_("split"));
199 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
201 RegionSelection::iterator tmp;
206 Playlist* pl = (*a)->region().playlist();
208 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*a);
210 _new_regionviews_show_envelope = arv->envelope_visible();
213 XMLNode &before = pl->get_state();
214 pl->split_region ((*a)->region(), where);
215 XMLNode &after = pl->get_state();
216 session->add_command(new MementoCommand<Playlist>(*pl, before, after));
222 commit_reversible_command ();
223 _new_regionviews_show_envelope = false;
227 Editor::remove_clicked_region ()
229 if (clicked_audio_trackview == 0 || clicked_regionview == 0) {
233 Playlist* playlist = clicked_audio_trackview->playlist();
235 begin_reversible_command (_("remove region"));
236 XMLNode &before = playlist->get_state();
237 playlist->remove_region (&clicked_regionview->region());
238 XMLNode &after = playlist->get_state();
239 session->add_command(new MementoCommand<Playlist>(*playlist, before, after));
240 commit_reversible_command ();
244 Editor::destroy_clicked_region ()
246 int32_t selected = selection->regions.size();
248 if (!session || clicked_regionview == 0 && selected == 0) {
252 vector<string> choices;
255 prompt = string_compose (_(" This is destructive, will possibly delete audio files\n\
256 It cannot be undone\n\
257 Do you really want to destroy %1 ?"),
259 _("these regions") : _("this region")));
261 choices.push_back (_("No, do nothing."));
264 choices.push_back (_("Yes, destroy them."));
266 choices.push_back (_("Yes, destroy it."));
269 Gtkmm2ext::Choice prompter (prompt, choices);
271 if (prompter.run() == 0) { /* first choice */
278 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
279 r.push_back (&(*i)->region());
282 session->destroy_regions (r);
284 } else if (clicked_regionview) {
285 session->destroy_region (&clicked_regionview->region());
290 Editor::select_region_for_operation (int dir, TimeAxisView **tv)
294 jack_nframes_t start = 0;
296 if (selection->time.start () == selection->time.end_frame ()) {
298 /* no current selection-> is there a selected regionview? */
300 if (selection->regions.empty()) {
308 if (!selection->regions.empty()) {
310 rv = *(selection->regions.begin());
311 (*tv) = &rv->get_time_axis_view();
312 region = &rv->region();
314 } else if (!selection->tracks.empty()) {
316 (*tv) = selection->tracks.front();
318 RouteTimeAxisView* rtv;
320 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*tv)) != 0) {
323 if ((pl = rtv->playlist()) == 0) {
327 region = pl->top_region_at (start);
335 Editor::extend_selection_to_end_of_region (bool next)
339 jack_nframes_t start;
341 if ((region = select_region_for_operation (next ? 1 : 0, &tv)) == 0) {
345 if (region && selection->time.start () == selection->time.end_frame ()) {
346 start = region->position();
348 start = selection->time.start ();
351 /* Try to leave the selection with the same route if possible */
353 if ((tv = selection->time.track) == 0) {
357 begin_reversible_command (_("extend selection"));
358 selection->set (tv, start, region->position() + region->length());
359 commit_reversible_command ();
363 Editor::extend_selection_to_start_of_region (bool previous)
369 if ((region = select_region_for_operation (previous ? -1 : 0, &tv)) == 0) {
373 if (region && selection->time.start () == selection->time.end_frame ()) {
374 end = region->position() + region->length();
376 end = selection->time.end_frame ();
379 /* Try to leave the selection with the same route if possible */
381 if ((tv = selection->time.track) == 0) {
385 begin_reversible_command (_("extend selection"));
386 selection->set (tv, region->position(), end);
387 commit_reversible_command ();
392 Editor::nudge_forward (bool next)
394 jack_nframes_t distance;
395 jack_nframes_t next_distance;
397 if (!session) return;
399 if (!selection->regions.empty()) {
401 begin_reversible_command (_("nudge forward"));
403 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
404 Region& r ((*i)->region());
406 distance = get_nudge_distance (r.position(), next_distance);
409 distance = next_distance;
412 XMLNode &before = r.playlist()->get_state();
413 r.set_position (r.position() + distance, this);
414 XMLNode &after = r.playlist()->get_state();
415 session->add_command (new MementoCommand<Playlist>(*(r.playlist()), before, after));
418 commit_reversible_command ();
421 distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
422 session->request_locate (playhead_cursor->current_frame + distance);
427 Editor::nudge_backward (bool next)
429 jack_nframes_t distance;
430 jack_nframes_t next_distance;
432 if (!session) return;
434 if (!selection->regions.empty()) {
436 begin_reversible_command (_("nudge forward"));
438 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
439 Region& r ((*i)->region());
441 distance = get_nudge_distance (r.position(), next_distance);
444 distance = next_distance;
447 XMLNode &before = r.playlist()->get_state();
449 if (r.position() > distance) {
450 r.set_position (r.position() - distance, this);
452 r.set_position (0, this);
454 XMLNode &after = r.playlist()->get_state();
455 session->add_command(new MementoCommand<Playlist>(*(r.playlist()), before, after));
458 commit_reversible_command ();
462 distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
464 if (playhead_cursor->current_frame > distance) {
465 session->request_locate (playhead_cursor->current_frame - distance);
467 session->goto_start();
473 Editor::nudge_forward_capture_offset ()
475 jack_nframes_t distance;
477 if (!session) return;
479 if (!selection->regions.empty()) {
481 begin_reversible_command (_("nudge forward"));
483 distance = session->worst_output_latency();
485 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
486 Region& r ((*i)->region());
488 XMLNode &before = r.playlist()->get_state();
489 r.set_position (r.position() + distance, this);
490 XMLNode &after = r.playlist()->get_state();
491 session->add_command(new MementoCommand<Playlist>(*(r.playlist()), before, after));
494 commit_reversible_command ();
500 Editor::nudge_backward_capture_offset ()
502 jack_nframes_t distance;
504 if (!session) return;
506 if (!selection->regions.empty()) {
508 begin_reversible_command (_("nudge forward"));
510 distance = session->worst_output_latency();
512 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
513 Region& r ((*i)->region());
515 XMLNode &before = r.playlist()->get_state();
517 if (r.position() > distance) {
518 r.set_position (r.position() - distance, this);
520 r.set_position (0, this);
522 XMLNode &after = r.playlist()->get_state();
523 session->add_command(new MementoCommand<Playlist>(*(r.playlist()), before, after));
526 commit_reversible_command ();
533 Editor::move_to_start ()
535 session->goto_start ();
539 Editor::move_to_end ()
542 session->request_locate (session->current_end_frame());
546 Editor::build_region_boundary_cache ()
548 jack_nframes_t pos = 0;
551 TrackViewList tracks;
553 region_boundary_cache.clear ();
560 case SnapToRegionStart:
563 case SnapToRegionEnd:
566 case SnapToRegionSync:
569 case SnapToRegionBoundary:
573 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), snap_type) << endmsg;
578 TimeAxisView *ontrack = 0;
580 while (pos < session->current_end_frame()) {
582 if (!selection->tracks.empty()) {
584 if ((r = find_next_region (pos, point, 1, selection->tracks, &ontrack)) == 0) {
588 } else if (clicked_trackview) {
591 t.push_back (clicked_trackview);
593 if ((r = find_next_region (pos, point, 1, t, &ontrack)) == 0) {
599 if ((r = find_next_region (pos, point, 1, track_views, &ontrack)) == 0) {
607 case SnapToRegionStart:
608 rpos = r->first_frame();
610 case SnapToRegionEnd:
611 rpos = r->last_frame();
613 case SnapToRegionSync:
614 rpos = r->adjust_to_sync (r->first_frame());
617 case SnapToRegionBoundary:
618 rpos = r->last_frame();
625 AudioTimeAxisView *atav;
627 if ( ontrack != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(ontrack)) != 0 ) {
628 if (atav->get_diskstream() != 0) {
629 speed = atav->get_diskstream()->speed();
633 rpos = track_frame_to_session_frame(rpos, speed);
635 if (region_boundary_cache.empty() || rpos != region_boundary_cache.back()) {
636 if (snap_type == SnapToRegionBoundary) {
637 region_boundary_cache.push_back (r->first_frame());
639 region_boundary_cache.push_back (rpos);
647 Editor::find_next_region (jack_nframes_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
649 TrackViewList::iterator i;
650 jack_nframes_t closest = max_frames;
652 jack_nframes_t rpos = 0;
655 jack_nframes_t track_frame;
656 AudioTimeAxisView *atav;
658 for (i = tracks.begin(); i != tracks.end(); ++i) {
660 jack_nframes_t distance;
664 if ( (atav = dynamic_cast<AudioTimeAxisView*>(*i)) != 0 ) {
665 if (atav->get_diskstream()!=0)
666 track_speed = atav->get_diskstream()->speed();
669 track_frame = session_frame_to_track_frame(frame, track_speed);
671 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
677 rpos = r->first_frame ();
681 rpos = r->last_frame ();
685 rpos = r->adjust_to_sync (r->first_frame());
688 // rpos is a "track frame", converting it to "session frame"
689 rpos = track_frame_to_session_frame(rpos, track_speed);
692 distance = rpos - frame;
694 distance = frame - rpos;
697 if (distance < closest) {
709 Editor::cursor_to_region_point (Cursor* cursor, RegionPoint point, int32_t dir)
712 jack_nframes_t pos = cursor->current_frame;
718 TimeAxisView *ontrack = 0;
720 // so we don't find the current region again..
724 if (!selection->tracks.empty()) {
726 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
728 } else if (clicked_trackview) {
731 t.push_back (clicked_trackview);
733 r = find_next_region (pos, point, dir, t, &ontrack);
737 r = find_next_region (pos, point, dir, track_views, &ontrack);
746 pos = r->first_frame ();
750 pos = r->last_frame ();
754 pos = r->adjust_to_sync (r->first_frame());
759 AudioTimeAxisView *atav;
761 if ( ontrack != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(ontrack)) != 0 ) {
762 if (atav->get_diskstream() != 0) {
763 speed = atav->get_diskstream()->speed();
767 pos = track_frame_to_session_frame(pos, speed);
769 if (cursor == playhead_cursor) {
770 session->request_locate (pos);
772 cursor->set_position (pos);
777 Editor::cursor_to_next_region_point (Cursor* cursor, RegionPoint point)
779 cursor_to_region_point (cursor, point, 1);
783 Editor::cursor_to_previous_region_point (Cursor* cursor, RegionPoint point)
785 cursor_to_region_point (cursor, point, -1);
789 Editor::cursor_to_selection_start (Cursor *cursor)
791 jack_nframes_t pos = 0;
792 switch (mouse_mode) {
794 if (!selection->regions.empty()) {
795 pos = selection->regions.start();
800 if (!selection->time.empty()) {
801 pos = selection->time.start ();
809 if (cursor == playhead_cursor) {
810 session->request_locate (pos);
812 cursor->set_position (pos);
817 Editor::cursor_to_selection_end (Cursor *cursor)
819 jack_nframes_t pos = 0;
821 switch (mouse_mode) {
823 if (!selection->regions.empty()) {
824 pos = selection->regions.end_frame();
829 if (!selection->time.empty()) {
830 pos = selection->time.end_frame ();
838 if (cursor == playhead_cursor) {
839 session->request_locate (pos);
841 cursor->set_position (pos);
846 Editor::playhead_backward ()
853 if (get_prefix (prefix, was_floating)) {
857 cnt = (jack_nframes_t) floor (prefix * session->frame_rate ());
859 cnt = (jack_nframes_t) prefix;
863 pos = playhead_cursor->current_frame;
865 if ((jack_nframes_t) pos < cnt) {
871 /* XXX this is completely insane. with the current buffering
872 design, we'll force a complete track buffer flush and
873 reload, just to move 1 sample !!!
876 session->request_locate (pos);
880 Editor::playhead_forward ()
887 if (get_prefix (prefix, was_floating)) {
891 cnt = (jack_nframes_t) floor (prefix * session->frame_rate ());
893 cnt = (jack_nframes_t) floor (prefix);
897 pos = playhead_cursor->current_frame;
899 /* XXX this is completely insane. with the current buffering
900 design, we'll force a complete track buffer flush and
901 reload, just to move 1 sample !!!
904 session->request_locate (pos+cnt);
908 Editor::cursor_align (bool playhead_to_edit)
910 if (playhead_to_edit) {
912 session->request_locate (edit_cursor->current_frame);
915 edit_cursor->set_position (playhead_cursor->current_frame);
920 Editor::edit_cursor_backward ()
927 if (get_prefix (prefix, was_floating)) {
931 cnt = (jack_nframes_t) floor (prefix * session->frame_rate ());
933 cnt = (jack_nframes_t) prefix;
937 pos = edit_cursor->current_frame;
939 if ((jack_nframes_t) pos < cnt) {
945 edit_cursor->set_position (pos);
949 Editor::edit_cursor_forward ()
956 if (get_prefix (prefix, was_floating)) {
960 cnt = (jack_nframes_t) floor (prefix * session->frame_rate ());
962 cnt = (jack_nframes_t) floor (prefix);
966 pos = edit_cursor->current_frame;
967 edit_cursor->set_position (pos+cnt);
971 Editor::goto_frame ()
975 jack_nframes_t frame;
977 if (get_prefix (prefix, was_floating)) {
982 frame = (jack_nframes_t) floor (prefix * session->frame_rate());
984 frame = (jack_nframes_t) floor (prefix);
987 session->request_locate (frame);
991 Editor::scroll_backward (float pages)
993 jack_nframes_t frame;
994 jack_nframes_t one_page = (jack_nframes_t) rint (canvas_width * frames_per_unit);
999 if (get_prefix (prefix, was_floating)) {
1000 cnt = (jack_nframes_t) floor (pages * one_page);
1003 cnt = (jack_nframes_t) floor (prefix * session->frame_rate());
1005 cnt = (jack_nframes_t) floor (prefix * one_page);
1009 if (leftmost_frame < cnt) {
1012 frame = leftmost_frame - cnt;
1015 reposition_x_origin (frame);
1019 Editor::scroll_forward (float pages)
1021 jack_nframes_t frame;
1022 jack_nframes_t one_page = (jack_nframes_t) rint (canvas_width * frames_per_unit);
1027 if (get_prefix (prefix, was_floating)) {
1028 cnt = (jack_nframes_t) floor (pages * one_page);
1031 cnt = (jack_nframes_t) floor (prefix * session->frame_rate());
1033 cnt = (jack_nframes_t) floor (prefix * one_page);
1037 if (ULONG_MAX - cnt < leftmost_frame) {
1038 frame = ULONG_MAX - cnt;
1040 frame = leftmost_frame + cnt;
1043 reposition_x_origin (frame);
1047 Editor::scroll_tracks_down ()
1053 if (get_prefix (prefix, was_floating)) {
1056 cnt = (int) floor (prefix);
1059 double vert_value = vertical_adjustment.get_value() + (cnt *
1060 vertical_adjustment.get_page_size());
1061 if (vert_value > vertical_adjustment.get_upper() - canvas_height) {
1062 vert_value = vertical_adjustment.get_upper() - canvas_height;
1064 vertical_adjustment.set_value (vert_value);
1068 Editor::scroll_tracks_up ()
1074 if (get_prefix (prefix, was_floating)) {
1077 cnt = (int) floor (prefix);
1080 vertical_adjustment.set_value (vertical_adjustment.get_value() - (cnt * vertical_adjustment.get_page_size()));
1084 Editor::scroll_tracks_down_line ()
1087 Gtk::Adjustment* adj = edit_vscrollbar.get_adjustment();
1088 double vert_value = adj->get_value() + 20;
1090 if (vert_value>adj->get_upper() - canvas_height) {
1091 vert_value = adj->get_upper() - canvas_height;
1093 adj->set_value (vert_value);
1097 Editor::scroll_tracks_up_line ()
1099 Gtk::Adjustment* adj = edit_vscrollbar.get_adjustment();
1100 adj->set_value (adj->get_value() - 20);
1106 Editor::temporal_zoom_step (bool coarser)
1108 ENSURE_GUI_THREAD (bind (mem_fun (*this, &Editor::temporal_zoom_step), coarser));
1112 nfpu = frames_per_unit;
1117 nfpu = max(1.0,(nfpu/2.0));
1120 temporal_zoom (nfpu);
1124 Editor::temporal_zoom (gdouble fpu)
1126 if (!session) return;
1128 jack_nframes_t current_page = current_page_frames();
1129 jack_nframes_t current_leftmost = leftmost_frame;
1130 jack_nframes_t current_rightmost;
1131 jack_nframes_t current_center;
1132 jack_nframes_t new_page;
1133 jack_nframes_t leftmost_after_zoom = 0;
1138 new_page = (jack_nframes_t) floor (canvas_width * nfpu);
1140 switch (zoom_focus) {
1142 leftmost_after_zoom = current_leftmost;
1145 case ZoomFocusRight:
1146 current_rightmost = leftmost_frame + current_page;
1147 if (current_rightmost > new_page) {
1148 leftmost_after_zoom = current_rightmost - new_page;
1150 leftmost_after_zoom = 0;
1154 case ZoomFocusCenter:
1155 current_center = current_leftmost + (current_page/2);
1156 if (current_center > (new_page/2)) {
1157 leftmost_after_zoom = current_center - (new_page / 2);
1159 leftmost_after_zoom = 0;
1163 case ZoomFocusPlayhead:
1164 /* try to keep the playhead in the center */
1165 if (playhead_cursor->current_frame > new_page/2) {
1166 leftmost_after_zoom = playhead_cursor->current_frame - (new_page/2);
1168 leftmost_after_zoom = 0;
1173 /* try to keep the edit cursor in the center */
1174 if (edit_cursor->current_frame > leftmost_frame + (new_page/2)) {
1175 leftmost_after_zoom = edit_cursor->current_frame - (new_page/2);
1177 leftmost_after_zoom = 0;
1183 // leftmost_after_zoom = min (leftmost_after_zoom, session->current_end_frame());
1185 // begin_reversible_command (_("zoom"));
1186 // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), current_leftmost, frames_per_unit));
1187 // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_after_zoom, nfpu));
1188 // commit_reversible_command ();
1190 reposition_and_zoom (leftmost_after_zoom, nfpu);
1194 Editor::temporal_zoom_selection ()
1196 if (!selection) return;
1198 if (selection->time.empty()) {
1202 jack_nframes_t start = selection->time[clicked_selection].start;
1203 jack_nframes_t end = selection->time[clicked_selection].end;
1205 temporal_zoom_by_frame (start, end, "zoom to selection");
1209 Editor::temporal_zoom_session ()
1211 ENSURE_GUI_THREAD (mem_fun (*this, &Editor::temporal_zoom_session));
1214 temporal_zoom_by_frame (session->current_start_frame(), session->current_end_frame(), "zoom to session");
1219 Editor::temporal_zoom_by_frame (jack_nframes_t start, jack_nframes_t end, const string & op)
1221 if (!session) return;
1223 if ((start == 0 && end == 0) || end < start) {
1227 jack_nframes_t range = end - start;
1229 double new_fpu = (double)range / (double)canvas_width;
1232 // while (p2 < new_fpu) {
1237 jack_nframes_t new_page = (jack_nframes_t) floor (canvas_width * new_fpu);
1238 jack_nframes_t middle = (jack_nframes_t) floor( (double)start + ((double)range / 2.0f ));
1239 jack_nframes_t new_leftmost = (jack_nframes_t) floor( (double)middle - ((double)new_page/2.0f));
1241 if (new_leftmost > middle) new_leftmost = 0;
1243 // begin_reversible_command (op);
1244 // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit));
1245 // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu));
1246 // commit_reversible_command ();
1248 reposition_and_zoom (new_leftmost, new_fpu);
1252 Editor::temporal_zoom_to_frame (bool coarser, jack_nframes_t frame)
1254 if (!session) return;
1256 jack_nframes_t range_before = frame - leftmost_frame;
1259 new_fpu = frames_per_unit;
1265 new_fpu = max(1.0,(new_fpu/2.0));
1269 if (new_fpu == frames_per_unit) return;
1271 jack_nframes_t new_leftmost = frame - range_before;
1273 if (new_leftmost > frame) new_leftmost = 0;
1275 // begin_reversible_command (_("zoom to frame"));
1276 // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit));
1277 // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu));
1278 // commit_reversible_command ();
1280 reposition_and_zoom (new_leftmost, new_fpu);
1284 Editor::add_location_from_selection ()
1286 if (selection->time.empty()) {
1290 if (session == 0 || clicked_trackview == 0) {
1294 jack_nframes_t start = selection->time[clicked_selection].start;
1295 jack_nframes_t end = selection->time[clicked_selection].end;
1297 Location *location = new Location (start, end, "selection");
1299 session->begin_reversible_command (_("add marker"));
1300 XMLNode &before = session->locations()->get_state();
1301 session->locations()->add (location, true);
1302 XMLNode &after = session->locations()->get_state();
1303 session->add_command(new MementoCommand<Locations>(*(session->locations()), before, after));
1304 session->commit_reversible_command ();
1308 Editor::add_location_from_playhead_cursor ()
1310 jack_nframes_t where = session->audible_frame();
1312 Location *location = new Location (where, where, "mark", Location::IsMark);
1313 session->begin_reversible_command (_("add marker"));
1314 XMLNode &before = session->locations()->get_state();
1315 session->locations()->add (location, true);
1316 XMLNode &after = session->locations()->get_state();
1317 session->add_command(new MementoCommand<Locations>(*(session->locations()), before, after));
1318 session->commit_reversible_command ();
1322 Editor::add_location_from_audio_region ()
1324 if (selection->regions.empty()) {
1328 RegionView* rv = *(selection->regions.begin());
1329 Region& region = rv->region();
1331 Location *location = new Location (region.position(), region.last_frame(), region.name());
1332 session->begin_reversible_command (_("add marker"));
1333 XMLNode &before = session->locations()->get_state();
1334 session->locations()->add (location, true);
1335 XMLNode &after = session->locations()->get_state();
1336 session->add_command(new MementoCommand<Locations>(*(session->locations()), before, after));
1337 session->commit_reversible_command ();
1341 Editor::select_all_in_track (Selection::Operation op)
1343 list<Selectable *> touched;
1345 if (!clicked_trackview) {
1349 clicked_trackview->get_selectables (0, max_frames, 0, DBL_MAX, touched);
1352 case Selection::Toggle:
1353 selection->add (touched);
1355 case Selection::Set:
1356 selection->set (touched);
1358 case Selection::Extend:
1359 /* not defined yet */
1365 Editor::select_all (Selection::Operation op)
1367 list<Selectable *> touched;
1369 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1370 if ((*iter)->hidden()) {
1373 (*iter)->get_selectables (0, max_frames, 0, DBL_MAX, touched);
1375 begin_reversible_command (_("select all"));
1377 case Selection::Toggle:
1378 selection->add (touched);
1380 case Selection::Set:
1381 selection->set (touched);
1383 case Selection::Extend:
1384 /* not defined yet */
1387 commit_reversible_command ();
1391 Editor::invert_selection_in_track ()
1393 list<Selectable *> touched;
1395 if (!clicked_trackview) {
1399 clicked_trackview->get_inverted_selectables (*selection, touched);
1400 selection->set (touched);
1404 Editor::invert_selection ()
1406 list<Selectable *> touched;
1408 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1409 if ((*iter)->hidden()) {
1412 (*iter)->get_inverted_selectables (*selection, touched);
1415 selection->set (touched);
1419 Editor::select_all_within (jack_nframes_t start, jack_nframes_t end, double top, double bot, Selection::Operation op)
1421 list<Selectable *> touched;
1423 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1424 if ((*iter)->hidden()) {
1427 (*iter)->get_selectables (start, end, top, bot, touched);
1430 cerr << "select all within found " << touched.size() << endl;
1432 begin_reversible_command (_("select all within"));
1434 case Selection::Toggle:
1436 selection->add (touched);
1438 case Selection::Set:
1440 selection->set (touched);
1442 case Selection::Extend:
1444 /* not defined yet */
1448 cerr << "selection now has " << selection->points.size() << endl;
1450 commit_reversible_command ();
1451 return !touched.empty();
1455 Editor::set_selection_from_audio_region ()
1457 if (selection->regions.empty()) {
1461 RegionView* rv = *(selection->regions.begin());
1462 Region& region = rv->region();
1464 begin_reversible_command (_("set selection from region"));
1465 selection->set (0, region.position(), region.last_frame());
1466 commit_reversible_command ();
1468 set_mouse_mode (Editing::MouseRange, false);
1472 Editor::set_selection_from_punch()
1476 if ((location = session->locations()->auto_punch_location()) == 0) {
1480 set_selection_from_range (*location);
1484 Editor::set_selection_from_loop()
1488 if ((location = session->locations()->auto_loop_location()) == 0) {
1491 set_selection_from_range (*location);
1495 Editor::set_selection_from_range (Location& loc)
1497 begin_reversible_command (_("set selection from range"));
1498 selection->set (0, loc.start(), loc.end());
1499 commit_reversible_command ();
1501 set_mouse_mode (Editing::MouseRange, false);
1505 Editor::select_all_selectables_using_time_selection ()
1507 list<Selectable *> touched;
1509 if (selection->time.empty()) {
1513 jack_nframes_t start = selection->time[clicked_selection].start;
1514 jack_nframes_t end = selection->time[clicked_selection].end;
1516 if (end - start < 1) {
1520 for (TrackViewList::iterator iter = selection->tracks.begin(); iter != selection->tracks.end(); ++iter) {
1521 if ((*iter)->hidden()) {
1524 (*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
1527 begin_reversible_command (_("select all from range"));
1528 selection->set (touched);
1529 commit_reversible_command ();
1534 Editor::select_all_selectables_using_punch()
1536 Location* location = session->locations()->auto_punch_location();
1537 list<Selectable *> touched;
1539 if (location == 0 || (location->end() - location->start() <= 1)) {
1543 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1544 if ((*iter)->hidden()) {
1547 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1549 begin_reversible_command (_("select all from punch"));
1550 selection->set (touched);
1551 commit_reversible_command ();
1556 Editor::select_all_selectables_using_loop()
1558 Location* location = session->locations()->auto_loop_location();
1559 list<Selectable *> touched;
1561 if (location == 0 || (location->end() - location->start() <= 1)) {
1565 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1566 if ((*iter)->hidden()) {
1569 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1571 begin_reversible_command (_("select all from loop"));
1572 selection->set (touched);
1573 commit_reversible_command ();
1578 Editor::select_all_selectables_using_cursor (Cursor *cursor, bool after)
1580 jack_nframes_t start;
1582 list<Selectable *> touched;
1585 begin_reversible_command (_("select all after cursor"));
1586 start = cursor->current_frame ;
1587 end = session->current_end_frame();
1589 if (cursor->current_frame > 0) {
1590 begin_reversible_command (_("select all before cursor"));
1592 end = cursor->current_frame - 1;
1598 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1599 if ((*iter)->hidden()) {
1602 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1604 selection->set (touched);
1605 commit_reversible_command ();
1609 Editor::select_all_selectables_between_cursors (Cursor *cursor, Cursor *other_cursor)
1611 jack_nframes_t start;
1613 list<Selectable *> touched;
1614 bool other_cursor_is_first = cursor->current_frame > other_cursor->current_frame;
1616 if (cursor->current_frame == other_cursor->current_frame) {
1620 begin_reversible_command (_("select all between cursors"));
1621 if (other_cursor_is_first) {
1622 start = other_cursor->current_frame;
1623 end = cursor->current_frame - 1;
1626 start = cursor->current_frame;
1627 end = other_cursor->current_frame - 1;
1630 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1631 if ((*iter)->hidden()) {
1634 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1636 selection->set (touched);
1637 commit_reversible_command ();
1641 Editor::amplitude_zoom_step (bool in)
1655 #ifdef FIX_FOR_CANVAS
1656 /* XXX DO SOMETHING */
1665 Editor::delete_sample_forward ()
1670 Editor::delete_sample_backward ()
1675 Editor::delete_screen ()
1682 Editor::search_backwards ()
1688 Editor::search_forwards ()
1696 Editor::jump_forward_to_mark ()
1702 Location *location = session->locations()->first_location_after (playhead_cursor->current_frame);
1705 session->request_locate (location->start(), session->transport_rolling());
1707 session->request_locate (session->current_end_frame());
1712 Editor::jump_backward_to_mark ()
1718 Location *location = session->locations()->first_location_before (playhead_cursor->current_frame);
1721 session->request_locate (location->start(), session->transport_rolling());
1723 session->goto_start ();
1734 if (get_prefix (prefix, was_floating)) {
1735 pos = session->audible_frame ();
1738 pos = (jack_nframes_t) floor (prefix * session->frame_rate ());
1740 pos = (jack_nframes_t) floor (prefix);
1744 session->locations()->add (new Location (pos, 0, "mark", Location::IsMark), true);
1748 Editor::clear_markers ()
1751 session->begin_reversible_command (_("clear markers"));
1752 XMLNode &before = session->locations()->get_state();
1753 session->locations()->clear_markers ();
1754 XMLNode &after = session->locations()->get_state();
1755 session->add_command(new MementoCommand<Locations>(*(session->locations()), before, after));
1756 session->commit_reversible_command ();
1761 Editor::clear_ranges ()
1764 session->begin_reversible_command (_("clear ranges"));
1765 XMLNode &before = session->locations()->get_state();
1767 Location * looploc = session->locations()->auto_loop_location();
1768 Location * punchloc = session->locations()->auto_punch_location();
1770 session->locations()->clear_ranges ();
1772 if (looploc) session->locations()->add (looploc);
1773 if (punchloc) session->locations()->add (punchloc);
1775 XMLNode &after = session->locations()->get_state();
1776 session->add_command(new MementoCommand<Locations>(*(session->locations()), before, after));
1777 session->commit_reversible_command ();
1782 Editor::clear_locations ()
1784 session->begin_reversible_command (_("clear locations"));
1785 XMLNode &before = session->locations()->get_state();
1786 session->locations()->clear ();
1787 XMLNode &after = session->locations()->get_state();
1788 session->add_command(new MementoCommand<Locations>(*(session->locations()), before, after));
1789 session->commit_reversible_command ();
1790 session->locations()->clear ();
1793 /* INSERT/REPLACE */
1796 Editor::insert_region_list_drag (AudioRegion& region, int x, int y)
1801 jack_nframes_t where;
1802 AudioTimeAxisView *atv = 0;
1805 track_canvas.window_to_world (x, y, wx, wy);
1806 wx += horizontal_adjustment.get_value();
1807 wy += vertical_adjustment.get_value();
1810 event.type = GDK_BUTTON_RELEASE;
1811 event.button.x = wx;
1812 event.button.y = wy;
1814 where = event_frame (&event, &cx, &cy);
1816 if (where < leftmost_frame || where > leftmost_frame + current_page_frames()) {
1817 /* clearly outside canvas area */
1821 if ((tv = trackview_by_y_position (cy)) == 0) {
1825 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) == 0) {
1829 if ((playlist = atv->playlist()) == 0) {
1835 begin_reversible_command (_("insert dragged region"));
1836 XMLNode &before = playlist->get_state();
1837 playlist->add_region (*(new AudioRegion (region)), where, 1.0);
1838 session->add_command(new MementoCommand<Playlist>(*playlist, before, playlist->get_state()));
1839 commit_reversible_command ();
1843 Editor::insert_region_list_selection (float times)
1845 RouteTimeAxisView *tv = 0;
1848 if (clicked_audio_trackview != 0) {
1849 tv = clicked_audio_trackview;
1850 } else if (!selection->tracks.empty()) {
1851 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
1858 if ((playlist = tv->playlist()) == 0) {
1862 Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
1864 if (selected->count_selected_rows() != 1) {
1868 TreeModel::iterator i = region_list_display.get_selection()->get_selected();
1869 Region* region = (*i)[region_list_columns.region];
1871 begin_reversible_command (_("insert region"));
1872 XMLNode &before = playlist->get_state();
1873 playlist->add_region (*(createRegion (*region)), edit_cursor->current_frame, times);
1874 session->add_command(new MementoCommand<Playlist>(*playlist, before, playlist->get_state()));
1875 commit_reversible_command ();
1879 /* BUILT-IN EFFECTS */
1882 Editor::reverse_selection ()
1887 /* GAIN ENVELOPE EDITING */
1890 Editor::edit_envelope ()
1897 Editor::toggle_playback (bool with_abort)
1903 switch (session->slave_source()) {
1908 /* transport controlled by the master */
1912 if (session->is_auditioning()) {
1913 session->cancel_audition ();
1917 if (session->transport_rolling()) {
1918 session->request_stop (with_abort);
1919 if (session->get_auto_loop()) {
1920 session->request_auto_loop (false);
1923 session->request_transport_speed (1.0f);
1928 Editor::play_from_start ()
1930 session->request_locate (session->current_start_frame(), true);
1934 Editor::play_selection ()
1936 if (selection->time.empty()) {
1940 session->request_play_range (true);
1944 Editor::play_selected_region ()
1946 if (!selection->regions.empty()) {
1947 RegionView *rv = *(selection->regions.begin());
1949 session->request_bounded_roll (rv->region().position(), rv->region().last_frame());
1954 Editor::loop_selected_region ()
1956 if (!selection->regions.empty()) {
1957 RegionView *rv = *(selection->regions.begin());
1960 if ((tll = transport_loop_location()) != 0) {
1962 tll->set (rv->region().position(), rv->region().last_frame());
1964 // enable looping, reposition and start rolling
1966 session->request_auto_loop (true);
1967 session->request_locate (tll->start(), false);
1968 session->request_transport_speed (1.0f);
1974 Editor::play_location (Location& location)
1976 if (location.start() <= location.end()) {
1980 session->request_bounded_roll (location.start(), location.end());
1984 Editor::loop_location (Location& location)
1986 if (location.start() <= location.end()) {
1992 if ((tll = transport_loop_location()) != 0) {
1993 tll->set (location.start(), location.end());
1995 // enable looping, reposition and start rolling
1996 session->request_auto_loop (true);
1997 session->request_locate (tll->start(), true);
2002 Editor::toggle_region_mute ()
2004 if (clicked_regionview) {
2005 clicked_regionview->region().set_muted (!clicked_regionview->region().muted());
2006 } else if (!selection->regions.empty()) {
2007 bool yn = ! (*selection->regions.begin())->region().muted();
2008 selection->foreach_region (&Region::set_muted, yn);
2013 Editor::toggle_region_opaque ()
2015 if (clicked_regionview) {
2016 clicked_regionview->region().set_opaque (!clicked_regionview->region().opaque());
2017 } else if (!selection->regions.empty()) {
2018 bool yn = ! (*selection->regions.begin())->region().opaque();
2019 selection->foreach_region (&Region::set_opaque, yn);
2024 Editor::raise_region ()
2026 selection->foreach_region (&Region::raise);
2030 Editor::raise_region_to_top ()
2032 selection->foreach_region (&Region::raise_to_top);
2036 Editor::lower_region ()
2038 selection->foreach_region (&Region::lower);
2042 Editor::lower_region_to_bottom ()
2044 selection->foreach_region (&Region::lower_to_bottom);
2048 Editor::edit_region ()
2050 if (clicked_regionview == 0) {
2054 clicked_regionview->show_region_editor ();
2058 Editor::rename_region ()
2062 Button ok_button (_("OK"));
2063 Button cancel_button (_("Cancel"));
2065 if (selection->regions.empty()) {
2069 dialog.set_title (_("ardour: rename region"));
2070 dialog.set_name ("RegionRenameWindow");
2071 dialog.set_size_request (300, -1);
2072 dialog.set_position (Gtk::WIN_POS_MOUSE);
2073 dialog.set_modal (true);
2075 dialog.get_vbox()->set_border_width (10);
2076 dialog.get_vbox()->pack_start (entry);
2077 dialog.get_action_area()->pack_start (ok_button);
2078 dialog.get_action_area()->pack_start (cancel_button);
2080 entry.set_name ("RegionNameDisplay");
2081 ok_button.set_name ("EditorGTKButton");
2082 cancel_button.set_name ("EditorGTKButton");
2084 region_renamed = false;
2086 entry.signal_activate().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
2087 ok_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
2088 cancel_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::rename_region_finished), false));
2095 if (region_renamed) {
2096 (*selection->regions.begin())->region().set_name (entry.get_text());
2097 redisplay_regions ();
2102 Editor::rename_region_finished (bool status)
2105 region_renamed = status;
2110 Editor::audition_playlist_region_via_route (Region& region, Route& route)
2112 if (session->is_auditioning()) {
2113 session->cancel_audition ();
2116 // note: some potential for creativity here, because region doesn't
2117 // have to belong to the playlist that Route is handling
2119 // bool was_soloed = route.soloed();
2121 route.set_solo (true, this);
2123 session->request_bounded_roll (region.position(), region.position() + region.length());
2125 /* XXX how to unset the solo state ? */
2129 Editor::audition_selected_region ()
2131 if (!selection->regions.empty()) {
2132 RegionView* rv = *(selection->regions.begin());
2133 session->audition_region (rv->region());
2138 Editor::audition_playlist_region_standalone (Region& region)
2140 session->audition_region (region);
2144 Editor::build_interthread_progress_window ()
2146 interthread_progress_window = new ArdourDialog (X_("interthread progress"), true);
2148 interthread_progress_bar.set_orientation (Gtk::PROGRESS_LEFT_TO_RIGHT);
2150 interthread_progress_window->get_vbox()->pack_start (interthread_progress_label, false, false);
2151 interthread_progress_window->get_vbox()->pack_start (interthread_progress_bar,false, false);
2153 // GTK2FIX: this button needs a modifiable label
2155 Button* b = interthread_progress_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
2156 b->signal_clicked().connect (mem_fun(*this, &Editor::interthread_cancel_clicked));
2158 interthread_cancel_button.add (interthread_cancel_label);
2160 interthread_progress_window->set_default_size (200, 100);
2164 Editor::interthread_cancel_clicked ()
2166 if (current_interthread_info) {
2167 current_interthread_info->cancel = true;
2172 Editor::region_from_selection ()
2174 if (clicked_trackview == 0) {
2178 if (selection->time.empty()) {
2182 jack_nframes_t start = selection->time[clicked_selection].start;
2183 jack_nframes_t end = selection->time[clicked_selection].end;
2185 jack_nframes_t selection_cnt = end - start + 1;
2187 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2188 AudioRegion *region;
2189 AudioRegion *current;
2193 jack_nframes_t internal_start;
2196 if ((pl = (*i)->playlist()) == 0) {
2200 if ((current_r = pl->top_region_at (start)) == 0) {
2204 current = dynamic_cast<AudioRegion*> (current_r);
2205 // FIXME: audio only
2207 internal_start = start - current->position();
2208 session->region_name (new_name, current->name(), true);
2209 region = new AudioRegion (*current, internal_start, selection_cnt, new_name);
2215 Editor::create_region_from_selection (vector<AudioRegion *>& new_regions)
2217 if (selection->time.empty() || selection->tracks.empty()) {
2221 jack_nframes_t start = selection->time[clicked_selection].start;
2222 jack_nframes_t end = selection->time[clicked_selection].end;
2224 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2226 AudioRegion* current;
2229 jack_nframes_t internal_start;
2232 if ((playlist = (*i)->playlist()) == 0) {
2236 if ((current_r = playlist->top_region_at(start)) == 0) {
2240 if ((current = dynamic_cast<AudioRegion*>(current_r)) == 0) {
2244 internal_start = start - current->position();
2245 session->region_name (new_name, current->name(), true);
2247 new_regions.push_back (new AudioRegion (*current, internal_start, end - start + 1, new_name));
2252 Editor::split_multichannel_region ()
2254 vector<AudioRegion*> v;
2256 AudioRegionView* clicked_arv = dynamic_cast<AudioRegionView*>(clicked_regionview);
2258 if (!clicked_arv || clicked_arv->audio_region().n_channels() < 2) {
2262 clicked_arv->audio_region().separate_by_channel (*session, v);
2264 /* nothing else to do, really */
2268 Editor::new_region_from_selection ()
2270 region_from_selection ();
2271 cancel_selection ();
2275 Editor::separate_region_from_selection ()
2277 bool doing_undo = false;
2279 if (selection->time.empty()) {
2285 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2287 AudioTimeAxisView* atv;
2289 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2291 if (atv->is_audio_track()) {
2293 if ((playlist = atv->playlist()) != 0) {
2295 begin_reversible_command (_("separate"));
2300 before = &(playlist->get_state());
2302 /* XXX need to consider musical time selections here at some point */
2304 double speed = atv->get_diskstream()->speed();
2306 for (list<AudioRange>::iterator t = selection->time.begin(); t != selection->time.end(); ++t) {
2307 playlist->partition ((jack_nframes_t)((*t).start * speed), (jack_nframes_t)((*t).end * speed), true);
2311 session->add_command(new MementoCommand<Playlist>(*playlist, *before, playlist->get_state()));
2317 if (doing_undo) commit_reversible_command ();
2321 Editor::separate_regions_using_location (Location& loc)
2323 bool doing_undo = false;
2325 if (loc.is_mark()) {
2331 /* XXX i'm unsure as to whether this should operate on selected tracks only
2332 or the entire enchillada. uncomment the below line to correct the behaviour
2333 (currently set for all tracks)
2336 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
2337 //for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2339 AudioTimeAxisView* atv;
2341 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2343 if (atv->is_audio_track()) {
2345 if ((playlist = atv->playlist()) != 0) {
2348 begin_reversible_command (_("separate"));
2352 before = &(playlist->get_state());
2355 /* XXX need to consider musical time selections here at some point */
2357 double speed = atv->get_diskstream()->speed();
2360 playlist->partition ((jack_nframes_t)(loc.start() * speed), (jack_nframes_t)(loc.end() * speed), true);
2362 session->add_command(new MementoCommand<Playlist>(*playlist, *before, playlist->get_state()));
2368 if (doing_undo) commit_reversible_command ();
2372 Editor::crop_region_to_selection ()
2374 if (selection->time.empty()) {
2378 vector<Playlist*> playlists;
2381 if (clicked_trackview != 0) {
2383 if ((playlist = clicked_trackview->playlist()) == 0) {
2387 playlists.push_back (playlist);
2391 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2393 AudioTimeAxisView* atv;
2395 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2397 if (atv->is_audio_track()) {
2399 if ((playlist = atv->playlist()) != 0) {
2400 playlists.push_back (playlist);
2407 if (!playlists.empty()) {
2409 jack_nframes_t start;
2413 begin_reversible_command (_("trim to selection"));
2415 for (vector<Playlist*>::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2419 start = selection->time.start();
2421 if ((region = (*i)->top_region_at(start)) == 0) {
2425 /* now adjust lengths to that we do the right thing
2426 if the selection extends beyond the region
2429 start = max (start, region->position());
2430 end = min (selection->time.end_frame(), start + region->length() - 1);
2431 cnt = end - start + 1;
2433 XMLNode &before = (*i)->get_state();
2434 region->trim_to (start, cnt, this);
2435 XMLNode &after = (*i)->get_state();
2436 session->add_command (new MementoCommand<Playlist>(*(*i), before, after));
2439 commit_reversible_command ();
2444 Editor::region_fill_track ()
2448 if (!session || selection->regions.empty()) {
2452 end = session->current_end_frame ();
2454 begin_reversible_command (_("region fill"));
2456 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2458 Region& region ((*i)->region());
2461 AudioRegion* const ar = dynamic_cast<AudioRegion*>(®ion);
2465 Playlist* pl = region.playlist();
2467 if (end <= region.last_frame()) {
2471 double times = (double) (end - region.last_frame()) / (double) region.length();
2477 XMLNode &before = pl->get_state();
2478 pl->add_region (*(new AudioRegion (*ar)), ar->last_frame(), times);
2479 session->add_command (new MementoCommand<Playlist>(*pl, before, pl->get_state()));
2482 commit_reversible_command ();
2486 Editor::region_fill_selection ()
2488 if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2492 if (selection->time.empty()) {
2498 Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
2500 if (selected->count_selected_rows() != 1) {
2504 TreeModel::iterator i = region_list_display.get_selection()->get_selected();
2505 region = (*i)[region_list_columns.region];
2507 jack_nframes_t start = selection->time[clicked_selection].start;
2508 jack_nframes_t end = selection->time[clicked_selection].end;
2512 if (selection->tracks.empty()) {
2516 jack_nframes_t selection_length = end - start;
2517 float times = (float)selection_length / region->length();
2519 begin_reversible_command (_("fill selection"));
2521 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2523 if ((playlist = (*i)->playlist()) == 0) {
2527 XMLNode &before = playlist->get_state();
2528 playlist->add_region (*(createRegion (*region)), start, times);
2529 session->add_command (new MementoCommand<Playlist>(*playlist, before, playlist->get_state()));
2532 commit_reversible_command ();
2536 Editor::set_a_regions_sync_position (Region& region, jack_nframes_t position)
2539 if (!region.covers (position)) {
2540 error << _("Programming error. that region doesn't cover that position") << __FILE__ << " +" << __LINE__ << endmsg;
2543 begin_reversible_command (_("set region sync position"));
2544 XMLNode &before = region.playlist()->get_state();
2545 region.set_sync_position (position);
2546 XMLNode &after = region.playlist()->get_state();
2547 session->add_command(new MementoCommand<Playlist>(*(region.playlist()), before, after));
2548 commit_reversible_command ();
2552 Editor::set_region_sync_from_edit_cursor ()
2554 if (clicked_regionview == 0) {
2558 if (!clicked_regionview->region().covers (edit_cursor->current_frame)) {
2559 error << _("Place the edit cursor at the desired sync point") << endmsg;
2563 Region& region (clicked_regionview->region());
2564 begin_reversible_command (_("set sync from edit cursor"));
2565 XMLNode &before = region.playlist()->get_state();
2566 region.set_sync_position (edit_cursor->current_frame);
2567 XMLNode &after = region.playlist()->get_state();
2568 session->add_command(new MementoCommand<Playlist>(*(region.playlist()), before, after));
2569 commit_reversible_command ();
2573 Editor::remove_region_sync ()
2575 if (clicked_regionview) {
2576 Region& region (clicked_regionview->region());
2577 begin_reversible_command (_("remove sync"));
2578 XMLNode &before = region.playlist()->get_state();
2579 region.clear_sync_position ();
2580 XMLNode &after = region.playlist()->get_state();
2581 session->add_command(new MementoCommand<Playlist>(*(region.playlist()), before, after));
2582 commit_reversible_command ();
2587 Editor::naturalize ()
2589 if (selection->regions.empty()) {
2592 begin_reversible_command (_("naturalize"));
2593 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2594 XMLNode &before = (*i)->region().get_state();
2595 (*i)->region().move_to_natural_position (this);
2596 XMLNode &after = (*i)->region().get_state();
2597 session->add_command (new MementoCommand<Region>((*i)->region(), before, after));
2599 commit_reversible_command ();
2603 Editor::align (RegionPoint what)
2605 align_selection (what, edit_cursor->current_frame);
2609 Editor::align_relative (RegionPoint what)
2611 align_selection_relative (what, edit_cursor->current_frame);
2614 struct RegionSortByTime {
2615 bool operator() (const AudioRegionView* a, const AudioRegionView* b) {
2616 return a->region().position() < b->region().position();
2621 Editor::align_selection_relative (RegionPoint point, jack_nframes_t position)
2623 if (selection->regions.empty()) {
2627 jack_nframes_t distance;
2628 jack_nframes_t pos = 0;
2631 list<RegionView*> sorted;
2632 selection->regions.by_position (sorted);
2633 Region& r ((*sorted.begin())->region());
2637 pos = r.first_frame ();
2641 pos = r.last_frame();
2645 pos = r.adjust_to_sync (r.first_frame());
2649 if (pos > position) {
2650 distance = pos - position;
2653 distance = position - pos;
2657 begin_reversible_command (_("align selection (relative)"));
2659 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2661 Region& region ((*i)->region());
2663 XMLNode &before = region.playlist()->get_state();
2666 region.set_position (region.position() + distance, this);
2668 region.set_position (region.position() - distance, this);
2671 XMLNode &after = region.playlist()->get_state();
2672 session->add_command(new MementoCommand<Playlist>(*(region.playlist()), before, after));
2676 commit_reversible_command ();
2680 Editor::align_selection (RegionPoint point, jack_nframes_t position)
2682 if (selection->regions.empty()) {
2686 begin_reversible_command (_("align selection"));
2688 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2689 align_region_internal ((*i)->region(), point, position);
2692 commit_reversible_command ();
2696 Editor::align_region (Region& region, RegionPoint point, jack_nframes_t position)
2698 begin_reversible_command (_("align region"));
2699 align_region_internal (region, point, position);
2700 commit_reversible_command ();
2704 Editor::align_region_internal (Region& region, RegionPoint point, jack_nframes_t position)
2706 XMLNode &before = region.playlist()->get_state();
2710 region.set_position (region.adjust_to_sync (position), this);
2714 if (position > region.length()) {
2715 region.set_position (position - region.length(), this);
2720 region.set_position (position, this);
2724 XMLNode &after = region.playlist()->get_state();
2725 session->add_command(new MementoCommand<Playlist>(*(region.playlist()), before, after));
2729 Editor::trim_region_to_edit_cursor ()
2731 if (clicked_regionview == 0) {
2735 Region& region (clicked_regionview->region());
2738 AudioTimeAxisView *atav;
2740 if ( clicked_trackview != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(clicked_trackview)) != 0 ) {
2741 if (atav->get_diskstream() != 0) {
2742 speed = atav->get_diskstream()->speed();
2746 begin_reversible_command (_("trim to edit"));
2747 XMLNode &before = region.playlist()->get_state();
2748 region.trim_end( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
2749 XMLNode &after = region.playlist()->get_state();
2750 session->add_command(new MementoCommand<Playlist>(*(region.playlist()), before, after));
2751 commit_reversible_command ();
2755 Editor::trim_region_from_edit_cursor ()
2757 if (clicked_regionview == 0) {
2761 Region& region (clicked_regionview->region());
2764 AudioTimeAxisView *atav;
2766 if ( clicked_trackview != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(clicked_trackview)) != 0 ) {
2767 if (atav->get_diskstream() != 0) {
2768 speed = atav->get_diskstream()->speed();
2772 begin_reversible_command (_("trim to edit"));
2773 XMLNode &before = region.playlist()->get_state();
2774 region.trim_front ( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
2775 XMLNode &after = region.playlist()->get_state();
2776 session->add_command(new MementoCommand<Playlist>(*(region.playlist()), before, after));
2777 commit_reversible_command ();
2781 Editor::unfreeze_route ()
2783 if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2787 clicked_audio_trackview->audio_track()->unfreeze ();
2791 Editor::_freeze_thread (void* arg)
2793 PBD::ThreadCreated (pthread_self(), X_("Freeze"));
2794 return static_cast<Editor*>(arg)->freeze_thread ();
2798 Editor::freeze_thread ()
2800 clicked_audio_trackview->audio_track()->freeze (*current_interthread_info);
2805 Editor::freeze_progress_timeout (void *arg)
2807 interthread_progress_bar.set_fraction (current_interthread_info->progress/100);
2808 return !(current_interthread_info->done || current_interthread_info->cancel);
2812 Editor::freeze_route ()
2814 if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2818 InterThreadInfo itt;
2820 if (interthread_progress_window == 0) {
2821 build_interthread_progress_window ();
2824 interthread_progress_window->set_title (_("ardour: freeze"));
2825 interthread_progress_window->set_position (Gtk::WIN_POS_MOUSE);
2826 interthread_progress_window->show_all ();
2827 interthread_progress_bar.set_fraction (0.0f);
2828 interthread_progress_label.set_text ("");
2829 interthread_cancel_label.set_text (_("Cancel Freeze"));
2830 current_interthread_info = &itt;
2832 interthread_progress_connection =
2833 Glib::signal_timeout().connect (bind (mem_fun(*this, &Editor::freeze_progress_timeout), (gpointer) 0), 100);
2837 itt.progress = 0.0f;
2839 pthread_create (&itt.thread, 0, _freeze_thread, this);
2841 track_canvas.get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
2843 while (!itt.done && !itt.cancel) {
2844 gtk_main_iteration ();
2847 interthread_progress_connection.disconnect ();
2848 interthread_progress_window->hide_all ();
2849 current_interthread_info = 0;
2850 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
2854 Editor::bounce_range_selection ()
2856 if (selection->time.empty()) {
2860 TrackViewList *views = get_valid_views (selection->time.track, selection->time.group);
2862 jack_nframes_t start = selection->time[clicked_selection].start;
2863 jack_nframes_t end = selection->time[clicked_selection].end;
2864 jack_nframes_t cnt = end - start + 1;
2866 begin_reversible_command (_("bounce range"));
2868 for (TrackViewList::iterator i = views->begin(); i != views->end(); ++i) {
2870 AudioTimeAxisView* atv;
2872 if ((atv = dynamic_cast<AudioTimeAxisView*> (*i)) == 0) {
2878 if ((playlist = atv->playlist()) == 0) {
2882 InterThreadInfo itt;
2886 itt.progress = false;
2888 XMLNode &before = playlist->get_state();
2889 atv->audio_track()->bounce_range (start, cnt, itt);
2890 XMLNode &after = playlist->get_state();
2891 session->add_command (new MementoCommand<Playlist> (*playlist, before, after));
2894 commit_reversible_command ();
2912 Editor::cut_copy (CutCopyOp op)
2914 /* only cancel selection if cut/copy is successful.*/
2926 opname = _("clear");
2930 cut_buffer->clear ();
2932 switch (current_mouse_mode()) {
2934 if (!selection->regions.empty() || !selection->points.empty()) {
2936 begin_reversible_command (opname + _(" objects"));
2938 if (!selection->regions.empty()) {
2940 cut_copy_regions (op);
2943 selection->clear_regions ();
2947 if (!selection->points.empty()) {
2948 cut_copy_points (op);
2951 selection->clear_points ();
2955 commit_reversible_command ();
2960 if (!selection->time.empty()) {
2962 begin_reversible_command (opname + _(" range"));
2963 cut_copy_ranges (op);
2964 commit_reversible_command ();
2967 selection->clear_time ();
2979 Editor::cut_copy_points (CutCopyOp op)
2981 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
2983 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
2986 atv->cut_copy_clear_objects (selection->points, op);
2992 Editor::cut_copy_regions (CutCopyOp op)
2994 typedef std::map<AudioPlaylist*,AudioPlaylist*> PlaylistMapping;
2995 PlaylistMapping pmap;
2996 jack_nframes_t first_position = max_frames;
2997 set<Playlist*> freezelist;
2998 pair<set<Playlist*>::iterator,bool> insert_result;
3000 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3001 first_position = min ((*x)->region().position(), first_position);
3003 if (op == Cut || op == Clear) {
3004 AudioPlaylist *pl = dynamic_cast<AudioPlaylist*>((*x)->region().playlist());
3006 insert_result = freezelist.insert (pl);
3007 if (insert_result.second) {
3009 session->add_command (new MementoUndoCommand<Playlist>(*pl, pl->get_state()));
3015 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ) {
3017 AudioPlaylist *pl = dynamic_cast<AudioPlaylist*>((*x)->region().playlist());
3019 RegionSelection::iterator tmp;
3026 PlaylistMapping::iterator pi = pmap.find (pl);
3028 if (pi == pmap.end()) {
3029 npl = new AudioPlaylist (*session, "cutlist", true);
3037 AudioRegion* const ar = dynamic_cast<AudioRegion*>(&(*x)->region());
3042 npl->add_region (*(new AudioRegion (*ar)), (*x)->region().position() - first_position);
3043 pl->remove_region (&((*x)->region()));
3049 npl->add_region (*(new AudioRegion (*ar)), (*x)->region().position() - first_position);
3053 pl->remove_region (&((*x)->region()));
3061 list<Playlist*> foo;
3063 for (PlaylistMapping::iterator i = pmap.begin(); i != pmap.end(); ++i) {
3064 foo.push_back (i->second);
3068 cut_buffer->set (foo);
3071 for (set<Playlist*>::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
3073 session->add_command (new MementoRedoCommand<Playlist>(*(*pl), (*pl)->get_state()));
3078 Editor::cut_copy_ranges (CutCopyOp op)
3080 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3081 (*i)->cut_copy_clear (*selection, op);
3086 Editor::paste (float times)
3088 paste_internal (edit_cursor->current_frame, times);
3092 Editor::mouse_paste ()
3097 track_canvas.get_pointer (x, y);
3098 track_canvas.window_to_world (x, y, wx, wy);
3099 wx += horizontal_adjustment.get_value();
3100 wy += vertical_adjustment.get_value();
3103 event.type = GDK_BUTTON_RELEASE;
3104 event.button.x = wx;
3105 event.button.y = wy;
3107 jack_nframes_t where = event_frame (&event, 0, 0);
3109 paste_internal (where, 1);
3113 Editor::paste_internal (jack_nframes_t position, float times)
3115 bool commit = false;
3117 if (cut_buffer->empty() || selection->tracks.empty()) {
3121 if (position == max_frames) {
3122 position = edit_cursor->current_frame;
3125 begin_reversible_command (_("paste"));
3127 TrackSelection::iterator i;
3130 for (nth = 0, i = selection->tracks.begin(); i != selection->tracks.end(); ++i, ++nth) {
3132 /* undo/redo is handled by individual tracks */
3134 if ((*i)->paste (position, times, *cut_buffer, nth)) {
3140 commit_reversible_command ();
3145 Editor::paste_named_selection (float times)
3147 TrackSelection::iterator t;
3149 Glib::RefPtr<TreeSelection> selected = named_selection_display.get_selection();
3151 if (selected->count_selected_rows() != 1 || selection->tracks.empty()) {
3155 TreeModel::iterator i = selected->get_selected();
3156 NamedSelection* ns = (*i)[named_selection_columns.selection];
3158 list<Playlist*>::iterator chunk;
3159 list<Playlist*>::iterator tmp;
3161 chunk = ns->playlists.begin();
3163 begin_reversible_command (_("paste chunk"));
3165 for (t = selection->tracks.begin(); t != selection->tracks.end(); ++t) {
3167 AudioTimeAxisView* atv;
3171 if ((atv = dynamic_cast<AudioTimeAxisView*> (*t)) == 0) {
3175 if ((pl = atv->playlist()) == 0) {
3179 if ((apl = dynamic_cast<AudioPlaylist*> (pl)) == 0) {
3186 XMLNode &before = apl->get_state();
3187 apl->paste (**chunk, edit_cursor->current_frame, times);
3188 session->add_command(new MementoCommand<AudioPlaylist>(*apl, before, apl->get_state()));
3190 if (tmp != ns->playlists.end()) {
3195 commit_reversible_command();
3199 Editor::duplicate_some_regions (RegionSelection& regions, float times)
3202 RegionSelection sel = regions; // clear (below) will clear the argument list
3204 begin_reversible_command (_("duplicate region"));
3206 selection->clear_regions ();
3208 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
3210 Region& r ((*i)->region());
3212 TimeAxisView& tv = (*i)->get_time_axis_view();
3213 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&tv);
3214 sigc::connection c = atv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3216 playlist = (*i)->region().playlist();
3217 XMLNode &before = playlist->get_state();
3218 playlist->duplicate (r, r.last_frame(), times);
3219 session->add_command(new MementoCommand<Playlist>(*playlist, before, playlist->get_state()));
3223 if (latest_regionview) {
3224 selection->add (latest_regionview);
3229 commit_reversible_command ();
3233 Editor::duplicate_selection (float times)
3235 if (selection->time.empty() || selection->tracks.empty()) {
3240 vector<AudioRegion*> new_regions;
3241 vector<AudioRegion*>::iterator ri;
3243 create_region_from_selection (new_regions);
3245 if (new_regions.empty()) {
3249 begin_reversible_command (_("duplicate selection"));
3251 ri = new_regions.begin();
3253 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3254 if ((playlist = (*i)->playlist()) == 0) {
3257 XMLNode &before = playlist->get_state();
3258 playlist->duplicate (**ri, selection->time[clicked_selection].end, times);
3259 XMLNode &after = playlist->get_state();
3260 session->add_command (new MementoCommand<Playlist>(*playlist, before, after));
3263 if (ri == new_regions.end()) {
3268 commit_reversible_command ();
3272 Editor::reset_point_selection ()
3274 /* reset all selected points to the relevant default value */
3276 cerr << "point selection has " << selection->points.size() << " entries\n";
3278 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3280 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
3283 atv->reset_objects (selection->points);
3289 Editor::center_playhead ()
3291 float page = canvas_width * frames_per_unit;
3293 center_screen_internal (playhead_cursor->current_frame, page);
3297 Editor::center_edit_cursor ()
3299 float page = canvas_width * frames_per_unit;
3301 center_screen_internal (edit_cursor->current_frame, page);
3305 Editor::clear_playlist (Playlist& playlist)
3307 begin_reversible_command (_("clear playlist"));
3308 XMLNode &before = playlist.get_state();
3310 XMLNode &after = playlist.get_state();
3311 session->add_command (new MementoCommand<Playlist>(playlist, before, after));
3312 commit_reversible_command ();
3316 Editor::nudge_track (bool use_edit_cursor, bool forwards)
3319 jack_nframes_t distance;
3320 jack_nframes_t next_distance;
3321 jack_nframes_t start;
3323 if (use_edit_cursor) {
3324 start = edit_cursor->current_frame;
3329 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
3333 if (selection->tracks.empty()) {
3337 begin_reversible_command (_("nudge track"));
3339 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3341 if ((playlist = (*i)->playlist()) == 0) {
3345 XMLNode &before = playlist->get_state();
3346 playlist->nudge_after (start, distance, forwards);
3347 XMLNode &after = playlist->get_state();
3348 session->add_command (new MementoCommand<Playlist>(*playlist, before, after));
3351 commit_reversible_command ();
3355 Editor::remove_last_capture ()
3357 vector<string> choices;
3364 if (Config->get_verify_remove_last_capture()) {
3365 prompt = _("Do you really want to destroy the last capture?"
3366 "\n(This is destructive and cannot be undone)");
3368 choices.push_back (_("No, do nothing."));
3369 choices.push_back (_("Yes, destroy it."));
3371 Gtkmm2ext::Choice prompter (prompt, choices);
3373 if (prompter.run () == 1) {
3374 session->remove_last_capture ();
3378 session->remove_last_capture();
3383 Editor::normalize_region ()
3389 if (selection->regions.empty()) {
3393 begin_reversible_command (_("normalize"));
3395 track_canvas.get_window()->set_cursor (*wait_cursor);
3398 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
3399 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3402 XMLNode &before = arv->region().get_state();
3403 arv->audio_region().normalize_to (0.0f);
3404 session->add_command (new MementoCommand<Region>(arv->region(), before, arv->region().get_state()));
3407 commit_reversible_command ();
3408 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3413 Editor::denormalize_region ()
3419 if (selection->regions.empty()) {
3423 begin_reversible_command ("denormalize");
3425 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
3426 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3429 XMLNode &before = arv->region().get_state();
3430 arv->audio_region().set_scale_amplitude (1.0f);
3431 session->add_command (new MementoCommand<Region>(arv->region(), before, arv->region().get_state()));
3434 commit_reversible_command ();
3439 Editor::reverse_region ()
3445 Reverse rev (*session);
3446 apply_filter (rev, _("reverse regions"));
3450 Editor::apply_filter (AudioFilter& filter, string command)
3452 if (selection->regions.empty()) {
3456 begin_reversible_command (command);
3458 track_canvas.get_window()->set_cursor (*wait_cursor);
3461 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ) {
3462 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3466 Playlist* playlist = arv->region().playlist();
3468 RegionSelection::iterator tmp;
3473 if (arv->audio_region().apply (filter) == 0) {
3475 XMLNode &before = playlist->get_state();
3476 playlist->replace_region (arv->region(), *(filter.results.front()), arv->region().position());
3477 XMLNode &after = playlist->get_state();
3478 session->add_command(new MementoCommand<Playlist>(*playlist, before, after));
3486 commit_reversible_command ();
3487 selection->regions.clear ();
3490 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3494 Editor::region_selection_op (void (Region::*pmf)(void))
3496 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3497 ((*i)->region().*pmf)();
3503 Editor::region_selection_op (void (Region::*pmf)(void*), void *arg)
3505 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3506 ((*i)->region().*pmf)(arg);
3511 Editor::region_selection_op (void (Region::*pmf)(bool), bool yn)
3513 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3514 ((*i)->region().*pmf)(yn);
3519 Editor::external_edit_region ()
3521 if (!clicked_regionview) {
3529 Editor::brush (jack_nframes_t pos)
3531 RegionSelection sel;
3534 if (selection->regions.empty()) {
3535 /* XXX get selection from region list */
3537 sel = selection->regions;
3544 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3545 mouse_brush_insert_region ((*i), pos);
3550 Editor::toggle_gain_envelope_visibility ()
3552 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3553 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3555 arv->set_envelope_visible (!arv->envelope_visible());
3560 Editor::toggle_gain_envelope_active ()
3562 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3563 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3565 arv->audio_region().set_envelope_active (true);