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::ensure_cursor (nframes_t *pos)
96 *pos = edit_cursor->current_frame;
101 Editor::split_region ()
103 split_region_at (edit_cursor->current_frame);
107 Editor::split_region_at (nframes_t where)
109 split_regions_at (where, selection->regions);
113 Editor::split_regions_at (nframes_t where, RegionSelection& regions)
115 begin_reversible_command (_("split"));
118 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
120 RegionSelection::iterator tmp;
125 Playlist* pl = (*a)->region()->playlist();
127 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*a);
129 _new_regionviews_show_envelope = arv->envelope_visible();
132 XMLNode &before = pl->get_state();
133 pl->split_region ((*a)->region(), where);
134 XMLNode &after = pl->get_state();
135 session->add_command(new MementoCommand<Playlist>(*pl, &before, &after));
141 commit_reversible_command ();
142 _new_regionviews_show_envelope = false;
146 Editor::remove_clicked_region ()
148 if (clicked_audio_trackview == 0 || clicked_regionview == 0) {
152 Playlist* playlist = clicked_audio_trackview->playlist();
154 begin_reversible_command (_("remove region"));
155 XMLNode &before = playlist->get_state();
156 playlist->remove_region (clicked_regionview->region());
157 XMLNode &after = playlist->get_state();
158 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
159 commit_reversible_command ();
163 Editor::destroy_clicked_region ()
165 uint32_t selected = selection->regions.size();
167 if (!session || !selected) {
171 vector<string> choices;
174 prompt = string_compose (_(" This is destructive, will possibly delete audio files\n\
175 It cannot be undone\n\
176 Do you really want to destroy %1 ?"),
178 _("these regions") : _("this region")));
180 choices.push_back (_("No, do nothing."));
183 choices.push_back (_("Yes, destroy them."));
185 choices.push_back (_("Yes, destroy it."));
188 Gtkmm2ext::Choice prompter (prompt, choices);
190 if (prompter.run() == 0) { /* first choice */
195 list<boost::shared_ptr<Region> > r;
197 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
198 r.push_back ((*i)->region());
201 session->destroy_regions (r);
205 boost::shared_ptr<Region>
206 Editor::select_region_for_operation (int dir, TimeAxisView **tv)
209 boost::shared_ptr<Region> region;
212 if (selection->time.start () == selection->time.end_frame ()) {
214 /* no current selection-> is there a selected regionview? */
216 if (selection->regions.empty()) {
222 if (!selection->regions.empty()) {
224 rv = *(selection->regions.begin());
225 (*tv) = &rv->get_time_axis_view();
226 region = rv->region();
228 } else if (!selection->tracks.empty()) {
230 (*tv) = selection->tracks.front();
232 RouteTimeAxisView* rtv;
234 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*tv)) != 0) {
237 if ((pl = rtv->playlist()) == 0) {
241 region = pl->top_region_at (start);
249 Editor::extend_selection_to_end_of_region (bool next)
252 boost::shared_ptr<Region> region;
255 if ((region = select_region_for_operation (next ? 1 : 0, &tv)) == 0) {
259 if (region && selection->time.start () == selection->time.end_frame ()) {
260 start = region->position();
262 start = selection->time.start ();
265 /* Try to leave the selection with the same route if possible */
267 if ((tv = selection->time.track) == 0) {
271 begin_reversible_command (_("extend selection"));
272 selection->set (tv, start, region->position() + region->length());
273 commit_reversible_command ();
277 Editor::extend_selection_to_start_of_region (bool previous)
280 boost::shared_ptr<Region> region;
283 if ((region = select_region_for_operation (previous ? -1 : 0, &tv)) == 0) {
287 if (region && selection->time.start () == selection->time.end_frame ()) {
288 end = region->position() + region->length();
290 end = selection->time.end_frame ();
293 /* Try to leave the selection with the same route if possible */
295 if ((tv = selection->time.track) == 0) {
299 begin_reversible_command (_("extend selection"));
300 selection->set (tv, region->position(), end);
301 commit_reversible_command ();
306 Editor::nudge_forward (bool next)
309 nframes_t next_distance;
311 if (!session) return;
313 if (!selection->regions.empty()) {
315 begin_reversible_command (_("nudge forward"));
317 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
318 boost::shared_ptr<Region> r ((*i)->region());
320 distance = get_nudge_distance (r->position(), next_distance);
323 distance = next_distance;
326 XMLNode &before = r->playlist()->get_state();
327 r->set_position (r->position() + distance, this);
328 XMLNode &after = r->playlist()->get_state();
329 session->add_command (new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
332 commit_reversible_command ();
335 distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
336 session->request_locate (playhead_cursor->current_frame + distance);
341 Editor::nudge_backward (bool next)
344 nframes_t next_distance;
346 if (!session) return;
348 if (!selection->regions.empty()) {
350 begin_reversible_command (_("nudge forward"));
352 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
353 boost::shared_ptr<Region> r ((*i)->region());
355 distance = get_nudge_distance (r->position(), next_distance);
358 distance = next_distance;
361 XMLNode &before = r->playlist()->get_state();
363 if (r->position() > distance) {
364 r->set_position (r->position() - distance, this);
366 r->set_position (0, this);
368 XMLNode &after = r->playlist()->get_state();
369 session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
372 commit_reversible_command ();
376 distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
378 if (playhead_cursor->current_frame > distance) {
379 session->request_locate (playhead_cursor->current_frame - distance);
381 session->goto_start();
387 Editor::nudge_forward_capture_offset ()
391 if (!session) return;
393 if (!selection->regions.empty()) {
395 begin_reversible_command (_("nudge forward"));
397 distance = session->worst_output_latency();
399 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
400 boost::shared_ptr<Region> r ((*i)->region());
402 XMLNode &before = r->playlist()->get_state();
403 r->set_position (r->position() + distance, this);
404 XMLNode &after = r->playlist()->get_state();
405 session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
408 commit_reversible_command ();
414 Editor::nudge_backward_capture_offset ()
418 if (!session) return;
420 if (!selection->regions.empty()) {
422 begin_reversible_command (_("nudge forward"));
424 distance = session->worst_output_latency();
426 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
427 boost::shared_ptr<Region> r ((*i)->region());
429 XMLNode &before = r->playlist()->get_state();
431 if (r->position() > distance) {
432 r->set_position (r->position() - distance, this);
434 r->set_position (0, this);
436 XMLNode &after = r->playlist()->get_state();
437 session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
440 commit_reversible_command ();
447 Editor::move_to_start ()
449 session->goto_start ();
453 Editor::move_to_end ()
456 session->request_locate (session->current_end_frame());
460 Editor::build_region_boundary_cache ()
464 boost::shared_ptr<Region> r;
465 TrackViewList tracks;
467 region_boundary_cache.clear ();
474 case SnapToRegionStart:
477 case SnapToRegionEnd:
480 case SnapToRegionSync:
483 case SnapToRegionBoundary:
487 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), snap_type) << endmsg;
492 TimeAxisView *ontrack = 0;
494 while (pos < session->current_end_frame()) {
496 if (!selection->tracks.empty()) {
498 if ((r = find_next_region (pos, point, 1, selection->tracks, &ontrack)) == 0) {
502 } else if (clicked_trackview) {
505 t.push_back (clicked_trackview);
507 if ((r = find_next_region (pos, point, 1, t, &ontrack)) == 0) {
513 if ((r = find_next_region (pos, point, 1, track_views, &ontrack)) == 0) {
521 case SnapToRegionStart:
522 rpos = r->first_frame();
524 case SnapToRegionEnd:
525 rpos = r->last_frame();
527 case SnapToRegionSync:
528 rpos = r->adjust_to_sync (r->first_frame());
531 case SnapToRegionBoundary:
532 rpos = r->last_frame();
539 AudioTimeAxisView *atav;
541 if ( ontrack != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(ontrack)) != 0 ) {
542 if (atav->get_diskstream() != 0) {
543 speed = atav->get_diskstream()->speed();
547 rpos = track_frame_to_session_frame(rpos, speed);
549 if (region_boundary_cache.empty() || rpos != region_boundary_cache.back()) {
550 if (snap_type == SnapToRegionBoundary) {
551 region_boundary_cache.push_back (r->first_frame());
553 region_boundary_cache.push_back (rpos);
560 boost::shared_ptr<Region>
561 Editor::find_next_region (nframes_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
563 TrackViewList::iterator i;
564 nframes_t closest = max_frames;
565 boost::shared_ptr<Region> ret;
569 nframes_t track_frame;
570 AudioTimeAxisView *atav;
572 for (i = tracks.begin(); i != tracks.end(); ++i) {
575 boost::shared_ptr<Region> r;
578 if ( (atav = dynamic_cast<AudioTimeAxisView*>(*i)) != 0 ) {
579 if (atav->get_diskstream()!=0)
580 track_speed = atav->get_diskstream()->speed();
583 track_frame = session_frame_to_track_frame(frame, track_speed);
585 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
591 rpos = r->first_frame ();
595 rpos = r->last_frame ();
599 rpos = r->adjust_to_sync (r->first_frame());
602 // rpos is a "track frame", converting it to "session frame"
603 rpos = track_frame_to_session_frame(rpos, track_speed);
606 distance = rpos - frame;
608 distance = frame - rpos;
611 if (distance < closest) {
623 Editor::cursor_to_region_point (Cursor* cursor, RegionPoint point, int32_t dir)
625 boost::shared_ptr<Region> r;
626 nframes_t pos = cursor->current_frame;
632 TimeAxisView *ontrack = 0;
634 // so we don't find the current region again..
638 if (!selection->tracks.empty()) {
640 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
642 } else if (clicked_trackview) {
645 t.push_back (clicked_trackview);
647 r = find_next_region (pos, point, dir, t, &ontrack);
651 r = find_next_region (pos, point, dir, track_views, &ontrack);
660 pos = r->first_frame ();
664 pos = r->last_frame ();
668 pos = r->adjust_to_sync (r->first_frame());
673 AudioTimeAxisView *atav;
675 if ( ontrack != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(ontrack)) != 0 ) {
676 if (atav->get_diskstream() != 0) {
677 speed = atav->get_diskstream()->speed();
681 pos = track_frame_to_session_frame(pos, speed);
683 if (cursor == playhead_cursor) {
684 session->request_locate (pos);
686 cursor->set_position (pos);
691 Editor::cursor_to_next_region_point (Cursor* cursor, RegionPoint point)
693 cursor_to_region_point (cursor, point, 1);
697 Editor::cursor_to_previous_region_point (Cursor* cursor, RegionPoint point)
699 cursor_to_region_point (cursor, point, -1);
703 Editor::cursor_to_selection_start (Cursor *cursor)
706 switch (mouse_mode) {
708 if (!selection->regions.empty()) {
709 pos = selection->regions.start();
714 if (!selection->time.empty()) {
715 pos = selection->time.start ();
723 if (cursor == playhead_cursor) {
724 session->request_locate (pos);
726 cursor->set_position (pos);
731 Editor::cursor_to_selection_end (Cursor *cursor)
735 switch (mouse_mode) {
737 if (!selection->regions.empty()) {
738 pos = selection->regions.end_frame();
743 if (!selection->time.empty()) {
744 pos = selection->time.end_frame ();
752 if (cursor == playhead_cursor) {
753 session->request_locate (pos);
755 cursor->set_position (pos);
760 Editor::playhead_backward ()
767 if (get_prefix (prefix, was_floating)) {
771 cnt = (nframes_t) floor (prefix * session->frame_rate ());
773 cnt = (nframes_t) prefix;
777 pos = playhead_cursor->current_frame;
779 if ((nframes_t) pos < cnt) {
785 /* XXX this is completely insane. with the current buffering
786 design, we'll force a complete track buffer flush and
787 reload, just to move 1 sample !!!
790 session->request_locate (pos);
794 Editor::playhead_forward ()
801 if (get_prefix (prefix, was_floating)) {
805 cnt = (nframes_t) floor (prefix * session->frame_rate ());
807 cnt = (nframes_t) floor (prefix);
811 pos = playhead_cursor->current_frame;
813 /* XXX this is completely insane. with the current buffering
814 design, we'll force a complete track buffer flush and
815 reload, just to move 1 sample !!!
818 session->request_locate (pos+cnt);
822 Editor::cursor_align (bool playhead_to_edit)
824 if (playhead_to_edit) {
826 session->request_locate (edit_cursor->current_frame);
829 edit_cursor->set_position (playhead_cursor->current_frame);
834 Editor::edit_cursor_backward ()
841 if (get_prefix (prefix, was_floating)) {
845 cnt = (nframes_t) floor (prefix * session->frame_rate ());
847 cnt = (nframes_t) prefix;
851 pos = edit_cursor->current_frame;
853 if ((nframes_t) pos < cnt) {
859 edit_cursor->set_position (pos);
863 Editor::edit_cursor_forward ()
870 if (get_prefix (prefix, was_floating)) {
874 cnt = (nframes_t) floor (prefix * session->frame_rate ());
876 cnt = (nframes_t) floor (prefix);
880 pos = edit_cursor->current_frame;
881 edit_cursor->set_position (pos+cnt);
885 Editor::goto_frame ()
891 if (get_prefix (prefix, was_floating)) {
896 frame = (nframes_t) floor (prefix * session->frame_rate());
898 frame = (nframes_t) floor (prefix);
901 session->request_locate (frame);
905 Editor::scroll_backward (float pages)
908 nframes_t one_page = (nframes_t) rint (canvas_width * frames_per_unit);
913 if (get_prefix (prefix, was_floating)) {
914 cnt = (nframes_t) floor (pages * one_page);
917 cnt = (nframes_t) floor (prefix * session->frame_rate());
919 cnt = (nframes_t) floor (prefix * one_page);
923 if (leftmost_frame < cnt) {
926 frame = leftmost_frame - cnt;
929 reposition_x_origin (frame);
933 Editor::scroll_forward (float pages)
936 nframes_t one_page = (nframes_t) rint (canvas_width * frames_per_unit);
941 if (get_prefix (prefix, was_floating)) {
942 cnt = (nframes_t) floor (pages * one_page);
945 cnt = (nframes_t) floor (prefix * session->frame_rate());
947 cnt = (nframes_t) floor (prefix * one_page);
951 if (max_frames - cnt < leftmost_frame) {
952 frame = max_frames - cnt;
954 frame = leftmost_frame + cnt;
957 reposition_x_origin (frame);
961 Editor::scroll_tracks_down ()
967 if (get_prefix (prefix, was_floating)) {
970 cnt = (int) floor (prefix);
973 double vert_value = vertical_adjustment.get_value() + (cnt *
974 vertical_adjustment.get_page_size());
975 if (vert_value > vertical_adjustment.get_upper() - canvas_height) {
976 vert_value = vertical_adjustment.get_upper() - canvas_height;
978 vertical_adjustment.set_value (vert_value);
982 Editor::scroll_tracks_up ()
988 if (get_prefix (prefix, was_floating)) {
991 cnt = (int) floor (prefix);
994 vertical_adjustment.set_value (vertical_adjustment.get_value() - (cnt * vertical_adjustment.get_page_size()));
998 Editor::scroll_tracks_down_line ()
1001 Gtk::Adjustment* adj = edit_vscrollbar.get_adjustment();
1002 double vert_value = adj->get_value() + 20;
1004 if (vert_value>adj->get_upper() - canvas_height) {
1005 vert_value = adj->get_upper() - canvas_height;
1007 adj->set_value (vert_value);
1011 Editor::scroll_tracks_up_line ()
1013 Gtk::Adjustment* adj = edit_vscrollbar.get_adjustment();
1014 adj->set_value (adj->get_value() - 20);
1020 Editor::temporal_zoom_step (bool coarser)
1022 ENSURE_GUI_THREAD (bind (mem_fun (*this, &Editor::temporal_zoom_step), coarser));
1026 nfpu = frames_per_unit;
1031 nfpu = max(1.0,(nfpu/1.61803399));
1034 temporal_zoom (nfpu);
1038 Editor::temporal_zoom (gdouble fpu)
1040 if (!session) return;
1042 nframes_t current_page = current_page_frames();
1043 nframes_t current_leftmost = leftmost_frame;
1044 nframes_t current_rightmost;
1045 nframes_t current_center;
1047 nframes_t leftmost_after_zoom = 0;
1052 new_page = (nframes_t) floor (canvas_width * nfpu);
1054 switch (zoom_focus) {
1056 leftmost_after_zoom = current_leftmost;
1059 case ZoomFocusRight:
1060 current_rightmost = leftmost_frame + current_page;
1061 if (current_rightmost > new_page) {
1062 leftmost_after_zoom = current_rightmost - new_page;
1064 leftmost_after_zoom = 0;
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);
1073 leftmost_after_zoom = 0;
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);
1082 leftmost_after_zoom = 0;
1087 /* try to keep the edit cursor in the center */
1088 if (edit_cursor->current_frame > new_page/2) {
1089 leftmost_after_zoom = edit_cursor->current_frame - (new_page/2);
1091 leftmost_after_zoom = 0;
1097 // leftmost_after_zoom = min (leftmost_after_zoom, session->current_end_frame());
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 ();
1104 reposition_and_zoom (leftmost_after_zoom, nfpu);
1108 Editor::temporal_zoom_selection ()
1110 if (!selection) return;
1112 if (selection->time.empty()) {
1116 nframes_t start = selection->time[clicked_selection].start;
1117 nframes_t end = selection->time[clicked_selection].end;
1119 temporal_zoom_by_frame (start, end, "zoom to selection");
1123 Editor::temporal_zoom_session ()
1125 ENSURE_GUI_THREAD (mem_fun (*this, &Editor::temporal_zoom_session));
1128 temporal_zoom_by_frame (session->current_start_frame(), session->current_end_frame(), "zoom to session");
1133 Editor::temporal_zoom_by_frame (nframes_t start, nframes_t end, const string & op)
1135 if (!session) return;
1137 if ((start == 0 && end == 0) || end < start) {
1141 nframes_t range = end - start;
1143 double new_fpu = (double)range / (double)canvas_width;
1146 // while (p2 < new_fpu) {
1151 nframes_t new_page = (nframes_t) floor (canvas_width * new_fpu);
1152 nframes_t middle = (nframes_t) floor( (double)start + ((double)range / 2.0f ));
1153 nframes_t new_leftmost = (nframes_t) floor( (double)middle - ((double)new_page/2.0f));
1155 if (new_leftmost > middle) new_leftmost = 0;
1157 // begin_reversible_command (op);
1158 // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit));
1159 // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu));
1160 // commit_reversible_command ();
1162 reposition_and_zoom (new_leftmost, new_fpu);
1166 Editor::temporal_zoom_to_frame (bool coarser, nframes_t frame)
1168 if (!session) return;
1170 double range_before = frame - leftmost_frame;
1173 new_fpu = frames_per_unit;
1176 new_fpu *= 1.61803399;
1177 range_before *= 1.61803399;
1179 new_fpu = max(1.0,(new_fpu/1.61803399));
1180 range_before /= 1.61803399;
1183 if (new_fpu == frames_per_unit) return;
1185 nframes_t new_leftmost = frame - (nframes_t)range_before;
1187 if (new_leftmost > frame) new_leftmost = 0;
1189 // begin_reversible_command (_("zoom to frame"));
1190 // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit));
1191 // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu));
1192 // commit_reversible_command ();
1194 reposition_and_zoom (new_leftmost, new_fpu);
1198 Editor::add_location_from_selection ()
1200 if (selection->time.empty()) {
1204 if (session == 0 || clicked_trackview == 0) {
1208 nframes_t start = selection->time[clicked_selection].start;
1209 nframes_t end = selection->time[clicked_selection].end;
1211 Location *location = new Location (start, end, "selection");
1213 session->begin_reversible_command (_("add marker"));
1214 XMLNode &before = session->locations()->get_state();
1215 session->locations()->add (location, true);
1216 XMLNode &after = session->locations()->get_state();
1217 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1218 session->commit_reversible_command ();
1222 Editor::add_location_from_playhead_cursor ()
1224 nframes_t where = session->audible_frame();
1226 Location *location = new Location (where, where, "mark", Location::IsMark);
1227 session->begin_reversible_command (_("add marker"));
1228 XMLNode &before = session->locations()->get_state();
1229 session->locations()->add (location, true);
1230 XMLNode &after = session->locations()->get_state();
1231 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1232 session->commit_reversible_command ();
1236 Editor::add_location_from_audio_region ()
1238 if (selection->regions.empty()) {
1242 RegionView* rv = *(selection->regions.begin());
1243 boost::shared_ptr<Region> region = rv->region();
1245 Location *location = new Location (region->position(), region->last_frame(), region->name());
1246 session->begin_reversible_command (_("add marker"));
1247 XMLNode &before = session->locations()->get_state();
1248 session->locations()->add (location, true);
1249 XMLNode &after = session->locations()->get_state();
1250 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1251 session->commit_reversible_command ();
1255 Editor::select_all_in_track (Selection::Operation op)
1257 list<Selectable *> touched;
1259 if (!clicked_trackview) {
1263 clicked_trackview->get_selectables (0, max_frames, 0, DBL_MAX, touched);
1266 case Selection::Toggle:
1267 selection->add (touched);
1269 case Selection::Set:
1270 selection->set (touched);
1272 case Selection::Extend:
1273 /* not defined yet */
1275 case Selection::Add:
1276 selection->add (touched);
1282 Editor::select_all (Selection::Operation op)
1284 list<Selectable *> touched;
1286 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1287 if ((*iter)->hidden()) {
1290 (*iter)->get_selectables (0, max_frames, 0, DBL_MAX, touched);
1292 begin_reversible_command (_("select all"));
1294 case Selection::Add:
1295 case Selection::Toggle:
1296 selection->add (touched);
1298 case Selection::Set:
1299 selection->set (touched);
1301 case Selection::Extend:
1302 /* not defined yet */
1305 commit_reversible_command ();
1309 Editor::invert_selection_in_track ()
1311 list<Selectable *> touched;
1313 if (!clicked_trackview) {
1317 clicked_trackview->get_inverted_selectables (*selection, touched);
1318 selection->set (touched);
1322 Editor::invert_selection ()
1324 list<Selectable *> touched;
1326 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1327 if ((*iter)->hidden()) {
1330 (*iter)->get_inverted_selectables (*selection, touched);
1333 selection->set (touched);
1337 Editor::select_all_within (nframes_t start, nframes_t end, double top, double bot, Selection::Operation op)
1339 list<Selectable *> touched;
1341 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1342 if ((*iter)->hidden()) {
1345 (*iter)->get_selectables (start, end, top, bot, touched);
1348 cerr << "select all within found " << touched.size() << endl;
1350 begin_reversible_command (_("select all within"));
1352 case Selection::Add:
1353 case Selection::Toggle:
1355 selection->add (touched);
1357 case Selection::Set:
1359 selection->set (touched);
1361 case Selection::Extend:
1363 /* not defined yet */
1367 cerr << "selection now has " << selection->points.size() << endl;
1369 commit_reversible_command ();
1370 return !touched.empty();
1374 Editor::set_selection_from_audio_region ()
1376 if (selection->regions.empty()) {
1380 RegionView* rv = *(selection->regions.begin());
1381 boost::shared_ptr<Region> region = rv->region();
1383 begin_reversible_command (_("set selection from region"));
1384 selection->set (0, region->position(), region->last_frame());
1385 commit_reversible_command ();
1387 set_mouse_mode (Editing::MouseRange, false);
1391 Editor::set_selection_from_punch()
1395 if ((location = session->locations()->auto_punch_location()) == 0) {
1399 set_selection_from_range (*location);
1403 Editor::set_selection_from_loop()
1407 if ((location = session->locations()->auto_loop_location()) == 0) {
1410 set_selection_from_range (*location);
1414 Editor::set_selection_from_range (Location& loc)
1416 begin_reversible_command (_("set selection from range"));
1417 selection->set (0, loc.start(), loc.end());
1418 commit_reversible_command ();
1420 set_mouse_mode (Editing::MouseRange, false);
1424 Editor::select_all_selectables_using_time_selection ()
1426 list<Selectable *> touched;
1428 if (selection->time.empty()) {
1432 nframes_t start = selection->time[clicked_selection].start;
1433 nframes_t end = selection->time[clicked_selection].end;
1435 if (end - start < 1) {
1439 for (TrackViewList::iterator iter = selection->tracks.begin(); iter != selection->tracks.end(); ++iter) {
1440 if ((*iter)->hidden()) {
1443 (*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
1446 begin_reversible_command (_("select all from range"));
1447 selection->set (touched);
1448 commit_reversible_command ();
1453 Editor::select_all_selectables_using_punch()
1455 Location* location = session->locations()->auto_punch_location();
1456 list<Selectable *> touched;
1458 if (location == 0 || (location->end() - location->start() <= 1)) {
1462 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1463 if ((*iter)->hidden()) {
1466 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1468 begin_reversible_command (_("select all from punch"));
1469 selection->set (touched);
1470 commit_reversible_command ();
1475 Editor::select_all_selectables_using_loop()
1477 Location* location = session->locations()->auto_loop_location();
1478 list<Selectable *> touched;
1480 if (location == 0 || (location->end() - location->start() <= 1)) {
1484 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1485 if ((*iter)->hidden()) {
1488 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1490 begin_reversible_command (_("select all from loop"));
1491 selection->set (touched);
1492 commit_reversible_command ();
1497 Editor::select_all_selectables_using_cursor (Cursor *cursor, bool after)
1501 list<Selectable *> touched;
1504 begin_reversible_command (_("select all after cursor"));
1505 start = cursor->current_frame ;
1506 end = session->current_end_frame();
1508 if (cursor->current_frame > 0) {
1509 begin_reversible_command (_("select all before cursor"));
1511 end = cursor->current_frame - 1;
1517 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1518 if ((*iter)->hidden()) {
1521 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1523 selection->set (touched);
1524 commit_reversible_command ();
1528 Editor::select_all_selectables_between_cursors (Cursor *cursor, Cursor *other_cursor)
1532 list<Selectable *> touched;
1533 bool other_cursor_is_first = cursor->current_frame > other_cursor->current_frame;
1535 if (cursor->current_frame == other_cursor->current_frame) {
1539 begin_reversible_command (_("select all between cursors"));
1540 if (other_cursor_is_first) {
1541 start = other_cursor->current_frame;
1542 end = cursor->current_frame - 1;
1545 start = cursor->current_frame;
1546 end = other_cursor->current_frame - 1;
1549 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1550 if ((*iter)->hidden()) {
1553 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1555 selection->set (touched);
1556 commit_reversible_command ();
1560 Editor::amplitude_zoom_step (bool in)
1574 #ifdef FIX_FOR_CANVAS
1575 /* XXX DO SOMETHING */
1584 Editor::delete_sample_forward ()
1589 Editor::delete_sample_backward ()
1594 Editor::delete_screen ()
1601 Editor::search_backwards ()
1607 Editor::search_forwards ()
1615 Editor::jump_forward_to_mark ()
1621 Location *location = session->locations()->first_location_after (playhead_cursor->current_frame);
1624 session->request_locate (location->start(), session->transport_rolling());
1626 session->request_locate (session->current_end_frame());
1631 Editor::jump_backward_to_mark ()
1637 Location *location = session->locations()->first_location_before (playhead_cursor->current_frame);
1640 session->request_locate (location->start(), session->transport_rolling());
1642 session->goto_start ();
1653 if (get_prefix (prefix, was_floating)) {
1654 pos = session->audible_frame ();
1657 pos = (nframes_t) floor (prefix * session->frame_rate ());
1659 pos = (nframes_t) floor (prefix);
1663 session->locations()->add (new Location (pos, 0, "mark", Location::IsMark), true);
1667 Editor::clear_markers ()
1670 session->begin_reversible_command (_("clear markers"));
1671 XMLNode &before = session->locations()->get_state();
1672 session->locations()->clear_markers ();
1673 XMLNode &after = session->locations()->get_state();
1674 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1675 session->commit_reversible_command ();
1680 Editor::clear_ranges ()
1683 session->begin_reversible_command (_("clear ranges"));
1684 XMLNode &before = session->locations()->get_state();
1686 Location * looploc = session->locations()->auto_loop_location();
1687 Location * punchloc = session->locations()->auto_punch_location();
1689 session->locations()->clear_ranges ();
1691 if (looploc) session->locations()->add (looploc);
1692 if (punchloc) session->locations()->add (punchloc);
1694 XMLNode &after = session->locations()->get_state();
1695 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1696 session->commit_reversible_command ();
1701 Editor::clear_locations ()
1703 session->begin_reversible_command (_("clear locations"));
1704 XMLNode &before = session->locations()->get_state();
1705 session->locations()->clear ();
1706 XMLNode &after = session->locations()->get_state();
1707 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1708 session->commit_reversible_command ();
1709 session->locations()->clear ();
1712 /* INSERT/REPLACE */
1715 Editor::insert_region_list_drag (boost::shared_ptr<AudioRegion> region, int x, int y)
1721 AudioTimeAxisView *atv = 0;
1724 track_canvas.window_to_world (x, y, wx, wy);
1725 wx += horizontal_adjustment.get_value();
1726 wy += vertical_adjustment.get_value();
1729 event.type = GDK_BUTTON_RELEASE;
1730 event.button.x = wx;
1731 event.button.y = wy;
1733 where = event_frame (&event, &cx, &cy);
1735 if (where < leftmost_frame || where > leftmost_frame + current_page_frames()) {
1736 /* clearly outside canvas area */
1740 if ((tv = trackview_by_y_position (cy)) == 0) {
1744 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) == 0) {
1748 if ((playlist = atv->playlist()) == 0) {
1754 begin_reversible_command (_("insert dragged region"));
1755 XMLNode &before = playlist->get_state();
1756 playlist->add_region (RegionFactory::create (region), where, 1.0);
1757 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
1758 commit_reversible_command ();
1762 Editor::insert_region_list_selection (float times)
1764 RouteTimeAxisView *tv = 0;
1767 if (clicked_audio_trackview != 0) {
1768 tv = clicked_audio_trackview;
1769 } else if (!selection->tracks.empty()) {
1770 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
1777 if ((playlist = tv->playlist()) == 0) {
1781 Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
1783 if (selected->count_selected_rows() != 1) {
1787 TreeView::Selection::ListHandle_Path rows = selected->get_selected_rows ();
1789 /* only one row selected, so rows.begin() is it */
1793 if ((iter = region_list_model->get_iter (*rows.begin()))) {
1795 boost::shared_ptr<Region> region = (*iter)[region_list_columns.region];
1797 begin_reversible_command (_("insert region"));
1798 XMLNode &before = playlist->get_state();
1799 playlist->add_region ((RegionFactory::create (region)), edit_cursor->current_frame, times);
1800 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
1801 commit_reversible_command ();
1805 /* BUILT-IN EFFECTS */
1808 Editor::reverse_selection ()
1813 /* GAIN ENVELOPE EDITING */
1816 Editor::edit_envelope ()
1823 Editor::toggle_playback (bool with_abort)
1829 switch (Config->get_slave_source()) {
1834 /* transport controlled by the master */
1838 if (session->is_auditioning()) {
1839 session->cancel_audition ();
1843 if (session->transport_rolling()) {
1844 session->request_stop (with_abort);
1845 if (session->get_play_loop()) {
1846 session->request_play_loop (false);
1849 session->request_transport_speed (1.0f);
1854 Editor::play_from_start ()
1856 session->request_locate (session->current_start_frame(), true);
1860 Editor::play_from_edit_cursor ()
1862 session->request_locate (edit_cursor->current_frame, true);
1866 Editor::play_selection ()
1868 if (selection->time.empty()) {
1872 session->request_play_range (true);
1876 Editor::play_selected_region ()
1878 if (!selection->regions.empty()) {
1879 RegionView *rv = *(selection->regions.begin());
1881 session->request_bounded_roll (rv->region()->position(), rv->region()->last_frame());
1886 Editor::loop_selected_region ()
1888 if (!selection->regions.empty()) {
1889 RegionView *rv = *(selection->regions.begin());
1892 if ((tll = transport_loop_location()) != 0) {
1894 tll->set (rv->region()->position(), rv->region()->last_frame());
1896 // enable looping, reposition and start rolling
1898 session->request_play_loop (true);
1899 session->request_locate (tll->start(), false);
1900 session->request_transport_speed (1.0f);
1906 Editor::play_location (Location& location)
1908 if (location.start() <= location.end()) {
1912 session->request_bounded_roll (location.start(), location.end());
1916 Editor::loop_location (Location& location)
1918 if (location.start() <= location.end()) {
1924 if ((tll = transport_loop_location()) != 0) {
1925 tll->set (location.start(), location.end());
1927 // enable looping, reposition and start rolling
1928 session->request_play_loop (true);
1929 session->request_locate (tll->start(), true);
1934 Editor::toggle_region_mute ()
1936 if (clicked_regionview) {
1937 clicked_regionview->region()->set_muted (!clicked_regionview->region()->muted());
1938 } else if (!selection->regions.empty()) {
1939 bool yn = ! (*selection->regions.begin())->region()->muted();
1940 selection->foreach_region (&Region::set_muted, yn);
1945 Editor::toggle_region_opaque ()
1947 if (clicked_regionview) {
1948 clicked_regionview->region()->set_opaque (!clicked_regionview->region()->opaque());
1949 } else if (!selection->regions.empty()) {
1950 bool yn = ! (*selection->regions.begin())->region()->opaque();
1951 selection->foreach_region (&Region::set_opaque, yn);
1956 Editor::raise_region ()
1958 selection->foreach_region (&Region::raise);
1962 Editor::raise_region_to_top ()
1964 selection->foreach_region (&Region::raise_to_top);
1968 Editor::lower_region ()
1970 selection->foreach_region (&Region::lower);
1974 Editor::lower_region_to_bottom ()
1976 selection->foreach_region (&Region::lower_to_bottom);
1980 Editor::edit_region ()
1982 if (clicked_regionview == 0) {
1986 clicked_regionview->show_region_editor ();
1990 Editor::rename_region ()
1994 Button ok_button (_("OK"));
1995 Button cancel_button (_("Cancel"));
1997 if (selection->regions.empty()) {
2001 dialog.set_title (_("ardour: rename region"));
2002 dialog.set_name ("RegionRenameWindow");
2003 dialog.set_size_request (300, -1);
2004 dialog.set_position (Gtk::WIN_POS_MOUSE);
2005 dialog.set_modal (true);
2007 dialog.get_vbox()->set_border_width (10);
2008 dialog.get_vbox()->pack_start (entry);
2009 dialog.get_action_area()->pack_start (ok_button);
2010 dialog.get_action_area()->pack_start (cancel_button);
2012 entry.set_name ("RegionNameDisplay");
2013 ok_button.set_name ("EditorGTKButton");
2014 cancel_button.set_name ("EditorGTKButton");
2016 region_renamed = false;
2018 entry.signal_activate().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
2019 ok_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
2020 cancel_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::rename_region_finished), false));
2027 if (region_renamed) {
2028 (*selection->regions.begin())->region()->set_name (entry.get_text());
2029 redisplay_regions ();
2034 Editor::rename_region_finished (bool status)
2037 region_renamed = status;
2042 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2044 if (session->is_auditioning()) {
2045 session->cancel_audition ();
2048 // note: some potential for creativity here, because region doesn't
2049 // have to belong to the playlist that Route is handling
2051 // bool was_soloed = route.soloed();
2053 route.set_solo (true, this);
2055 session->request_bounded_roll (region->position(), region->position() + region->length());
2057 /* XXX how to unset the solo state ? */
2061 Editor::audition_selected_region ()
2063 if (!selection->regions.empty()) {
2064 RegionView* rv = *(selection->regions.begin());
2065 session->audition_region (rv->region());
2070 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2072 session->audition_region (region);
2076 Editor::build_interthread_progress_window ()
2078 interthread_progress_window = new ArdourDialog (X_("interthread progress"), true);
2080 interthread_progress_bar.set_orientation (Gtk::PROGRESS_LEFT_TO_RIGHT);
2082 interthread_progress_window->get_vbox()->pack_start (interthread_progress_label, false, false);
2083 interthread_progress_window->get_vbox()->pack_start (interthread_progress_bar,false, false);
2085 // GTK2FIX: this button needs a modifiable label
2087 Button* b = interthread_progress_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
2088 b->signal_clicked().connect (mem_fun(*this, &Editor::interthread_cancel_clicked));
2090 interthread_cancel_button.add (interthread_cancel_label);
2092 interthread_progress_window->set_default_size (200, 100);
2096 Editor::interthread_cancel_clicked ()
2098 if (current_interthread_info) {
2099 current_interthread_info->cancel = true;
2104 Editor::region_from_selection ()
2106 if (clicked_trackview == 0) {
2110 if (selection->time.empty()) {
2114 nframes_t start = selection->time[clicked_selection].start;
2115 nframes_t end = selection->time[clicked_selection].end;
2117 nframes_t selection_cnt = end - start + 1;
2119 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2120 boost::shared_ptr<AudioRegion> current;
2121 boost::shared_ptr<Region> current_r;
2124 nframes_t internal_start;
2127 if ((pl = (*i)->playlist()) == 0) {
2131 if ((current_r = pl->top_region_at (start)) == 0) {
2135 current = boost::dynamic_pointer_cast<AudioRegion> (current_r);
2136 // FIXME: audio only
2138 internal_start = start - current->position();
2139 session->region_name (new_name, current->name(), true);
2140 boost::shared_ptr<Region> region (RegionFactory::create (current, internal_start, selection_cnt, new_name));
2146 Editor::create_region_from_selection (vector<boost::shared_ptr<AudioRegion> >& new_regions)
2148 if (selection->time.empty() || selection->tracks.empty()) {
2152 nframes_t start = selection->time[clicked_selection].start;
2153 nframes_t end = selection->time[clicked_selection].end;
2155 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2157 boost::shared_ptr<AudioRegion> current;
2158 boost::shared_ptr<Region> current_r;
2160 nframes_t internal_start;
2163 if ((playlist = (*i)->playlist()) == 0) {
2167 if ((current_r = playlist->top_region_at(start)) == 0) {
2171 if ((current = boost::dynamic_pointer_cast<AudioRegion>(current_r)) == 0) {
2175 internal_start = start - current->position();
2176 session->region_name (new_name, current->name(), true);
2178 new_regions.push_back (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (current, internal_start, end - start + 1, new_name)));
2183 Editor::split_multichannel_region ()
2185 vector<AudioRegion*> v;
2187 AudioRegionView* clicked_arv = dynamic_cast<AudioRegionView*>(clicked_regionview);
2189 if (!clicked_arv || clicked_arv->audio_region()->n_channels() < 2) {
2193 clicked_arv->audio_region()->separate_by_channel (*session, v);
2195 /* nothing else to do, really */
2199 Editor::new_region_from_selection ()
2201 region_from_selection ();
2202 cancel_selection ();
2206 Editor::separate_region_from_selection ()
2208 bool doing_undo = false;
2210 if (selection->time.empty()) {
2216 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2218 AudioTimeAxisView* atv;
2220 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2222 if (atv->is_audio_track()) {
2224 if ((playlist = atv->playlist()) != 0) {
2226 begin_reversible_command (_("separate"));
2231 before = &(playlist->get_state());
2233 /* XXX need to consider musical time selections here at some point */
2235 double speed = atv->get_diskstream()->speed();
2237 for (list<AudioRange>::iterator t = selection->time.begin(); t != selection->time.end(); ++t) {
2238 playlist->partition ((nframes_t)((*t).start * speed), (nframes_t)((*t).end * speed), true);
2242 session->add_command(new MementoCommand<Playlist>(*playlist, before, &playlist->get_state()));
2248 if (doing_undo) commit_reversible_command ();
2252 Editor::separate_regions_using_location (Location& loc)
2254 bool doing_undo = false;
2256 if (loc.is_mark()) {
2262 /* XXX i'm unsure as to whether this should operate on selected tracks only
2263 or the entire enchillada. uncomment the below line to correct the behaviour
2264 (currently set for all tracks)
2267 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
2268 //for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2270 AudioTimeAxisView* atv;
2272 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2274 if (atv->is_audio_track()) {
2276 if ((playlist = atv->playlist()) != 0) {
2279 begin_reversible_command (_("separate"));
2283 before = &(playlist->get_state());
2286 /* XXX need to consider musical time selections here at some point */
2288 double speed = atv->get_diskstream()->speed();
2291 playlist->partition ((nframes_t)(loc.start() * speed), (nframes_t)(loc.end() * speed), true);
2293 session->add_command(new MementoCommand<Playlist>(*playlist, before, &playlist->get_state()));
2299 if (doing_undo) commit_reversible_command ();
2303 Editor::crop_region_to_selection ()
2305 if (selection->time.empty()) {
2309 vector<Playlist*> playlists;
2312 if (clicked_trackview != 0) {
2314 if ((playlist = clicked_trackview->playlist()) == 0) {
2318 playlists.push_back (playlist);
2322 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2324 AudioTimeAxisView* atv;
2326 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2328 if (atv->is_audio_track()) {
2330 if ((playlist = atv->playlist()) != 0) {
2331 playlists.push_back (playlist);
2338 if (!playlists.empty()) {
2344 begin_reversible_command (_("trim to selection"));
2346 for (vector<Playlist*>::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2348 boost::shared_ptr<Region> region;
2350 start = selection->time.start();
2352 if ((region = (*i)->top_region_at(start)) == 0) {
2356 /* now adjust lengths to that we do the right thing
2357 if the selection extends beyond the region
2360 start = max (start, region->position());
2361 end = min (selection->time.end_frame(), start + region->length() - 1);
2362 cnt = end - start + 1;
2364 XMLNode &before = (*i)->get_state();
2365 region->trim_to (start, cnt, this);
2366 XMLNode &after = (*i)->get_state();
2367 session->add_command (new MementoCommand<Playlist>(*(*i), &before, &after));
2370 commit_reversible_command ();
2375 Editor::region_fill_track ()
2379 if (!session || selection->regions.empty()) {
2383 end = session->current_end_frame ();
2385 begin_reversible_command (_("region fill"));
2387 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2389 boost::shared_ptr<Region> region ((*i)->region());
2392 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(region);
2396 Playlist* pl = region->playlist();
2398 if (end <= region->last_frame()) {
2402 double times = (double) (end - region->last_frame()) / (double) region->length();
2408 XMLNode &before = pl->get_state();
2409 pl->add_region (RegionFactory::create (ar), ar->last_frame(), times);
2410 session->add_command (new MementoCommand<Playlist>(*pl, &before, &pl->get_state()));
2413 commit_reversible_command ();
2417 Editor::region_fill_selection ()
2419 if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2423 if (selection->time.empty()) {
2428 Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
2430 if (selected->count_selected_rows() != 1) {
2434 TreeModel::iterator i = region_list_display.get_selection()->get_selected();
2435 boost::shared_ptr<Region> region = (*i)[region_list_columns.region];
2437 nframes_t start = selection->time[clicked_selection].start;
2438 nframes_t end = selection->time[clicked_selection].end;
2442 if (selection->tracks.empty()) {
2446 nframes_t selection_length = end - start;
2447 float times = (float)selection_length / region->length();
2449 begin_reversible_command (_("fill selection"));
2451 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2453 if ((playlist = (*i)->playlist()) == 0) {
2457 XMLNode &before = playlist->get_state();
2458 playlist->add_region (RegionFactory::create (region), start, times);
2459 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
2462 commit_reversible_command ();
2466 Editor::set_a_regions_sync_position (boost::shared_ptr<Region> region, nframes_t position)
2469 if (!region->covers (position)) {
2470 error << _("Programming error. that region doesn't cover that position") << __FILE__ << " +" << __LINE__ << endmsg;
2473 begin_reversible_command (_("set region sync position"));
2474 XMLNode &before = region->playlist()->get_state();
2475 region->set_sync_position (position);
2476 XMLNode &after = region->playlist()->get_state();
2477 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2478 commit_reversible_command ();
2482 Editor::set_region_sync_from_edit_cursor ()
2484 if (clicked_regionview == 0) {
2488 if (!clicked_regionview->region()->covers (edit_cursor->current_frame)) {
2489 error << _("Place the edit cursor at the desired sync point") << endmsg;
2493 boost::shared_ptr<Region> region (clicked_regionview->region());
2494 begin_reversible_command (_("set sync from edit cursor"));
2495 XMLNode &before = region->playlist()->get_state();
2496 region->set_sync_position (edit_cursor->current_frame);
2497 XMLNode &after = region->playlist()->get_state();
2498 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2499 commit_reversible_command ();
2503 Editor::remove_region_sync ()
2505 if (clicked_regionview) {
2506 boost::shared_ptr<Region> region (clicked_regionview->region());
2507 begin_reversible_command (_("remove sync"));
2508 XMLNode &before = region->playlist()->get_state();
2509 region->clear_sync_position ();
2510 XMLNode &after = region->playlist()->get_state();
2511 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2512 commit_reversible_command ();
2517 Editor::naturalize ()
2519 if (selection->regions.empty()) {
2522 begin_reversible_command (_("naturalize"));
2523 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2524 XMLNode &before = (*i)->region()->get_state();
2525 (*i)->region()->move_to_natural_position (this);
2526 XMLNode &after = (*i)->region()->get_state();
2527 session->add_command (new MementoCommand<Region>(*((*i)->region().get()), &before, &after));
2529 commit_reversible_command ();
2533 Editor::align (RegionPoint what)
2535 align_selection (what, edit_cursor->current_frame);
2539 Editor::align_relative (RegionPoint what)
2541 align_selection_relative (what, edit_cursor->current_frame);
2544 struct RegionSortByTime {
2545 bool operator() (const AudioRegionView* a, const AudioRegionView* b) {
2546 return a->region()->position() < b->region()->position();
2551 Editor::align_selection_relative (RegionPoint point, nframes_t position)
2553 if (selection->regions.empty()) {
2561 list<RegionView*> sorted;
2562 selection->regions.by_position (sorted);
2563 boost::shared_ptr<Region> r ((*sorted.begin())->region());
2567 pos = r->first_frame ();
2571 pos = r->last_frame();
2575 pos = r->adjust_to_sync (r->first_frame());
2579 if (pos > position) {
2580 distance = pos - position;
2583 distance = position - pos;
2587 begin_reversible_command (_("align selection (relative)"));
2589 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2591 boost::shared_ptr<Region> region ((*i)->region());
2593 XMLNode &before = region->playlist()->get_state();
2596 region->set_position (region->position() + distance, this);
2598 region->set_position (region->position() - distance, this);
2601 XMLNode &after = region->playlist()->get_state();
2602 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2606 commit_reversible_command ();
2610 Editor::align_selection (RegionPoint point, nframes_t position)
2612 if (selection->regions.empty()) {
2616 begin_reversible_command (_("align selection"));
2618 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2619 align_region_internal ((*i)->region(), point, position);
2622 commit_reversible_command ();
2626 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, nframes_t position)
2628 begin_reversible_command (_("align region"));
2629 align_region_internal (region, point, position);
2630 commit_reversible_command ();
2634 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, nframes_t position)
2636 XMLNode &before = region->playlist()->get_state();
2640 region->set_position (region->adjust_to_sync (position), this);
2644 if (position > region->length()) {
2645 region->set_position (position - region->length(), this);
2650 region->set_position (position, this);
2654 XMLNode &after = region->playlist()->get_state();
2655 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2659 Editor::trim_region_to_edit_cursor ()
2661 if (clicked_regionview == 0) {
2665 boost::shared_ptr<Region> region (clicked_regionview->region());
2668 AudioTimeAxisView *atav;
2670 if ( clicked_trackview != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(clicked_trackview)) != 0 ) {
2671 if (atav->get_diskstream() != 0) {
2672 speed = atav->get_diskstream()->speed();
2676 begin_reversible_command (_("trim to edit"));
2677 XMLNode &before = region->playlist()->get_state();
2678 region->trim_end( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
2679 XMLNode &after = region->playlist()->get_state();
2680 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2681 commit_reversible_command ();
2685 Editor::trim_region_from_edit_cursor ()
2687 if (clicked_regionview == 0) {
2691 boost::shared_ptr<Region> region (clicked_regionview->region());
2694 AudioTimeAxisView *atav;
2696 if ( clicked_trackview != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(clicked_trackview)) != 0 ) {
2697 if (atav->get_diskstream() != 0) {
2698 speed = atav->get_diskstream()->speed();
2702 begin_reversible_command (_("trim to edit"));
2703 XMLNode &before = region->playlist()->get_state();
2704 region->trim_front ( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
2705 XMLNode &after = region->playlist()->get_state();
2706 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2707 commit_reversible_command ();
2711 Editor::unfreeze_route ()
2713 if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2717 clicked_audio_trackview->audio_track()->unfreeze ();
2721 Editor::_freeze_thread (void* arg)
2723 PBD::ThreadCreated (pthread_self(), X_("Freeze"));
2724 return static_cast<Editor*>(arg)->freeze_thread ();
2728 Editor::freeze_thread ()
2730 clicked_audio_trackview->audio_track()->freeze (*current_interthread_info);
2735 Editor::freeze_progress_timeout (void *arg)
2737 interthread_progress_bar.set_fraction (current_interthread_info->progress/100);
2738 return !(current_interthread_info->done || current_interthread_info->cancel);
2742 Editor::freeze_route ()
2744 if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2748 InterThreadInfo itt;
2750 if (interthread_progress_window == 0) {
2751 build_interthread_progress_window ();
2754 interthread_progress_window->set_title (_("ardour: freeze"));
2755 interthread_progress_window->set_position (Gtk::WIN_POS_MOUSE);
2756 interthread_progress_window->show_all ();
2757 interthread_progress_bar.set_fraction (0.0f);
2758 interthread_progress_label.set_text ("");
2759 interthread_cancel_label.set_text (_("Cancel Freeze"));
2760 current_interthread_info = &itt;
2762 interthread_progress_connection =
2763 Glib::signal_timeout().connect (bind (mem_fun(*this, &Editor::freeze_progress_timeout), (gpointer) 0), 100);
2767 itt.progress = 0.0f;
2769 pthread_create (&itt.thread, 0, _freeze_thread, this);
2771 track_canvas.get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
2773 while (!itt.done && !itt.cancel) {
2774 gtk_main_iteration ();
2777 interthread_progress_connection.disconnect ();
2778 interthread_progress_window->hide_all ();
2779 current_interthread_info = 0;
2780 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
2784 Editor::bounce_range_selection ()
2786 if (selection->time.empty()) {
2790 TrackViewList *views = get_valid_views (selection->time.track, selection->time.group);
2792 nframes_t start = selection->time[clicked_selection].start;
2793 nframes_t end = selection->time[clicked_selection].end;
2794 nframes_t cnt = end - start + 1;
2796 begin_reversible_command (_("bounce range"));
2798 for (TrackViewList::iterator i = views->begin(); i != views->end(); ++i) {
2800 AudioTimeAxisView* atv;
2802 if ((atv = dynamic_cast<AudioTimeAxisView*> (*i)) == 0) {
2808 if ((playlist = atv->playlist()) == 0) {
2812 InterThreadInfo itt;
2816 itt.progress = false;
2818 XMLNode &before = playlist->get_state();
2819 atv->audio_track()->bounce_range (start, cnt, itt);
2820 XMLNode &after = playlist->get_state();
2821 session->add_command (new MementoCommand<Playlist> (*playlist, &before, &after));
2824 commit_reversible_command ();
2842 Editor::cut_copy (CutCopyOp op)
2844 /* only cancel selection if cut/copy is successful.*/
2856 opname = _("clear");
2860 cut_buffer->clear ();
2862 switch (current_mouse_mode()) {
2864 if (!selection->regions.empty() || !selection->points.empty()) {
2866 begin_reversible_command (opname + _(" objects"));
2868 if (!selection->regions.empty()) {
2870 cut_copy_regions (op);
2873 selection->clear_regions ();
2877 if (!selection->points.empty()) {
2878 cut_copy_points (op);
2881 selection->clear_points ();
2885 commit_reversible_command ();
2890 if (!selection->time.empty()) {
2892 begin_reversible_command (opname + _(" range"));
2893 cut_copy_ranges (op);
2894 commit_reversible_command ();
2897 selection->clear_time ();
2909 Editor::cut_copy_points (CutCopyOp op)
2911 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
2913 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
2916 atv->cut_copy_clear_objects (selection->points, op);
2921 struct PlaylistState {
2926 struct lt_playlist {
2927 bool operator () (const PlaylistState& a, const PlaylistState& b) {
2928 return a.playlist < b.playlist;
2933 Editor::cut_copy_regions (CutCopyOp op)
2935 typedef std::map<AudioPlaylist*,AudioPlaylist*> PlaylistMapping;
2936 PlaylistMapping pmap;
2937 nframes_t first_position = max_frames;
2939 set<PlaylistState, lt_playlist> freezelist;
2940 pair<set<PlaylistState, lt_playlist>::iterator,bool> insert_result;
2942 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
2943 first_position = min ((*x)->region()->position(), first_position);
2945 if (op == Cut || op == Clear) {
2946 AudioPlaylist *pl = dynamic_cast<AudioPlaylist*>((*x)->region()->playlist());
2949 PlaylistState before;
2950 before.playlist = pl;
2951 before.before = &pl->get_state();
2953 insert_result = freezelist.insert (before);
2955 if (insert_result.second) {
2962 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ) {
2964 AudioPlaylist *pl = dynamic_cast<AudioPlaylist*>((*x)->region()->playlist());
2966 RegionSelection::iterator tmp;
2973 PlaylistMapping::iterator pi = pmap.find (pl);
2975 if (pi == pmap.end()) {
2976 npl = new AudioPlaylist (*session, "cutlist", true);
2984 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>((*x)->region());
2989 npl->add_region (RegionFactory::create (ar), (*x)->region()->position() - first_position);
2990 pl->remove_region (((*x)->region()));
2996 npl->add_region (RegionFactory::create (ar), (*x)->region()->position() - first_position);
3000 pl->remove_region (((*x)->region()));
3008 list<Playlist*> foo;
3010 for (PlaylistMapping::iterator i = pmap.begin(); i != pmap.end(); ++i) {
3011 foo.push_back (i->second);
3015 cut_buffer->set (foo);
3018 for (set<PlaylistState, lt_playlist>::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
3019 (*pl).playlist->thaw ();
3020 session->add_command (new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3025 Editor::cut_copy_ranges (CutCopyOp op)
3027 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3028 (*i)->cut_copy_clear (*selection, op);
3033 Editor::paste (float times)
3035 paste_internal (edit_cursor->current_frame, times);
3039 Editor::mouse_paste ()
3044 track_canvas.get_pointer (x, y);
3045 track_canvas.window_to_world (x, y, wx, wy);
3046 wx += horizontal_adjustment.get_value();
3047 wy += vertical_adjustment.get_value();
3050 event.type = GDK_BUTTON_RELEASE;
3051 event.button.x = wx;
3052 event.button.y = wy;
3054 nframes_t where = event_frame (&event, 0, 0);
3056 paste_internal (where, 1);
3060 Editor::paste_internal (nframes_t position, float times)
3062 bool commit = false;
3064 if (cut_buffer->empty() || selection->tracks.empty()) {
3068 if (position == max_frames) {
3069 position = edit_cursor->current_frame;
3072 begin_reversible_command (_("paste"));
3074 TrackSelection::iterator i;
3077 for (nth = 0, i = selection->tracks.begin(); i != selection->tracks.end(); ++i, ++nth) {
3079 /* undo/redo is handled by individual tracks */
3081 if ((*i)->paste (position, times, *cut_buffer, nth)) {
3087 commit_reversible_command ();
3092 Editor::paste_named_selection (float times)
3094 TrackSelection::iterator t;
3096 Glib::RefPtr<TreeSelection> selected = named_selection_display.get_selection();
3098 if (selected->count_selected_rows() != 1 || selection->tracks.empty()) {
3102 TreeModel::iterator i = selected->get_selected();
3103 NamedSelection* ns = (*i)[named_selection_columns.selection];
3105 list<Playlist*>::iterator chunk;
3106 list<Playlist*>::iterator tmp;
3108 chunk = ns->playlists.begin();
3110 begin_reversible_command (_("paste chunk"));
3112 for (t = selection->tracks.begin(); t != selection->tracks.end(); ++t) {
3114 AudioTimeAxisView* atv;
3118 if ((atv = dynamic_cast<AudioTimeAxisView*> (*t)) == 0) {
3122 if ((pl = atv->playlist()) == 0) {
3126 if ((apl = dynamic_cast<AudioPlaylist*> (pl)) == 0) {
3133 XMLNode &before = apl->get_state();
3134 apl->paste (**chunk, edit_cursor->current_frame, times);
3135 session->add_command(new MementoCommand<AudioPlaylist>(*apl, &before, &apl->get_state()));
3137 if (tmp != ns->playlists.end()) {
3142 commit_reversible_command();
3146 Editor::duplicate_some_regions (RegionSelection& regions, float times)
3149 RegionSelection sel = regions; // clear (below) will clear the argument list
3151 begin_reversible_command (_("duplicate region"));
3153 selection->clear_regions ();
3155 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
3157 boost::shared_ptr<Region> r ((*i)->region());
3159 TimeAxisView& tv = (*i)->get_time_axis_view();
3160 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&tv);
3161 sigc::connection c = atv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3163 playlist = (*i)->region()->playlist();
3164 XMLNode &before = playlist->get_state();
3165 playlist->duplicate (r, r->last_frame(), times);
3166 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
3170 if (latest_regionview) {
3171 selection->add (latest_regionview);
3176 commit_reversible_command ();
3180 Editor::duplicate_selection (float times)
3182 if (selection->time.empty() || selection->tracks.empty()) {
3187 vector<boost::shared_ptr<AudioRegion> > new_regions;
3188 vector<boost::shared_ptr<AudioRegion> >::iterator ri;
3190 create_region_from_selection (new_regions);
3192 if (new_regions.empty()) {
3196 begin_reversible_command (_("duplicate selection"));
3198 ri = new_regions.begin();
3200 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3201 if ((playlist = (*i)->playlist()) == 0) {
3204 XMLNode &before = playlist->get_state();
3205 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
3206 XMLNode &after = playlist->get_state();
3207 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
3210 if (ri == new_regions.end()) {
3215 commit_reversible_command ();
3219 Editor::reset_point_selection ()
3221 /* reset all selected points to the relevant default value */
3223 cerr << "point selection has " << selection->points.size() << " entries\n";
3225 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3227 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
3230 atv->reset_objects (selection->points);
3236 Editor::center_playhead ()
3238 float page = canvas_width * frames_per_unit;
3240 center_screen_internal (playhead_cursor->current_frame, page);
3244 Editor::center_edit_cursor ()
3246 float page = canvas_width * frames_per_unit;
3248 center_screen_internal (edit_cursor->current_frame, page);
3252 Editor::clear_playlist (Playlist& playlist)
3254 begin_reversible_command (_("clear playlist"));
3255 XMLNode &before = playlist.get_state();
3257 XMLNode &after = playlist.get_state();
3258 session->add_command (new MementoCommand<Playlist>(playlist, &before, &after));
3259 commit_reversible_command ();
3263 Editor::nudge_track (bool use_edit_cursor, bool forwards)
3267 nframes_t next_distance;
3270 if (use_edit_cursor) {
3271 start = edit_cursor->current_frame;
3276 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
3280 if (selection->tracks.empty()) {
3284 begin_reversible_command (_("nudge track"));
3286 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3288 if ((playlist = (*i)->playlist()) == 0) {
3292 XMLNode &before = playlist->get_state();
3293 playlist->nudge_after (start, distance, forwards);
3294 XMLNode &after = playlist->get_state();
3295 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
3298 commit_reversible_command ();
3302 Editor::remove_last_capture ()
3304 vector<string> choices;
3311 if (Config->get_verify_remove_last_capture()) {
3312 prompt = _("Do you really want to destroy the last capture?"
3313 "\n(This is destructive and cannot be undone)");
3315 choices.push_back (_("No, do nothing."));
3316 choices.push_back (_("Yes, destroy it."));
3318 Gtkmm2ext::Choice prompter (prompt, choices);
3320 if (prompter.run () == 1) {
3321 session->remove_last_capture ();
3325 session->remove_last_capture();
3330 Editor::normalize_region ()
3336 if (selection->regions.empty()) {
3340 begin_reversible_command (_("normalize"));
3342 track_canvas.get_window()->set_cursor (*wait_cursor);
3345 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
3346 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3349 XMLNode &before = arv->region()->get_state();
3350 arv->audio_region()->normalize_to (0.0f);
3351 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
3354 commit_reversible_command ();
3355 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3360 Editor::denormalize_region ()
3366 if (selection->regions.empty()) {
3370 begin_reversible_command ("denormalize");
3372 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
3373 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3376 XMLNode &before = arv->region()->get_state();
3377 arv->audio_region()->set_scale_amplitude (1.0f);
3378 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
3381 commit_reversible_command ();
3386 Editor::reverse_region ()
3392 Reverse rev (*session);
3393 apply_filter (rev, _("reverse regions"));
3397 Editor::apply_filter (AudioFilter& filter, string command)
3399 if (selection->regions.empty()) {
3403 begin_reversible_command (command);
3405 track_canvas.get_window()->set_cursor (*wait_cursor);
3408 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ) {
3409 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3413 Playlist* playlist = arv->region()->playlist();
3415 RegionSelection::iterator tmp;
3420 if (arv->audio_region()->apply (filter) == 0) {
3422 XMLNode &before = playlist->get_state();
3423 playlist->replace_region (arv->region(), filter.results.front(), arv->region()->position());
3424 XMLNode &after = playlist->get_state();
3425 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
3433 commit_reversible_command ();
3434 selection->regions.clear ();
3437 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3441 Editor::region_selection_op (void (Region::*pmf)(void))
3443 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3444 Region* region = (*i)->region().get();
3451 Editor::region_selection_op (void (Region::*pmf)(void*), void *arg)
3453 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3454 Region* region = (*i)->region().get();
3455 (region->*pmf)(arg);
3460 Editor::region_selection_op (void (Region::*pmf)(bool), bool yn)
3462 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3463 Region* region = (*i)->region().get();
3469 Editor::external_edit_region ()
3471 if (!clicked_regionview) {
3479 Editor::brush (nframes_t pos)
3481 RegionSelection sel;
3484 if (selection->regions.empty()) {
3485 /* XXX get selection from region list */
3487 sel = selection->regions;
3494 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3495 mouse_brush_insert_region ((*i), pos);
3500 Editor::toggle_gain_envelope_visibility ()
3502 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3503 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3505 arv->set_envelope_visible (!arv->envelope_visible());
3510 Editor::toggle_gain_envelope_active ()
3512 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3513 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3515 arv->audio_region()->set_envelope_active (true);