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/playlist_factory.h>
48 #include <ardour/reverse.h>
50 #include "ardour_ui.h"
52 #include "time_axis_view.h"
53 #include "audio_time_axis.h"
54 #include "automation_time_axis.h"
55 #include "streamview.h"
56 #include "audio_region_view.h"
57 #include "rgb_macros.h"
58 #include "selection_templates.h"
59 #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 boost::shared_ptr<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 boost::shared_ptr<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) {
235 boost::shared_ptr<Playlist> pl;
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 reset_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 reset_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 ()
1202 if (selection->time.empty()) {
1206 if (session == 0 || clicked_trackview == 0) {
1210 nframes_t start = selection->time[clicked_selection].start;
1211 nframes_t end = selection->time[clicked_selection].end;
1213 session->locations()->next_available_name(rangename,"selection");
1214 Location *location = new Location (start, end, rangename, Location::IsRangeMarker);
1216 session->begin_reversible_command (_("add marker"));
1217 XMLNode &before = session->locations()->get_state();
1218 session->locations()->add (location, true);
1219 XMLNode &after = session->locations()->get_state();
1220 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1221 session->commit_reversible_command ();
1225 Editor::add_location_from_playhead_cursor ()
1229 nframes_t where = session->audible_frame();
1231 session->locations()->next_available_name(markername,"mark");
1232 Location *location = new Location (where, where, markername, Location::IsMark);
1233 session->begin_reversible_command (_("add marker"));
1234 XMLNode &before = session->locations()->get_state();
1235 session->locations()->add (location, true);
1236 XMLNode &after = session->locations()->get_state();
1237 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1238 session->commit_reversible_command ();
1242 Editor::add_location_from_audio_region ()
1244 if (selection->regions.empty()) {
1248 RegionView* rv = *(selection->regions.begin());
1249 boost::shared_ptr<Region> region = rv->region();
1251 Location *location = new Location (region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
1252 session->begin_reversible_command (_("add marker"));
1253 XMLNode &before = session->locations()->get_state();
1254 session->locations()->add (location, true);
1255 XMLNode &after = session->locations()->get_state();
1256 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1257 session->commit_reversible_command ();
1261 Editor::select_all_in_track (Selection::Operation op)
1263 list<Selectable *> touched;
1265 if (!clicked_trackview) {
1269 clicked_trackview->get_selectables (0, max_frames, 0, DBL_MAX, touched);
1272 case Selection::Toggle:
1273 selection->add (touched);
1275 case Selection::Set:
1276 selection->set (touched);
1278 case Selection::Extend:
1279 /* not defined yet */
1281 case Selection::Add:
1282 selection->add (touched);
1288 Editor::select_all (Selection::Operation op)
1290 list<Selectable *> touched;
1292 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1293 if ((*iter)->hidden()) {
1296 (*iter)->get_selectables (0, max_frames, 0, DBL_MAX, touched);
1298 begin_reversible_command (_("select all"));
1300 case Selection::Add:
1301 case Selection::Toggle:
1302 selection->add (touched);
1304 case Selection::Set:
1305 selection->set (touched);
1307 case Selection::Extend:
1308 /* not defined yet */
1311 commit_reversible_command ();
1315 Editor::invert_selection_in_track ()
1317 list<Selectable *> touched;
1319 if (!clicked_trackview) {
1323 clicked_trackview->get_inverted_selectables (*selection, touched);
1324 selection->set (touched);
1328 Editor::invert_selection ()
1330 list<Selectable *> touched;
1332 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1333 if ((*iter)->hidden()) {
1336 (*iter)->get_inverted_selectables (*selection, touched);
1339 selection->set (touched);
1343 Editor::select_all_within (nframes_t start, nframes_t end, double top, double bot, Selection::Operation op)
1345 list<Selectable *> touched;
1347 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1348 if ((*iter)->hidden()) {
1351 (*iter)->get_selectables (start, end, top, bot, touched);
1354 begin_reversible_command (_("select all within"));
1356 case Selection::Add:
1357 case Selection::Toggle:
1358 selection->add (touched);
1360 case Selection::Set:
1361 selection->set (touched);
1363 case Selection::Extend:
1364 /* not defined yet */
1368 commit_reversible_command ();
1369 return !touched.empty();
1373 Editor::set_selection_from_audio_region ()
1375 if (selection->regions.empty()) {
1379 RegionView* rv = *(selection->regions.begin());
1380 boost::shared_ptr<Region> region = rv->region();
1382 begin_reversible_command (_("set selection from region"));
1383 selection->set (0, region->position(), region->last_frame());
1384 commit_reversible_command ();
1386 set_mouse_mode (Editing::MouseRange, false);
1390 Editor::set_selection_from_punch()
1394 if ((location = session->locations()->auto_punch_location()) == 0) {
1398 set_selection_from_range (*location);
1402 Editor::set_selection_from_loop()
1406 if ((location = session->locations()->auto_loop_location()) == 0) {
1409 set_selection_from_range (*location);
1413 Editor::set_selection_from_range (Location& loc)
1415 begin_reversible_command (_("set selection from range"));
1416 selection->set (0, loc.start(), loc.end());
1417 commit_reversible_command ();
1419 set_mouse_mode (Editing::MouseRange, false);
1423 Editor::select_all_selectables_using_time_selection ()
1425 list<Selectable *> touched;
1427 if (selection->time.empty()) {
1431 nframes_t start = selection->time[clicked_selection].start;
1432 nframes_t end = selection->time[clicked_selection].end;
1434 if (end - start < 1) {
1438 for (TrackViewList::iterator iter = selection->tracks.begin(); iter != selection->tracks.end(); ++iter) {
1439 if ((*iter)->hidden()) {
1442 (*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
1445 begin_reversible_command (_("select all from range"));
1446 selection->set (touched);
1447 commit_reversible_command ();
1452 Editor::select_all_selectables_using_punch()
1454 Location* location = session->locations()->auto_punch_location();
1455 list<Selectable *> touched;
1457 if (location == 0 || (location->end() - location->start() <= 1)) {
1461 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1462 if ((*iter)->hidden()) {
1465 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1467 begin_reversible_command (_("select all from punch"));
1468 selection->set (touched);
1469 commit_reversible_command ();
1474 Editor::select_all_selectables_using_loop()
1476 Location* location = session->locations()->auto_loop_location();
1477 list<Selectable *> touched;
1479 if (location == 0 || (location->end() - location->start() <= 1)) {
1483 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1484 if ((*iter)->hidden()) {
1487 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1489 begin_reversible_command (_("select all from loop"));
1490 selection->set (touched);
1491 commit_reversible_command ();
1496 Editor::select_all_selectables_using_cursor (Cursor *cursor, bool after)
1500 list<Selectable *> touched;
1503 begin_reversible_command (_("select all after cursor"));
1504 start = cursor->current_frame ;
1505 end = session->current_end_frame();
1507 if (cursor->current_frame > 0) {
1508 begin_reversible_command (_("select all before cursor"));
1510 end = cursor->current_frame - 1;
1516 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1517 if ((*iter)->hidden()) {
1520 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1522 selection->set (touched);
1523 commit_reversible_command ();
1527 Editor::select_all_selectables_between_cursors (Cursor *cursor, Cursor *other_cursor)
1531 list<Selectable *> touched;
1532 bool other_cursor_is_first = cursor->current_frame > other_cursor->current_frame;
1534 if (cursor->current_frame == other_cursor->current_frame) {
1538 begin_reversible_command (_("select all between cursors"));
1539 if (other_cursor_is_first) {
1540 start = other_cursor->current_frame;
1541 end = cursor->current_frame - 1;
1544 start = cursor->current_frame;
1545 end = other_cursor->current_frame - 1;
1548 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1549 if ((*iter)->hidden()) {
1552 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1554 selection->set (touched);
1555 commit_reversible_command ();
1559 Editor::amplitude_zoom_step (bool in)
1573 #ifdef FIX_FOR_CANVAS
1574 /* XXX DO SOMETHING */
1583 Editor::delete_sample_forward ()
1588 Editor::delete_sample_backward ()
1593 Editor::delete_screen ()
1600 Editor::search_backwards ()
1606 Editor::search_forwards ()
1614 Editor::jump_forward_to_mark ()
1620 Location *location = session->locations()->first_location_after (playhead_cursor->current_frame);
1623 session->request_locate (location->start(), session->transport_rolling());
1625 session->request_locate (session->current_end_frame());
1630 Editor::jump_backward_to_mark ()
1636 Location *location = session->locations()->first_location_before (playhead_cursor->current_frame);
1639 session->request_locate (location->start(), session->transport_rolling());
1641 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()->next_available_name(markername,"mark");
1664 session->locations()->add (new Location (pos, 0, markername, Location::IsMark), true);
1668 Editor::clear_markers ()
1671 session->begin_reversible_command (_("clear markers"));
1672 XMLNode &before = session->locations()->get_state();
1673 session->locations()->clear_markers ();
1674 XMLNode &after = session->locations()->get_state();
1675 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1676 session->commit_reversible_command ();
1681 Editor::clear_ranges ()
1684 session->begin_reversible_command (_("clear ranges"));
1685 XMLNode &before = session->locations()->get_state();
1687 Location * looploc = session->locations()->auto_loop_location();
1688 Location * punchloc = session->locations()->auto_punch_location();
1690 session->locations()->clear_ranges ();
1692 if (looploc) session->locations()->add (looploc);
1693 if (punchloc) session->locations()->add (punchloc);
1695 XMLNode &after = session->locations()->get_state();
1696 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1697 session->commit_reversible_command ();
1702 Editor::clear_locations ()
1704 session->begin_reversible_command (_("clear locations"));
1705 XMLNode &before = session->locations()->get_state();
1706 session->locations()->clear ();
1707 XMLNode &after = session->locations()->get_state();
1708 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1709 session->commit_reversible_command ();
1710 session->locations()->clear ();
1714 Editor::unhide_markers ()
1716 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1717 Location *l = (*i).first;
1718 if (l->is_hidden() && l->is_mark()) {
1719 l->set_hidden(false, this);
1725 Editor::unhide_ranges ()
1727 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1728 Location *l = (*i).first;
1729 if (l->is_hidden() && l->is_range_marker()) {
1730 l->set_hidden(false, this);
1735 /* INSERT/REPLACE */
1738 Editor::insert_region_list_drag (boost::shared_ptr<AudioRegion> region, int x, int y)
1744 AudioTimeAxisView *atv = 0;
1745 boost::shared_ptr<Playlist> playlist;
1747 track_canvas.window_to_world (x, y, wx, wy);
1748 wx += horizontal_adjustment.get_value();
1749 wy += vertical_adjustment.get_value();
1752 event.type = GDK_BUTTON_RELEASE;
1753 event.button.x = wx;
1754 event.button.y = wy;
1756 where = event_frame (&event, &cx, &cy);
1758 if (where < leftmost_frame || where > leftmost_frame + current_page_frames()) {
1759 /* clearly outside canvas area */
1763 if ((tv = trackview_by_y_position (cy)) == 0) {
1767 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) == 0) {
1771 if ((playlist = atv->playlist()) == 0) {
1775 cerr << "drop target playlist, UC = " << playlist.use_count() << endl;
1779 begin_reversible_command (_("insert dragged region"));
1780 XMLNode &before = playlist->get_state();
1781 cerr << "pre add target playlist, UC = " << playlist.use_count() << endl;
1782 playlist->add_region (RegionFactory::create (region), where, 1.0);
1783 cerr << "post add target playlist, UC = " << playlist.use_count() << endl;
1784 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
1785 commit_reversible_command ();
1787 cerr << "post drop target playlist, UC = " << playlist.use_count() << endl;
1791 Editor::insert_region_list_selection (float times)
1793 RouteTimeAxisView *tv = 0;
1794 boost::shared_ptr<Playlist> playlist;
1796 if (clicked_audio_trackview != 0) {
1797 tv = clicked_audio_trackview;
1798 } else if (!selection->tracks.empty()) {
1799 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
1806 if ((playlist = tv->playlist()) == 0) {
1810 Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
1812 if (selected->count_selected_rows() != 1) {
1816 TreeView::Selection::ListHandle_Path rows = selected->get_selected_rows ();
1818 /* only one row selected, so rows.begin() is it */
1822 if ((iter = region_list_model->get_iter (*rows.begin()))) {
1824 boost::shared_ptr<Region> region = (*iter)[region_list_columns.region];
1826 begin_reversible_command (_("insert region"));
1827 XMLNode &before = playlist->get_state();
1828 playlist->add_region ((RegionFactory::create (region)), edit_cursor->current_frame, times);
1829 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
1830 commit_reversible_command ();
1834 /* BUILT-IN EFFECTS */
1837 Editor::reverse_selection ()
1842 /* GAIN ENVELOPE EDITING */
1845 Editor::edit_envelope ()
1852 Editor::toggle_playback (bool with_abort)
1858 switch (Config->get_slave_source()) {
1863 /* transport controlled by the master */
1867 if (session->is_auditioning()) {
1868 session->cancel_audition ();
1872 if (session->transport_rolling()) {
1873 session->request_stop (with_abort);
1874 if (session->get_play_loop()) {
1875 session->request_play_loop (false);
1878 session->request_transport_speed (1.0f);
1883 Editor::play_from_start ()
1885 session->request_locate (session->current_start_frame(), true);
1889 Editor::play_from_edit_cursor ()
1891 session->request_locate (edit_cursor->current_frame, true);
1895 Editor::play_selection ()
1897 if (selection->time.empty()) {
1901 session->request_play_range (true);
1905 Editor::play_selected_region ()
1907 if (!selection->regions.empty()) {
1908 RegionView *rv = *(selection->regions.begin());
1910 session->request_bounded_roll (rv->region()->position(), rv->region()->last_frame());
1915 Editor::loop_selected_region ()
1917 if (!selection->regions.empty()) {
1918 RegionView *rv = *(selection->regions.begin());
1921 if ((tll = transport_loop_location()) != 0) {
1923 tll->set (rv->region()->position(), rv->region()->last_frame());
1925 // enable looping, reposition and start rolling
1927 session->request_play_loop (true);
1928 session->request_locate (tll->start(), false);
1929 session->request_transport_speed (1.0f);
1935 Editor::play_location (Location& location)
1937 if (location.start() <= location.end()) {
1941 session->request_bounded_roll (location.start(), location.end());
1945 Editor::loop_location (Location& location)
1947 if (location.start() <= location.end()) {
1953 if ((tll = transport_loop_location()) != 0) {
1954 tll->set (location.start(), location.end());
1956 // enable looping, reposition and start rolling
1957 session->request_play_loop (true);
1958 session->request_locate (tll->start(), true);
1963 Editor::raise_region ()
1965 selection->foreach_region (&Region::raise);
1969 Editor::raise_region_to_top ()
1971 selection->foreach_region (&Region::raise_to_top);
1975 Editor::lower_region ()
1977 selection->foreach_region (&Region::lower);
1981 Editor::lower_region_to_bottom ()
1983 selection->foreach_region (&Region::lower_to_bottom);
1987 Editor::edit_region ()
1989 if (clicked_regionview == 0) {
1993 clicked_regionview->show_region_editor ();
1997 Editor::rename_region ()
2001 Button ok_button (_("OK"));
2002 Button cancel_button (_("Cancel"));
2004 if (selection->regions.empty()) {
2008 dialog.set_title (_("ardour: rename region"));
2009 dialog.set_name ("RegionRenameWindow");
2010 dialog.set_size_request (300, -1);
2011 dialog.set_position (Gtk::WIN_POS_MOUSE);
2012 dialog.set_modal (true);
2014 dialog.get_vbox()->set_border_width (10);
2015 dialog.get_vbox()->pack_start (entry);
2016 dialog.get_action_area()->pack_start (ok_button);
2017 dialog.get_action_area()->pack_start (cancel_button);
2019 entry.set_name ("RegionNameDisplay");
2020 ok_button.set_name ("EditorGTKButton");
2021 cancel_button.set_name ("EditorGTKButton");
2023 region_renamed = false;
2025 entry.signal_activate().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
2026 ok_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
2027 cancel_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::rename_region_finished), false));
2034 if (region_renamed) {
2035 (*selection->regions.begin())->region()->set_name (entry.get_text());
2036 redisplay_regions ();
2041 Editor::rename_region_finished (bool status)
2044 region_renamed = status;
2049 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2051 if (session->is_auditioning()) {
2052 session->cancel_audition ();
2055 // note: some potential for creativity here, because region doesn't
2056 // have to belong to the playlist that Route is handling
2058 // bool was_soloed = route.soloed();
2060 route.set_solo (true, this);
2062 session->request_bounded_roll (region->position(), region->position() + region->length());
2064 /* XXX how to unset the solo state ? */
2068 Editor::audition_selected_region ()
2070 if (!selection->regions.empty()) {
2071 RegionView* rv = *(selection->regions.begin());
2072 session->audition_region (rv->region());
2077 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2079 session->audition_region (region);
2083 Editor::build_interthread_progress_window ()
2085 interthread_progress_window = new ArdourDialog (X_("interthread progress"), true);
2087 interthread_progress_bar.set_orientation (Gtk::PROGRESS_LEFT_TO_RIGHT);
2089 interthread_progress_window->get_vbox()->pack_start (interthread_progress_label, false, false);
2090 interthread_progress_window->get_vbox()->pack_start (interthread_progress_bar,false, false);
2092 // GTK2FIX: this button needs a modifiable label
2094 Button* b = interthread_progress_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
2095 b->signal_clicked().connect (mem_fun(*this, &Editor::interthread_cancel_clicked));
2097 interthread_cancel_button.add (interthread_cancel_label);
2099 interthread_progress_window->set_default_size (200, 100);
2103 Editor::interthread_cancel_clicked ()
2105 if (current_interthread_info) {
2106 current_interthread_info->cancel = true;
2111 Editor::region_from_selection ()
2113 if (clicked_trackview == 0) {
2117 if (selection->time.empty()) {
2121 nframes_t start = selection->time[clicked_selection].start;
2122 nframes_t end = selection->time[clicked_selection].end;
2124 nframes_t selection_cnt = end - start + 1;
2126 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2127 boost::shared_ptr<AudioRegion> current;
2128 boost::shared_ptr<Region> current_r;
2129 boost::shared_ptr<Playlist> pl;
2131 nframes_t internal_start;
2134 if ((pl = (*i)->playlist()) == 0) {
2138 if ((current_r = pl->top_region_at (start)) == 0) {
2142 current = boost::dynamic_pointer_cast<AudioRegion> (current_r);
2143 // FIXME: audio only
2145 internal_start = start - current->position();
2146 session->region_name (new_name, current->name(), true);
2147 boost::shared_ptr<Region> region (RegionFactory::create (current, internal_start, selection_cnt, new_name));
2153 Editor::create_region_from_selection (vector<boost::shared_ptr<AudioRegion> >& new_regions)
2155 if (selection->time.empty() || selection->tracks.empty()) {
2159 nframes_t start = selection->time[clicked_selection].start;
2160 nframes_t end = selection->time[clicked_selection].end;
2162 sort_track_selection ();
2164 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2166 boost::shared_ptr<AudioRegion> current;
2167 boost::shared_ptr<Region> current_r;
2168 boost::shared_ptr<Playlist> playlist;
2169 nframes_t internal_start;
2172 if ((playlist = (*i)->playlist()) == 0) {
2176 if ((current_r = playlist->top_region_at(start)) == 0) {
2180 if ((current = boost::dynamic_pointer_cast<AudioRegion>(current_r)) == 0) {
2184 internal_start = start - current->position();
2185 session->region_name (new_name, current->name(), true);
2187 new_regions.push_back (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (current, internal_start, end - start + 1, new_name)));
2192 Editor::split_multichannel_region ()
2194 vector<AudioRegion*> v;
2196 AudioRegionView* clicked_arv = dynamic_cast<AudioRegionView*>(clicked_regionview);
2198 if (!clicked_arv || clicked_arv->audio_region()->n_channels() < 2) {
2202 clicked_arv->audio_region()->separate_by_channel (*session, v);
2204 /* nothing else to do, really */
2208 Editor::new_region_from_selection ()
2210 region_from_selection ();
2211 cancel_selection ();
2215 Editor::separate_region_from_selection ()
2217 bool doing_undo = false;
2219 if (selection->time.empty()) {
2223 boost::shared_ptr<Playlist> playlist;
2225 sort_track_selection ();
2227 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2229 AudioTimeAxisView* atv;
2231 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2233 if (atv->is_audio_track()) {
2235 if ((playlist = atv->playlist()) != 0) {
2237 begin_reversible_command (_("separate"));
2242 before = &(playlist->get_state());
2244 /* XXX need to consider musical time selections here at some point */
2246 double speed = atv->get_diskstream()->speed();
2248 for (list<AudioRange>::iterator t = selection->time.begin(); t != selection->time.end(); ++t) {
2249 playlist->partition ((nframes_t)((*t).start * speed), (nframes_t)((*t).end * speed), true);
2253 session->add_command(new MementoCommand<Playlist>(*playlist, before, &playlist->get_state()));
2259 if (doing_undo) commit_reversible_command ();
2263 Editor::separate_regions_using_location (Location& loc)
2265 bool doing_undo = false;
2267 if (loc.is_mark()) {
2271 boost::shared_ptr<Playlist> playlist;
2273 /* XXX i'm unsure as to whether this should operate on selected tracks only
2274 or the entire enchillada. uncomment the below line to correct the behaviour
2275 (currently set for all tracks)
2278 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
2279 //for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2281 AudioTimeAxisView* atv;
2283 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2285 if (atv->is_audio_track()) {
2287 if ((playlist = atv->playlist()) != 0) {
2290 begin_reversible_command (_("separate"));
2294 before = &(playlist->get_state());
2297 /* XXX need to consider musical time selections here at some point */
2299 double speed = atv->get_diskstream()->speed();
2302 playlist->partition ((nframes_t)(loc.start() * speed), (nframes_t)(loc.end() * speed), true);
2304 session->add_command(new MementoCommand<Playlist>(*playlist, before, &playlist->get_state()));
2310 if (doing_undo) commit_reversible_command ();
2314 Editor::crop_region_to_selection ()
2316 if (selection->time.empty()) {
2320 vector<boost::shared_ptr<Playlist> > playlists;
2321 boost::shared_ptr<Playlist> playlist;
2323 if (clicked_trackview != 0) {
2325 if ((playlist = clicked_trackview->playlist()) == 0) {
2329 playlists.push_back (playlist);
2333 sort_track_selection ();
2335 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2337 AudioTimeAxisView* atv;
2339 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2341 if (atv->is_audio_track()) {
2343 if ((playlist = atv->playlist()) != 0) {
2344 playlists.push_back (playlist);
2351 if (!playlists.empty()) {
2357 begin_reversible_command (_("trim to selection"));
2359 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2361 boost::shared_ptr<Region> region;
2363 start = selection->time.start();
2365 if ((region = (*i)->top_region_at(start)) == 0) {
2369 /* now adjust lengths to that we do the right thing
2370 if the selection extends beyond the region
2373 start = max (start, region->position());
2374 end = min (selection->time.end_frame(), start + region->length() - 1);
2375 cnt = end - start + 1;
2377 XMLNode &before = (*i)->get_state();
2378 region->trim_to (start, cnt, this);
2379 XMLNode &after = (*i)->get_state();
2380 session->add_command (new MementoCommand<Playlist>(*(*i), &before, &after));
2383 commit_reversible_command ();
2388 Editor::region_fill_track ()
2392 if (!session || selection->regions.empty()) {
2396 end = session->current_end_frame ();
2398 begin_reversible_command (_("region fill"));
2400 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2402 boost::shared_ptr<Region> region ((*i)->region());
2405 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(region);
2409 boost::shared_ptr<Playlist> pl = region->playlist();
2411 if (end <= region->last_frame()) {
2415 double times = (double) (end - region->last_frame()) / (double) region->length();
2421 XMLNode &before = pl->get_state();
2422 pl->add_region (RegionFactory::create (ar), ar->last_frame(), times);
2423 session->add_command (new MementoCommand<Playlist>(*pl, &before, &pl->get_state()));
2426 commit_reversible_command ();
2430 Editor::region_fill_selection ()
2432 if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2436 if (selection->time.empty()) {
2441 Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
2443 if (selected->count_selected_rows() != 1) {
2447 TreeModel::iterator i = region_list_display.get_selection()->get_selected();
2448 boost::shared_ptr<Region> region = (*i)[region_list_columns.region];
2450 nframes_t start = selection->time[clicked_selection].start;
2451 nframes_t end = selection->time[clicked_selection].end;
2453 boost::shared_ptr<Playlist> playlist;
2455 if (selection->tracks.empty()) {
2459 nframes_t selection_length = end - start;
2460 float times = (float)selection_length / region->length();
2462 begin_reversible_command (_("fill selection"));
2464 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2466 if ((playlist = (*i)->playlist()) == 0) {
2470 XMLNode &before = playlist->get_state();
2471 playlist->add_region (RegionFactory::create (region), start, times);
2472 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
2475 commit_reversible_command ();
2479 Editor::set_a_regions_sync_position (boost::shared_ptr<Region> region, nframes_t position)
2482 if (!region->covers (position)) {
2483 error << _("Programming error. that region doesn't cover that position") << __FILE__ << " +" << __LINE__ << endmsg;
2486 begin_reversible_command (_("set region sync position"));
2487 XMLNode &before = region->playlist()->get_state();
2488 region->set_sync_position (position);
2489 XMLNode &after = region->playlist()->get_state();
2490 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2491 commit_reversible_command ();
2495 Editor::set_region_sync_from_edit_cursor ()
2497 if (clicked_regionview == 0) {
2501 if (!clicked_regionview->region()->covers (edit_cursor->current_frame)) {
2502 error << _("Place the edit cursor at the desired sync point") << endmsg;
2506 boost::shared_ptr<Region> region (clicked_regionview->region());
2507 begin_reversible_command (_("set sync from edit cursor"));
2508 XMLNode &before = region->playlist()->get_state();
2509 region->set_sync_position (edit_cursor->current_frame);
2510 XMLNode &after = region->playlist()->get_state();
2511 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2512 commit_reversible_command ();
2516 Editor::remove_region_sync ()
2518 if (clicked_regionview) {
2519 boost::shared_ptr<Region> region (clicked_regionview->region());
2520 begin_reversible_command (_("remove sync"));
2521 XMLNode &before = region->playlist()->get_state();
2522 region->clear_sync_position ();
2523 XMLNode &after = region->playlist()->get_state();
2524 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2525 commit_reversible_command ();
2530 Editor::naturalize ()
2532 if (selection->regions.empty()) {
2535 begin_reversible_command (_("naturalize"));
2536 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2537 XMLNode &before = (*i)->region()->get_state();
2538 (*i)->region()->move_to_natural_position (this);
2539 XMLNode &after = (*i)->region()->get_state();
2540 session->add_command (new MementoCommand<Region>(*((*i)->region().get()), &before, &after));
2542 commit_reversible_command ();
2546 Editor::align (RegionPoint what)
2548 align_selection (what, edit_cursor->current_frame);
2552 Editor::align_relative (RegionPoint what)
2554 align_selection_relative (what, edit_cursor->current_frame);
2557 struct RegionSortByTime {
2558 bool operator() (const AudioRegionView* a, const AudioRegionView* b) {
2559 return a->region()->position() < b->region()->position();
2564 Editor::align_selection_relative (RegionPoint point, nframes_t position)
2566 if (selection->regions.empty()) {
2574 list<RegionView*> sorted;
2575 selection->regions.by_position (sorted);
2576 boost::shared_ptr<Region> r ((*sorted.begin())->region());
2580 pos = r->first_frame ();
2584 pos = r->last_frame();
2588 pos = r->adjust_to_sync (r->first_frame());
2592 if (pos > position) {
2593 distance = pos - position;
2596 distance = position - pos;
2600 begin_reversible_command (_("align selection (relative)"));
2602 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2604 boost::shared_ptr<Region> region ((*i)->region());
2606 XMLNode &before = region->playlist()->get_state();
2609 region->set_position (region->position() + distance, this);
2611 region->set_position (region->position() - distance, this);
2614 XMLNode &after = region->playlist()->get_state();
2615 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2619 commit_reversible_command ();
2623 Editor::align_selection (RegionPoint point, nframes_t position)
2625 if (selection->regions.empty()) {
2629 begin_reversible_command (_("align selection"));
2631 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2632 align_region_internal ((*i)->region(), point, position);
2635 commit_reversible_command ();
2639 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, nframes_t position)
2641 begin_reversible_command (_("align region"));
2642 align_region_internal (region, point, position);
2643 commit_reversible_command ();
2647 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, nframes_t position)
2649 XMLNode &before = region->playlist()->get_state();
2653 region->set_position (region->adjust_to_sync (position), this);
2657 if (position > region->length()) {
2658 region->set_position (position - region->length(), this);
2663 region->set_position (position, this);
2667 XMLNode &after = region->playlist()->get_state();
2668 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2672 Editor::trim_region_to_edit_cursor ()
2674 if (clicked_regionview == 0) {
2678 boost::shared_ptr<Region> region (clicked_regionview->region());
2681 AudioTimeAxisView *atav;
2683 if ( clicked_trackview != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(clicked_trackview)) != 0 ) {
2684 if (atav->get_diskstream() != 0) {
2685 speed = atav->get_diskstream()->speed();
2689 begin_reversible_command (_("trim to edit"));
2690 XMLNode &before = region->playlist()->get_state();
2691 region->trim_end( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
2692 XMLNode &after = region->playlist()->get_state();
2693 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2694 commit_reversible_command ();
2698 Editor::trim_region_from_edit_cursor ()
2700 if (clicked_regionview == 0) {
2704 boost::shared_ptr<Region> region (clicked_regionview->region());
2707 AudioTimeAxisView *atav;
2709 if ( clicked_trackview != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(clicked_trackview)) != 0 ) {
2710 if (atav->get_diskstream() != 0) {
2711 speed = atav->get_diskstream()->speed();
2715 begin_reversible_command (_("trim to edit"));
2716 XMLNode &before = region->playlist()->get_state();
2717 region->trim_front ( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
2718 XMLNode &after = region->playlist()->get_state();
2719 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2720 commit_reversible_command ();
2724 Editor::unfreeze_route ()
2726 if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2730 clicked_audio_trackview->audio_track()->unfreeze ();
2734 Editor::_freeze_thread (void* arg)
2736 PBD::ThreadCreated (pthread_self(), X_("Freeze"));
2737 return static_cast<Editor*>(arg)->freeze_thread ();
2741 Editor::freeze_thread ()
2743 clicked_audio_trackview->audio_track()->freeze (*current_interthread_info);
2748 Editor::freeze_progress_timeout (void *arg)
2750 interthread_progress_bar.set_fraction (current_interthread_info->progress/100);
2751 return !(current_interthread_info->done || current_interthread_info->cancel);
2755 Editor::freeze_route ()
2757 if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2761 InterThreadInfo itt;
2763 if (interthread_progress_window == 0) {
2764 build_interthread_progress_window ();
2767 interthread_progress_window->set_title (_("ardour: freeze"));
2768 interthread_progress_window->set_position (Gtk::WIN_POS_MOUSE);
2769 interthread_progress_window->show_all ();
2770 interthread_progress_bar.set_fraction (0.0f);
2771 interthread_progress_label.set_text ("");
2772 interthread_cancel_label.set_text (_("Cancel Freeze"));
2773 current_interthread_info = &itt;
2775 interthread_progress_connection =
2776 Glib::signal_timeout().connect (bind (mem_fun(*this, &Editor::freeze_progress_timeout), (gpointer) 0), 100);
2780 itt.progress = 0.0f;
2782 pthread_attr_t attr;
2783 pthread_attr_init(&attr);
2784 pthread_attr_setstacksize(&attr, 500000);
2786 pthread_create (&itt.thread, &attr, _freeze_thread, this);
2788 pthread_attr_destroy(&attr);
2790 track_canvas.get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
2792 while (!itt.done && !itt.cancel) {
2793 gtk_main_iteration ();
2796 interthread_progress_connection.disconnect ();
2797 interthread_progress_window->hide_all ();
2798 current_interthread_info = 0;
2799 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
2803 Editor::bounce_range_selection ()
2805 if (selection->time.empty()) {
2809 TrackViewList *views = get_valid_views (selection->time.track, selection->time.group);
2811 nframes_t start = selection->time[clicked_selection].start;
2812 nframes_t end = selection->time[clicked_selection].end;
2813 nframes_t cnt = end - start + 1;
2815 begin_reversible_command (_("bounce range"));
2817 for (TrackViewList::iterator i = views->begin(); i != views->end(); ++i) {
2819 AudioTimeAxisView* atv;
2821 if ((atv = dynamic_cast<AudioTimeAxisView*> (*i)) == 0) {
2825 boost::shared_ptr<Playlist> playlist;
2827 if ((playlist = atv->playlist()) == 0) {
2831 InterThreadInfo itt;
2835 itt.progress = false;
2837 XMLNode &before = playlist->get_state();
2838 atv->audio_track()->bounce_range (start, cnt, itt);
2839 XMLNode &after = playlist->get_state();
2840 session->add_command (new MementoCommand<Playlist> (*playlist, &before, &after));
2843 commit_reversible_command ();
2861 Editor::cut_copy (CutCopyOp op)
2863 /* only cancel selection if cut/copy is successful.*/
2875 opname = _("clear");
2879 cut_buffer->clear ();
2881 switch (current_mouse_mode()) {
2883 if (!selection->regions.empty() || !selection->points.empty()) {
2885 begin_reversible_command (opname + _(" objects"));
2887 if (!selection->regions.empty()) {
2889 cut_copy_regions (op);
2892 selection->clear_regions ();
2896 if (!selection->points.empty()) {
2897 cut_copy_points (op);
2900 selection->clear_points ();
2904 commit_reversible_command ();
2909 if (!selection->time.empty()) {
2911 begin_reversible_command (opname + _(" range"));
2912 cut_copy_ranges (op);
2913 commit_reversible_command ();
2916 selection->clear_time ();
2928 Editor::cut_copy_points (CutCopyOp op)
2930 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
2932 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
2935 atv->cut_copy_clear_objects (selection->points, op);
2940 struct PlaylistState {
2941 boost::shared_ptr<Playlist> playlist;
2945 struct lt_playlist {
2946 bool operator () (const PlaylistState& a, const PlaylistState& b) {
2947 return a.playlist < b.playlist;
2951 struct PlaylistMapping {
2953 boost::shared_ptr<AudioPlaylist> pl;
2955 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
2959 Editor::cut_copy_regions (CutCopyOp op)
2961 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
2962 a map when we want ordered access to both elements. i think.
2965 vector<PlaylistMapping> pmap;
2967 nframes_t first_position = max_frames;
2969 set<PlaylistState, lt_playlist> freezelist;
2970 pair<set<PlaylistState, lt_playlist>::iterator,bool> insert_result;
2972 /* get ordering correct before we cut/copy */
2974 selection->regions.sort_by_position_and_track ();
2976 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
2978 first_position = min ((*x)->region()->position(), first_position);
2980 if (op == Cut || op == Clear) {
2981 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist>((*x)->region()->playlist());
2985 PlaylistState before;
2986 before.playlist = pl;
2987 before.before = &pl->get_state();
2989 insert_result = freezelist.insert (before);
2991 if (insert_result.second) {
2997 TimeAxisView* tv = &(*x)->get_trackview();
2998 vector<PlaylistMapping>::iterator z;
3000 for (z = pmap.begin(); z != pmap.end(); ++z) {
3001 if ((*z).tv == tv) {
3006 if (z == pmap.end()) {
3007 pmap.push_back (PlaylistMapping (tv));
3011 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ) {
3013 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist>((*x)->region()->playlist());
3016 /* impossible, but this handles it for the future */
3020 TimeAxisView& tv = (*x)->get_trackview();
3021 boost::shared_ptr<AudioPlaylist> npl;
3022 RegionSelection::iterator tmp;
3027 vector<PlaylistMapping>::iterator z;
3029 for (z = pmap.begin(); z != pmap.end(); ++z) {
3030 if ((*z).tv == &tv) {
3035 assert (z != pmap.end());
3038 npl = boost::dynamic_pointer_cast<AudioPlaylist> (PlaylistFactory::create (*session, "cutlist", true));
3045 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>((*x)->region());
3051 npl->add_region (RegionFactory::create (ar), (*x)->region()->position() - first_position);
3052 pl->remove_region (((*x)->region()));
3058 npl->add_region (RegionFactory::create (ar), (*x)->region()->position() - first_position);
3062 pl->remove_region (((*x)->region()));
3069 list<boost::shared_ptr<Playlist> > foo;
3071 /* the pmap is in the same order as the tracks in which selected regions occured */
3073 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
3075 foo.push_back ((*i).pl);
3079 cut_buffer->set (foo);
3082 for (set<PlaylistState, lt_playlist>::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
3083 (*pl).playlist->thaw ();
3084 session->add_command (new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3089 Editor::cut_copy_ranges (CutCopyOp op)
3091 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3092 (*i)->cut_copy_clear (*selection, op);
3097 Editor::paste (float times)
3099 paste_internal (edit_cursor->current_frame, times);
3103 Editor::mouse_paste ()
3108 track_canvas.get_pointer (x, y);
3109 track_canvas.window_to_world (x, y, wx, wy);
3110 wx += horizontal_adjustment.get_value();
3111 wy += vertical_adjustment.get_value();
3114 event.type = GDK_BUTTON_RELEASE;
3115 event.button.x = wx;
3116 event.button.y = wy;
3118 nframes_t where = event_frame (&event, 0, 0);
3120 paste_internal (where, 1);
3124 Editor::paste_internal (nframes_t position, float times)
3126 bool commit = false;
3128 if (cut_buffer->empty() || selection->tracks.empty()) {
3132 if (position == max_frames) {
3133 position = edit_cursor->current_frame;
3136 begin_reversible_command (_("paste"));
3138 TrackSelection::iterator i;
3141 /* get everything in the correct order */
3143 sort_track_selection ();
3145 for (nth = 0, i = selection->tracks.begin(); i != selection->tracks.end(); ++i, ++nth) {
3147 /* undo/redo is handled by individual tracks */
3149 if ((*i)->paste (position, times, *cut_buffer, nth)) {
3155 commit_reversible_command ();
3160 Editor::paste_named_selection (float times)
3162 TrackSelection::iterator t;
3164 Glib::RefPtr<TreeSelection> selected = named_selection_display.get_selection();
3166 if (selected->count_selected_rows() != 1 || selection->tracks.empty()) {
3170 TreeModel::iterator i = selected->get_selected();
3171 NamedSelection* ns = (*i)[named_selection_columns.selection];
3173 list<boost::shared_ptr<Playlist> >::iterator chunk;
3174 list<boost::shared_ptr<Playlist> >::iterator tmp;
3176 chunk = ns->playlists.begin();
3178 begin_reversible_command (_("paste chunk"));
3180 sort_track_selection ();
3182 for (t = selection->tracks.begin(); t != selection->tracks.end(); ++t) {
3184 AudioTimeAxisView* atv;
3185 boost::shared_ptr<Playlist> pl;
3186 boost::shared_ptr<AudioPlaylist> apl;
3188 if ((atv = dynamic_cast<AudioTimeAxisView*> (*t)) == 0) {
3192 if ((pl = atv->playlist()) == 0) {
3196 if ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) == 0) {
3203 XMLNode &before = apl->get_state();
3204 apl->paste (*chunk, edit_cursor->current_frame, times);
3205 session->add_command(new MementoCommand<AudioPlaylist>(*apl, &before, &apl->get_state()));
3207 if (tmp != ns->playlists.end()) {
3212 commit_reversible_command();
3216 Editor::duplicate_some_regions (RegionSelection& regions, float times)
3218 boost::shared_ptr<Playlist> playlist;
3219 RegionSelection sel = regions; // clear (below) will clear the argument list
3221 begin_reversible_command (_("duplicate region"));
3223 selection->clear_regions ();
3225 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
3227 boost::shared_ptr<Region> r ((*i)->region());
3229 TimeAxisView& tv = (*i)->get_time_axis_view();
3230 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&tv);
3231 sigc::connection c = atv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3233 playlist = (*i)->region()->playlist();
3234 XMLNode &before = playlist->get_state();
3235 playlist->duplicate (r, r->last_frame(), times);
3236 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
3240 if (latest_regionview) {
3241 selection->add (latest_regionview);
3246 commit_reversible_command ();
3250 Editor::duplicate_selection (float times)
3252 if (selection->time.empty() || selection->tracks.empty()) {
3256 boost::shared_ptr<Playlist> playlist;
3257 vector<boost::shared_ptr<AudioRegion> > new_regions;
3258 vector<boost::shared_ptr<AudioRegion> >::iterator ri;
3260 create_region_from_selection (new_regions);
3262 if (new_regions.empty()) {
3266 begin_reversible_command (_("duplicate selection"));
3268 ri = new_regions.begin();
3270 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3271 if ((playlist = (*i)->playlist()) == 0) {
3274 XMLNode &before = playlist->get_state();
3275 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
3276 XMLNode &after = playlist->get_state();
3277 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
3280 if (ri == new_regions.end()) {
3285 commit_reversible_command ();
3289 Editor::reset_point_selection ()
3291 /* reset all selected points to the relevant default value */
3293 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3295 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
3298 atv->reset_objects (selection->points);
3304 Editor::center_playhead ()
3306 float page = canvas_width * frames_per_unit;
3308 center_screen_internal (playhead_cursor->current_frame, page);
3312 Editor::center_edit_cursor ()
3314 float page = canvas_width * frames_per_unit;
3316 center_screen_internal (edit_cursor->current_frame, page);
3320 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
3322 begin_reversible_command (_("clear playlist"));
3323 XMLNode &before = playlist->get_state();
3325 XMLNode &after = playlist->get_state();
3326 session->add_command (new MementoCommand<Playlist>(*playlist.get(), &before, &after));
3327 commit_reversible_command ();
3331 Editor::nudge_track (bool use_edit_cursor, bool forwards)
3333 boost::shared_ptr<Playlist> playlist;
3335 nframes_t next_distance;
3338 if (use_edit_cursor) {
3339 start = edit_cursor->current_frame;
3344 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
3348 if (selection->tracks.empty()) {
3352 begin_reversible_command (_("nudge track"));
3354 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3356 if ((playlist = (*i)->playlist()) == 0) {
3360 XMLNode &before = playlist->get_state();
3361 playlist->nudge_after (start, distance, forwards);
3362 XMLNode &after = playlist->get_state();
3363 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
3366 commit_reversible_command ();
3370 Editor::remove_last_capture ()
3372 vector<string> choices;
3379 if (Config->get_verify_remove_last_capture()) {
3380 prompt = _("Do you really want to destroy the last capture?"
3381 "\n(This is destructive and cannot be undone)");
3383 choices.push_back (_("No, do nothing."));
3384 choices.push_back (_("Yes, destroy it."));
3386 Gtkmm2ext::Choice prompter (prompt, choices);
3388 if (prompter.run () == 1) {
3389 session->remove_last_capture ();
3393 session->remove_last_capture();
3398 Editor::normalize_region ()
3404 if (selection->regions.empty()) {
3408 begin_reversible_command (_("normalize"));
3410 track_canvas.get_window()->set_cursor (*wait_cursor);
3413 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
3414 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3417 XMLNode &before = arv->region()->get_state();
3418 arv->audio_region()->normalize_to (0.0f);
3419 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
3422 commit_reversible_command ();
3423 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3428 Editor::denormalize_region ()
3434 if (selection->regions.empty()) {
3438 begin_reversible_command ("denormalize");
3440 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
3441 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3444 XMLNode &before = arv->region()->get_state();
3445 arv->audio_region()->set_scale_amplitude (1.0f);
3446 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
3449 commit_reversible_command ();
3454 Editor::reverse_region ()
3460 Reverse rev (*session);
3461 apply_filter (rev, _("reverse regions"));
3465 Editor::apply_filter (AudioFilter& filter, string command)
3467 if (selection->regions.empty()) {
3471 begin_reversible_command (command);
3473 track_canvas.get_window()->set_cursor (*wait_cursor);
3476 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ) {
3477 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3481 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
3483 RegionSelection::iterator tmp;
3488 if (arv->audio_region()->apply (filter) == 0) {
3490 XMLNode &before = playlist->get_state();
3491 playlist->replace_region (arv->region(), filter.results.front(), arv->region()->position());
3492 XMLNode &after = playlist->get_state();
3493 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
3501 commit_reversible_command ();
3502 selection->regions.clear ();
3505 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3509 Editor::region_selection_op (void (Region::*pmf)(void))
3511 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3512 Region* region = (*i)->region().get();
3519 Editor::region_selection_op (void (Region::*pmf)(void*), void *arg)
3521 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3522 Region* region = (*i)->region().get();
3523 (region->*pmf)(arg);
3528 Editor::region_selection_op (void (Region::*pmf)(bool), bool yn)
3530 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3531 Region* region = (*i)->region().get();
3537 Editor::external_edit_region ()
3539 if (!clicked_regionview) {
3547 Editor::brush (nframes_t pos)
3549 RegionSelection sel;
3552 if (selection->regions.empty()) {
3553 /* XXX get selection from region list */
3555 sel = selection->regions;
3562 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3563 mouse_brush_insert_region ((*i), pos);
3568 Editor::reset_region_gain_envelopes ()
3570 if (!session || selection->regions.empty()) {
3574 session->begin_reversible_command (_("reset region gain"));
3576 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3577 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3579 AutomationList& alist (arv->audio_region()->envelope());
3580 XMLNode& before (alist.get_state());
3582 arv->audio_region()->set_default_envelope ();
3583 session->add_command (new MementoCommand<AutomationList>(arv->audio_region()->envelope(), &before, &alist.get_state()));
3587 session->commit_reversible_command ();
3591 Editor::toggle_gain_envelope_visibility ()
3593 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3594 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3596 bool x = region_envelope_visible_item->get_active();
3597 if (x != arv->envelope_visible()) {
3598 arv->set_envelope_visible (x);
3605 Editor::toggle_gain_envelope_active ()
3607 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3608 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3610 bool x = region_envelope_active_item->get_active();
3611 if (x != arv->audio_region()->envelope_active()) {
3612 arv->audio_region()->set_envelope_active (x);
3619 Editor::toggle_region_lock ()
3621 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3622 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3624 bool x = region_lock_item->get_active();
3625 if (x != arv->audio_region()->locked()) {
3626 arv->audio_region()->set_locked (x);
3633 Editor::toggle_region_mute ()
3635 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3636 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3638 bool x = region_mute_item->get_active();
3639 if (x != arv->audio_region()->muted()) {
3640 arv->audio_region()->set_muted (x);
3647 Editor::toggle_region_opaque ()
3649 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3650 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3652 bool x = region_opaque_item->get_active();
3653 if (x != arv->audio_region()->opaque()) {
3654 arv->audio_region()->set_opaque (x);