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.
20 /* Note: public Editor methods are documented in public_editor.h */
31 #include "pbd/error.h"
32 #include "pbd/basename.h"
33 #include "pbd/pthread_utils.h"
34 #include "pbd/memento_command.h"
35 #include "pbd/unwind.h"
36 #include "pbd/whitespace.h"
37 #include "pbd/stateful_diff_command.h"
39 #include <gtkmm2ext/utils.h>
40 #include <gtkmm2ext/choice.h>
41 #include <gtkmm2ext/popup.h>
43 #include "ardour/audio_track.h"
44 #include "ardour/audioregion.h"
45 #include "ardour/dB.h"
46 #include "ardour/location.h"
47 #include "ardour/midi_region.h"
48 #include "ardour/midi_track.h"
49 #include "ardour/operations.h"
50 #include "ardour/playlist_factory.h"
51 #include "ardour/profile.h"
52 #include "ardour/quantize.h"
53 #include "ardour/legatize.h"
54 #include "ardour/region_factory.h"
55 #include "ardour/reverse.h"
56 #include "ardour/session.h"
57 #include "ardour/session_playlists.h"
58 #include "ardour/strip_silence.h"
59 #include "ardour/transient_detector.h"
60 #include "ardour/transpose.h"
62 #include "canvas/canvas.h"
65 #include "audio_region_view.h"
66 #include "audio_streamview.h"
67 #include "audio_time_axis.h"
68 #include "automation_region_view.h"
69 #include "automation_time_axis.h"
70 #include "control_point.h"
74 #include "editor_cursors.h"
75 #include "editor_drag.h"
76 #include "editor_regions.h"
77 #include "editor_routes.h"
78 #include "gui_thread.h"
79 #include "insert_remove_time_dialog.h"
80 #include "interthread_progress_window.h"
81 #include "item_counts.h"
83 #include "midi_region_view.h"
84 #include "mixer_strip.h"
85 #include "mouse_cursors.h"
86 #include "normalize_dialog.h"
88 #include "paste_context.h"
89 #include "patch_change_dialog.h"
90 #include "quantize_dialog.h"
91 #include "region_gain_line.h"
92 #include "rgb_macros.h"
93 #include "route_time_axis.h"
94 #include "selection.h"
95 #include "selection_templates.h"
96 #include "streamview.h"
97 #include "strip_silence_dialog.h"
98 #include "time_axis_view.h"
100 #include "transpose_dialog.h"
101 #include "transform_dialog.h"
102 #include "ui_config.h"
107 using namespace ARDOUR;
110 using namespace Gtkmm2ext;
111 using namespace Editing;
112 using Gtkmm2ext::Keyboard;
114 /***********************************************************************
116 ***********************************************************************/
119 Editor::undo (uint32_t n)
121 if (_drags->active ()) {
127 if (_session->undo_depth() == 0) {
128 undo_action->set_sensitive(false);
130 redo_action->set_sensitive(true);
131 begin_selection_op_history ();
136 Editor::redo (uint32_t n)
138 if (_drags->active ()) {
144 if (_session->redo_depth() == 0) {
145 redo_action->set_sensitive(false);
147 undo_action->set_sensitive(true);
148 begin_selection_op_history ();
153 Editor::split_regions_at (framepos_t where, RegionSelection& regions)
157 RegionSelection pre_selected_regions = selection->regions;
158 bool working_on_selection = !pre_selected_regions.empty();
160 list<boost::shared_ptr<Playlist> > used_playlists;
161 list<RouteTimeAxisView*> used_trackviews;
163 if (regions.empty()) {
167 begin_reversible_command (_("split"));
169 // if splitting a single region, and snap-to is using
170 // region boundaries, don't pay attention to them
172 if (regions.size() == 1) {
173 switch (_snap_type) {
174 case SnapToRegionStart:
175 case SnapToRegionSync:
176 case SnapToRegionEnd:
185 EditorFreeze(); /* Emit Signal */
188 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
190 RegionSelection::iterator tmp;
192 /* XXX this test needs to be more complicated, to make sure we really
193 have something to split.
196 if (!(*a)->region()->covers (where)) {
204 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
212 /* we haven't seen this playlist before */
214 /* remember used playlists so we can thaw them later */
215 used_playlists.push_back(pl);
217 TimeAxisView& tv = (*a)->get_time_axis_view();
218 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
220 used_trackviews.push_back (rtv);
227 pl->clear_changes ();
228 pl->split_region ((*a)->region(), where);
229 _session->add_command (new StatefulDiffCommand (pl));
235 latest_regionviews.clear ();
237 vector<sigc::connection> region_added_connections;
239 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
240 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
243 while (used_playlists.size() > 0) {
244 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
246 used_playlists.pop_front();
249 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
254 EditorThaw(); /* Emit Signal */
257 if (working_on_selection) {
258 // IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
260 _ignore_follow_edits = true; // a split will change the region selection in mysterious ways; it's not practical or wanted to follow this edit
261 RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
262 /* There are three classes of regions that we might want selected after
263 splitting selected regions:
264 - regions selected before the split operation, and unaffected by it
265 - newly-created regions before the split
266 - newly-created regions after the split
269 if (rsas & Existing) {
270 // region selections that existed before the split.
271 selection->add ( pre_selected_regions );
274 for (RegionSelection::iterator ri = latest_regionviews.begin(); ri != latest_regionviews.end(); ri++) {
275 if ((*ri)->region()->position() < where) {
276 // new regions created before the split
277 if (rsas & NewlyCreatedLeft) {
278 selection->add (*ri);
281 // new regions created after the split
282 if (rsas & NewlyCreatedRight) {
283 selection->add (*ri);
287 _ignore_follow_edits = false;
289 _ignore_follow_edits = true;
290 if( working_on_selection ) {
291 selection->add (latest_regionviews); //these are the new regions created after the split
293 _ignore_follow_edits = false;
296 commit_reversible_command ();
299 /** Move one extreme of the current range selection. If more than one range is selected,
300 * the start of the earliest range or the end of the latest range is moved.
302 * @param move_end true to move the end of the current range selection, false to move
304 * @param next true to move the extreme to the next region boundary, false to move to
308 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
310 if (selection->time.start() == selection->time.end_frame()) {
314 framepos_t start = selection->time.start ();
315 framepos_t end = selection->time.end_frame ();
317 /* the position of the thing we may move */
318 framepos_t pos = move_end ? end : start;
319 int dir = next ? 1 : -1;
321 /* so we don't find the current region again */
322 if (dir > 0 || pos > 0) {
326 framepos_t const target = get_region_boundary (pos, dir, true, false);
341 begin_reversible_selection_op (_("alter selection"));
342 selection->set_preserving_all_ranges (start, end);
343 commit_reversible_selection_op ();
347 Editor::nudge_forward_release (GdkEventButton* ev)
349 if (ev->state & Keyboard::PrimaryModifier) {
350 nudge_forward (false, true);
352 nudge_forward (false, false);
358 Editor::nudge_backward_release (GdkEventButton* ev)
360 if (ev->state & Keyboard::PrimaryModifier) {
361 nudge_backward (false, true);
363 nudge_backward (false, false);
370 Editor::nudge_forward (bool next, bool force_playhead)
373 framepos_t next_distance;
379 RegionSelection rs = get_regions_from_selection_and_entered ();
381 if (!force_playhead && !rs.empty()) {
383 begin_reversible_command (_("nudge regions forward"));
385 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
386 boost::shared_ptr<Region> r ((*i)->region());
388 distance = get_nudge_distance (r->position(), next_distance);
391 distance = next_distance;
395 r->set_position (r->position() + distance);
396 _session->add_command (new StatefulDiffCommand (r));
399 commit_reversible_command ();
402 } else if (!force_playhead && !selection->markers.empty()) {
405 bool in_command = false;
407 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
409 Location* loc = find_location_from_marker ((*i), is_start);
413 XMLNode& before (loc->get_state());
416 distance = get_nudge_distance (loc->start(), next_distance);
418 distance = next_distance;
420 if (max_framepos - distance > loc->start() + loc->length()) {
421 loc->set_start (loc->start() + distance);
423 loc->set_start (max_framepos - loc->length());
426 distance = get_nudge_distance (loc->end(), next_distance);
428 distance = next_distance;
430 if (max_framepos - distance > loc->end()) {
431 loc->set_end (loc->end() + distance);
433 loc->set_end (max_framepos);
437 begin_reversible_command (_("nudge location forward"));
440 XMLNode& after (loc->get_state());
441 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
446 commit_reversible_command ();
449 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
450 _session->request_locate (playhead_cursor->current_frame () + distance);
455 Editor::nudge_backward (bool next, bool force_playhead)
458 framepos_t next_distance;
464 RegionSelection rs = get_regions_from_selection_and_entered ();
466 if (!force_playhead && !rs.empty()) {
468 begin_reversible_command (_("nudge regions backward"));
470 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
471 boost::shared_ptr<Region> r ((*i)->region());
473 distance = get_nudge_distance (r->position(), next_distance);
476 distance = next_distance;
481 if (r->position() > distance) {
482 r->set_position (r->position() - distance);
486 _session->add_command (new StatefulDiffCommand (r));
489 commit_reversible_command ();
491 } else if (!force_playhead && !selection->markers.empty()) {
494 bool in_command = false;
496 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
498 Location* loc = find_location_from_marker ((*i), is_start);
502 XMLNode& before (loc->get_state());
505 distance = get_nudge_distance (loc->start(), next_distance);
507 distance = next_distance;
509 if (distance < loc->start()) {
510 loc->set_start (loc->start() - distance);
515 distance = get_nudge_distance (loc->end(), next_distance);
518 distance = next_distance;
521 if (distance < loc->end() - loc->length()) {
522 loc->set_end (loc->end() - distance);
524 loc->set_end (loc->length());
528 begin_reversible_command (_("nudge location forward"));
531 XMLNode& after (loc->get_state());
532 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
536 commit_reversible_command ();
541 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
543 if (playhead_cursor->current_frame () > distance) {
544 _session->request_locate (playhead_cursor->current_frame () - distance);
546 _session->goto_start();
552 Editor::nudge_forward_capture_offset ()
554 RegionSelection rs = get_regions_from_selection_and_entered ();
556 if (!_session || rs.empty()) {
560 begin_reversible_command (_("nudge forward"));
562 framepos_t const distance = _session->worst_output_latency();
564 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
565 boost::shared_ptr<Region> r ((*i)->region());
568 r->set_position (r->position() + distance);
569 _session->add_command(new StatefulDiffCommand (r));
572 commit_reversible_command ();
576 Editor::nudge_backward_capture_offset ()
578 RegionSelection rs = get_regions_from_selection_and_entered ();
580 if (!_session || rs.empty()) {
584 begin_reversible_command (_("nudge backward"));
586 framepos_t const distance = _session->worst_output_latency();
588 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
589 boost::shared_ptr<Region> r ((*i)->region());
593 if (r->position() > distance) {
594 r->set_position (r->position() - distance);
598 _session->add_command(new StatefulDiffCommand (r));
601 commit_reversible_command ();
604 struct RegionSelectionPositionSorter {
605 bool operator() (RegionView* a, RegionView* b) {
606 return a->region()->position() < b->region()->position();
611 Editor::sequence_regions ()
614 framepos_t r_end_prev;
622 RegionSelection rs = get_regions_from_selection_and_entered ();
623 rs.sort(RegionSelectionPositionSorter());
627 bool in_command = false;
629 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
630 boost::shared_ptr<Region> r ((*i)->region());
638 if(r->position_locked())
645 r->set_position(r_end_prev);
649 begin_reversible_command (_("sequence regions"));
652 _session->add_command (new StatefulDiffCommand (r));
654 r_end=r->position() + r->length();
660 commit_reversible_command ();
669 Editor::move_to_start ()
671 _session->goto_start ();
675 Editor::move_to_end ()
678 _session->request_locate (_session->current_end_frame());
682 Editor::build_region_boundary_cache ()
685 vector<RegionPoint> interesting_points;
686 boost::shared_ptr<Region> r;
687 TrackViewList tracks;
690 region_boundary_cache.clear ();
696 switch (_snap_type) {
697 case SnapToRegionStart:
698 interesting_points.push_back (Start);
700 case SnapToRegionEnd:
701 interesting_points.push_back (End);
703 case SnapToRegionSync:
704 interesting_points.push_back (SyncPoint);
706 case SnapToRegionBoundary:
707 interesting_points.push_back (Start);
708 interesting_points.push_back (End);
711 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
712 abort(); /*NOTREACHED*/
716 TimeAxisView *ontrack = 0;
719 if (!selection->tracks.empty()) {
720 tlist = selection->tracks.filter_to_unique_playlists ();
722 tlist = track_views.filter_to_unique_playlists ();
725 while (pos < _session->current_end_frame() && !at_end) {
728 framepos_t lpos = max_framepos;
730 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
732 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
733 if (*p == interesting_points.back()) {
736 /* move to next point type */
742 rpos = r->first_frame();
746 rpos = r->last_frame();
750 rpos = r->sync_position ();
758 RouteTimeAxisView *rtav;
760 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
761 if (rtav->track() != 0) {
762 speed = rtav->track()->speed();
766 rpos = track_frame_to_session_frame (rpos, speed);
772 /* prevent duplicates, but we don't use set<> because we want to be able
776 vector<framepos_t>::iterator ri;
778 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
784 if (ri == region_boundary_cache.end()) {
785 region_boundary_cache.push_back (rpos);
792 /* finally sort to be sure that the order is correct */
794 sort (region_boundary_cache.begin(), region_boundary_cache.end());
797 boost::shared_ptr<Region>
798 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
800 TrackViewList::iterator i;
801 framepos_t closest = max_framepos;
802 boost::shared_ptr<Region> ret;
806 framepos_t track_frame;
807 RouteTimeAxisView *rtav;
809 for (i = tracks.begin(); i != tracks.end(); ++i) {
812 boost::shared_ptr<Region> r;
815 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
816 if (rtav->track()!=0)
817 track_speed = rtav->track()->speed();
820 track_frame = session_frame_to_track_frame(frame, track_speed);
822 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
828 rpos = r->first_frame ();
832 rpos = r->last_frame ();
836 rpos = r->sync_position ();
840 // rpos is a "track frame", converting it to "_session frame"
841 rpos = track_frame_to_session_frame(rpos, track_speed);
844 distance = rpos - frame;
846 distance = frame - rpos;
849 if (distance < closest) {
861 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
863 framecnt_t distance = max_framepos;
864 framepos_t current_nearest = -1;
866 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
867 framepos_t contender;
870 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
876 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
880 d = ::llabs (pos - contender);
883 current_nearest = contender;
888 return current_nearest;
892 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
897 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
899 if (!selection->tracks.empty()) {
901 target = find_next_region_boundary (pos, dir, selection->tracks);
905 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
906 get_onscreen_tracks (tvl);
907 target = find_next_region_boundary (pos, dir, tvl);
909 target = find_next_region_boundary (pos, dir, track_views);
915 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
916 get_onscreen_tracks (tvl);
917 target = find_next_region_boundary (pos, dir, tvl);
919 target = find_next_region_boundary (pos, dir, track_views);
927 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
929 framepos_t pos = playhead_cursor->current_frame ();
936 // so we don't find the current region again..
937 if (dir > 0 || pos > 0) {
941 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
945 _session->request_locate (target);
949 Editor::cursor_to_next_region_boundary (bool with_selection)
951 cursor_to_region_boundary (with_selection, 1);
955 Editor::cursor_to_previous_region_boundary (bool with_selection)
957 cursor_to_region_boundary (with_selection, -1);
961 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
963 boost::shared_ptr<Region> r;
964 framepos_t pos = cursor->current_frame ();
970 TimeAxisView *ontrack = 0;
972 // so we don't find the current region again..
976 if (!selection->tracks.empty()) {
978 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
980 } else if (clicked_axisview) {
983 t.push_back (clicked_axisview);
985 r = find_next_region (pos, point, dir, t, &ontrack);
989 r = find_next_region (pos, point, dir, track_views, &ontrack);
998 pos = r->first_frame ();
1002 pos = r->last_frame ();
1006 pos = r->sync_position ();
1011 RouteTimeAxisView *rtav;
1013 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
1014 if (rtav->track() != 0) {
1015 speed = rtav->track()->speed();
1019 pos = track_frame_to_session_frame(pos, speed);
1021 if (cursor == playhead_cursor) {
1022 _session->request_locate (pos);
1024 cursor->set_position (pos);
1029 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
1031 cursor_to_region_point (cursor, point, 1);
1035 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
1037 cursor_to_region_point (cursor, point, -1);
1041 Editor::cursor_to_selection_start (EditorCursor *cursor)
1045 switch (mouse_mode) {
1047 if (!selection->regions.empty()) {
1048 pos = selection->regions.start();
1053 if (!selection->time.empty()) {
1054 pos = selection->time.start ();
1062 if (cursor == playhead_cursor) {
1063 _session->request_locate (pos);
1065 cursor->set_position (pos);
1070 Editor::cursor_to_selection_end (EditorCursor *cursor)
1074 switch (mouse_mode) {
1076 if (!selection->regions.empty()) {
1077 pos = selection->regions.end_frame();
1082 if (!selection->time.empty()) {
1083 pos = selection->time.end_frame ();
1091 if (cursor == playhead_cursor) {
1092 _session->request_locate (pos);
1094 cursor->set_position (pos);
1099 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1109 if (selection->markers.empty()) {
1113 if (!mouse_frame (mouse, ignored)) {
1117 add_location_mark (mouse);
1120 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1124 framepos_t pos = loc->start();
1126 // so we don't find the current region again..
1127 if (dir > 0 || pos > 0) {
1131 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1135 loc->move_to (target);
1139 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1141 selected_marker_to_region_boundary (with_selection, 1);
1145 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1147 selected_marker_to_region_boundary (with_selection, -1);
1151 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1153 boost::shared_ptr<Region> r;
1158 if (!_session || selection->markers.empty()) {
1162 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1166 TimeAxisView *ontrack = 0;
1170 // so we don't find the current region again..
1174 if (!selection->tracks.empty()) {
1176 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1180 r = find_next_region (pos, point, dir, track_views, &ontrack);
1189 pos = r->first_frame ();
1193 pos = r->last_frame ();
1197 pos = r->adjust_to_sync (r->first_frame());
1202 RouteTimeAxisView *rtav;
1204 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1205 if (rtav->track() != 0) {
1206 speed = rtav->track()->speed();
1210 pos = track_frame_to_session_frame(pos, speed);
1216 Editor::selected_marker_to_next_region_point (RegionPoint point)
1218 selected_marker_to_region_point (point, 1);
1222 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1224 selected_marker_to_region_point (point, -1);
1228 Editor::selected_marker_to_selection_start ()
1234 if (!_session || selection->markers.empty()) {
1238 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1242 switch (mouse_mode) {
1244 if (!selection->regions.empty()) {
1245 pos = selection->regions.start();
1250 if (!selection->time.empty()) {
1251 pos = selection->time.start ();
1263 Editor::selected_marker_to_selection_end ()
1269 if (!_session || selection->markers.empty()) {
1273 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1277 switch (mouse_mode) {
1279 if (!selection->regions.empty()) {
1280 pos = selection->regions.end_frame();
1285 if (!selection->time.empty()) {
1286 pos = selection->time.end_frame ();
1298 Editor::scroll_playhead (bool forward)
1300 framepos_t pos = playhead_cursor->current_frame ();
1301 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1304 if (pos == max_framepos) {
1308 if (pos < max_framepos - delta) {
1327 _session->request_locate (pos);
1331 Editor::cursor_align (bool playhead_to_edit)
1337 if (playhead_to_edit) {
1339 if (selection->markers.empty()) {
1343 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1346 /* move selected markers to playhead */
1348 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1351 Location* loc = find_location_from_marker (*i, ignored);
1353 if (loc->is_mark()) {
1354 loc->set_start (playhead_cursor->current_frame ());
1356 loc->set (playhead_cursor->current_frame (),
1357 playhead_cursor->current_frame () + loc->length());
1364 Editor::scroll_backward (float pages)
1366 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1367 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1370 if (leftmost_frame < cnt) {
1373 frame = leftmost_frame - cnt;
1376 reset_x_origin (frame);
1380 Editor::scroll_forward (float pages)
1382 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1383 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1386 if (max_framepos - cnt < leftmost_frame) {
1387 frame = max_framepos - cnt;
1389 frame = leftmost_frame + cnt;
1392 reset_x_origin (frame);
1396 Editor::scroll_tracks_down ()
1398 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1399 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1400 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1403 vertical_adjustment.set_value (vert_value);
1407 Editor::scroll_tracks_up ()
1409 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1413 Editor::scroll_tracks_down_line ()
1415 double vert_value = vertical_adjustment.get_value() + 60;
1417 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1418 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1421 vertical_adjustment.set_value (vert_value);
1425 Editor::scroll_tracks_up_line ()
1427 reset_y_origin (vertical_adjustment.get_value() - 60);
1431 Editor::scroll_down_one_track (bool skip_child_views)
1433 TrackViewList::reverse_iterator next = track_views.rend();
1434 const double top_of_trackviews = vertical_adjustment.get_value();
1436 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1437 if ((*t)->hidden()) {
1441 /* If this is the upper-most visible trackview, we want to display
1442 * the one above it (next)
1444 * Note that covers_y_position() is recursive and includes child views
1446 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1449 if (skip_child_views) {
1452 /* automation lane (one level, non-recursive)
1454 * - if no automation lane exists -> move to next tack
1455 * - if the first (here: bottom-most) matches -> move to next tack
1456 * - if no y-axis match is found -> the current track is at the top
1457 * -> move to last (here: top-most) automation lane
1459 TimeAxisView::Children kids = (*t)->get_child_list();
1460 TimeAxisView::Children::reverse_iterator nkid = kids.rend();
1462 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1463 if ((*ci)->hidden()) {
1467 std::pair<TimeAxisView*,double> dev;
1468 dev = (*ci)->covers_y_position (top_of_trackviews);
1470 /* some automation lane is currently at the top */
1471 if (ci == kids.rbegin()) {
1472 /* first (bottom-most) autmation lane is at the top.
1473 * -> move to next track
1482 if (nkid != kids.rend()) {
1483 ensure_time_axis_view_is_visible (**nkid, true);
1491 /* move to the track below the first one that covers the */
1493 if (next != track_views.rend()) {
1494 ensure_time_axis_view_is_visible (**next, true);
1502 Editor::scroll_up_one_track (bool skip_child_views)
1504 TrackViewList::iterator prev = track_views.end();
1505 double top_of_trackviews = vertical_adjustment.get_value ();
1507 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1509 if ((*t)->hidden()) {
1513 /* find the trackview at the top of the trackview group
1515 * Note that covers_y_position() is recursive and includes child views
1517 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1520 if (skip_child_views) {
1523 /* automation lane (one level, non-recursive)
1525 * - if no automation lane exists -> move to prev tack
1526 * - if no y-axis match is found -> the current track is at the top -> move to prev track
1527 * (actually last automation lane of previous track, see below)
1528 * - if first (top-most) lane is at the top -> move to this track
1529 * - else move up one lane
1531 TimeAxisView::Children kids = (*t)->get_child_list();
1532 TimeAxisView::Children::iterator pkid = kids.end();
1534 for (TimeAxisView::Children::iterator ci = kids.begin(); ci != kids.end(); ++ci) {
1535 if ((*ci)->hidden()) {
1539 std::pair<TimeAxisView*,double> dev;
1540 dev = (*ci)->covers_y_position (top_of_trackviews);
1542 /* some automation lane is currently at the top */
1543 if (ci == kids.begin()) {
1544 /* first (top-most) autmation lane is at the top.
1545 * jump directly to this track's top
1547 ensure_time_axis_view_is_visible (**t, true);
1550 else if (pkid != kids.end()) {
1551 /* some other automation lane is at the top.
1552 * move up to prev automation lane.
1554 ensure_time_axis_view_is_visible (**pkid, true);
1557 assert(0); // not reached
1568 if (prev != track_views.end()) {
1569 // move to bottom-most automation-lane of the previous track
1570 TimeAxisView::Children kids = (*prev)->get_child_list();
1571 TimeAxisView::Children::reverse_iterator pkid = kids.rend();
1572 if (!skip_child_views) {
1573 // find the last visible lane
1574 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1575 if (!(*ci)->hidden()) {
1581 if (pkid != kids.rend()) {
1582 ensure_time_axis_view_is_visible (**pkid, true);
1584 ensure_time_axis_view_is_visible (**prev, true);
1595 Editor::tav_zoom_step (bool coarser)
1597 DisplaySuspender ds;
1601 if (selection->tracks.empty()) {
1604 ts = &selection->tracks;
1607 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1608 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1609 tv->step_height (coarser);
1614 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1616 DisplaySuspender ds;
1620 if (selection->tracks.empty() || force_all) {
1623 ts = &selection->tracks;
1626 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1627 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1628 uint32_t h = tv->current_height ();
1633 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1638 tv->set_height (h + 5);
1645 Editor::temporal_zoom_step (bool coarser)
1647 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1649 framecnt_t nspp = samples_per_pixel;
1657 temporal_zoom (nspp);
1661 Editor::temporal_zoom (framecnt_t fpp)
1667 framepos_t current_page = current_page_samples();
1668 framepos_t current_leftmost = leftmost_frame;
1669 framepos_t current_rightmost;
1670 framepos_t current_center;
1671 framepos_t new_page_size;
1672 framepos_t half_page_size;
1673 framepos_t leftmost_after_zoom = 0;
1675 bool in_track_canvas;
1679 if (fpp == samples_per_pixel) {
1683 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1684 // segfaults for lack of memory. If somebody decides this is not high enough I
1685 // believe it can be raisen to higher values but some limit must be in place.
1687 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1688 // all of which is used for the editor track displays. The whole day
1689 // would be 4147200000 samples, so 2592000 samples per pixel.
1691 nfpp = min (fpp, (framecnt_t) 2592000);
1692 nfpp = max ((framecnt_t) 1, nfpp);
1694 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1695 half_page_size = new_page_size / 2;
1697 switch (zoom_focus) {
1699 leftmost_after_zoom = current_leftmost;
1702 case ZoomFocusRight:
1703 current_rightmost = leftmost_frame + current_page;
1704 if (current_rightmost < new_page_size) {
1705 leftmost_after_zoom = 0;
1707 leftmost_after_zoom = current_rightmost - new_page_size;
1711 case ZoomFocusCenter:
1712 current_center = current_leftmost + (current_page/2);
1713 if (current_center < half_page_size) {
1714 leftmost_after_zoom = 0;
1716 leftmost_after_zoom = current_center - half_page_size;
1720 case ZoomFocusPlayhead:
1721 /* centre playhead */
1722 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1725 leftmost_after_zoom = 0;
1726 } else if (l > max_framepos) {
1727 leftmost_after_zoom = max_framepos - new_page_size;
1729 leftmost_after_zoom = (framepos_t) l;
1733 case ZoomFocusMouse:
1734 /* try to keep the mouse over the same point in the display */
1736 if (!mouse_frame (where, in_track_canvas)) {
1737 /* use playhead instead */
1738 where = playhead_cursor->current_frame ();
1740 if (where < half_page_size) {
1741 leftmost_after_zoom = 0;
1743 leftmost_after_zoom = where - half_page_size;
1748 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1751 leftmost_after_zoom = 0;
1752 } else if (l > max_framepos) {
1753 leftmost_after_zoom = max_framepos - new_page_size;
1755 leftmost_after_zoom = (framepos_t) l;
1762 /* try to keep the edit point in the same place */
1763 where = get_preferred_edit_position ();
1767 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1770 leftmost_after_zoom = 0;
1771 } else if (l > max_framepos) {
1772 leftmost_after_zoom = max_framepos - new_page_size;
1774 leftmost_after_zoom = (framepos_t) l;
1778 /* edit point not defined */
1785 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1787 reposition_and_zoom (leftmost_after_zoom, nfpp);
1791 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1793 /* this func helps make sure we leave a little space
1794 at each end of the editor so that the zoom doesn't fit the region
1795 precisely to the screen.
1798 GdkScreen* screen = gdk_screen_get_default ();
1799 const gint pixwidth = gdk_screen_get_width (screen);
1800 const gint mmwidth = gdk_screen_get_width_mm (screen);
1801 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1802 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1804 const framepos_t range = end - start;
1805 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1806 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1808 if (start > extra_samples) {
1809 start -= extra_samples;
1814 if (max_framepos - extra_samples > end) {
1815 end += extra_samples;
1822 Editor::temporal_zoom_region (bool both_axes)
1824 framepos_t start = max_framepos;
1826 set<TimeAxisView*> tracks;
1828 if ( !get_selection_extents(start, end) )
1831 calc_extra_zoom_edges (start, end);
1833 /* if we're zooming on both axes we need to save track heights etc.
1836 undo_visual_stack.push_back (current_visual_state (both_axes));
1838 PBD::Unwinder<bool> nsv (no_save_visual, true);
1840 temporal_zoom_by_frame (start, end);
1843 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1845 /* set visible track heights appropriately */
1847 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1848 (*t)->set_height (per_track_height);
1851 /* hide irrelevant tracks */
1853 DisplaySuspender ds;
1855 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1856 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1857 hide_track_in_display (*i);
1861 vertical_adjustment.set_value (0.0);
1864 redo_visual_stack.push_back (current_visual_state (both_axes));
1869 Editor::get_selection_extents ( framepos_t &start, framepos_t &end )
1871 start = max_framepos;
1875 //ToDo: if notes are selected, set extents to that selection
1877 //ToDo: if control points are selected, set extents to that selection
1879 if ( !selection->regions.empty() ) {
1880 RegionSelection rs = get_regions_from_selection_and_entered ();
1882 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1884 if ((*i)->region()->position() < start) {
1885 start = (*i)->region()->position();
1888 if ((*i)->region()->last_frame() + 1 > end) {
1889 end = (*i)->region()->last_frame() + 1;
1893 } else if (!selection->time.empty()) {
1894 start = selection->time.start();
1895 end = selection->time.end_frame();
1897 ret = false; //no selection found
1900 if ((start == 0 && end == 0) || end < start) {
1909 Editor::temporal_zoom_selection (bool both_axes)
1911 if (!selection) return;
1913 //ToDo: if notes are selected, zoom to that
1915 //ToDo: if control points are selected, zoom to that
1917 //if region(s) are selected, zoom to that
1918 if ( !selection->regions.empty() )
1919 temporal_zoom_region (both_axes);
1921 //if a range is selected, zoom to that
1922 if (!selection->time.empty()) {
1924 framepos_t start, end;
1925 if (get_selection_extents (start, end)) {
1926 calc_extra_zoom_edges(start, end);
1927 temporal_zoom_by_frame (start, end);
1937 Editor::temporal_zoom_session ()
1939 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1942 framecnt_t start = _session->current_start_frame();
1943 framecnt_t end = _session->current_end_frame();
1945 if (_session->actively_recording () ) {
1946 framepos_t cur = playhead_cursor->current_frame ();
1948 /* recording beyond the end marker; zoom out
1949 * by 5 seconds more so that if 'follow
1950 * playhead' is active we don't immediately
1953 end = cur + _session->frame_rate() * 5;
1957 if ((start == 0 && end == 0) || end < start) {
1961 calc_extra_zoom_edges(start, end);
1963 temporal_zoom_by_frame (start, end);
1968 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1970 if (!_session) return;
1972 if ((start == 0 && end == 0) || end < start) {
1976 framepos_t range = end - start;
1978 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1980 framepos_t new_page = range;
1981 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1982 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1984 if (new_leftmost > middle) {
1988 if (new_leftmost < 0) {
1992 reposition_and_zoom (new_leftmost, new_fpp);
1996 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
2002 framecnt_t range_before = frame - leftmost_frame;
2006 if (samples_per_pixel <= 1) {
2009 new_spp = samples_per_pixel + (samples_per_pixel/2);
2011 range_before += range_before/2;
2013 if (samples_per_pixel >= 1) {
2014 new_spp = samples_per_pixel - (samples_per_pixel/2);
2016 /* could bail out here since we cannot zoom any finer,
2017 but leave that to the equality test below
2019 new_spp = samples_per_pixel;
2022 range_before -= range_before/2;
2025 if (new_spp == samples_per_pixel) {
2029 /* zoom focus is automatically taken as @param frame when this
2033 framepos_t new_leftmost = frame - (framepos_t)range_before;
2035 if (new_leftmost > frame) {
2039 if (new_leftmost < 0) {
2043 reposition_and_zoom (new_leftmost, new_spp);
2048 Editor::choose_new_marker_name(string &name) {
2050 if (!UIConfiguration::instance().get_name_new_markers()) {
2051 /* don't prompt user for a new name */
2055 ArdourPrompter dialog (true);
2057 dialog.set_prompt (_("New Name:"));
2059 dialog.set_title (_("New Location Marker"));
2061 dialog.set_name ("MarkNameWindow");
2062 dialog.set_size_request (250, -1);
2063 dialog.set_position (Gtk::WIN_POS_MOUSE);
2065 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
2066 dialog.set_initial_text (name);
2070 switch (dialog.run ()) {
2071 case RESPONSE_ACCEPT:
2077 dialog.get_result(name);
2084 Editor::add_location_from_selection ()
2088 if (selection->time.empty()) {
2092 if (_session == 0 || clicked_axisview == 0) {
2096 framepos_t start = selection->time[clicked_selection].start;
2097 framepos_t end = selection->time[clicked_selection].end;
2099 _session->locations()->next_available_name(rangename,"selection");
2100 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
2102 begin_reversible_command (_("add marker"));
2104 XMLNode &before = _session->locations()->get_state();
2105 _session->locations()->add (location, true);
2106 XMLNode &after = _session->locations()->get_state();
2107 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2109 commit_reversible_command ();
2113 Editor::add_location_mark (framepos_t where)
2117 select_new_marker = true;
2119 _session->locations()->next_available_name(markername,"mark");
2120 if (!choose_new_marker_name(markername)) {
2123 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
2124 begin_reversible_command (_("add marker"));
2126 XMLNode &before = _session->locations()->get_state();
2127 _session->locations()->add (location, true);
2128 XMLNode &after = _session->locations()->get_state();
2129 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2131 commit_reversible_command ();
2135 Editor::set_session_start_from_playhead ()
2141 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2142 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2144 XMLNode &before = loc->get_state();
2146 _session->set_session_extents ( _session->audible_frame(), loc->end() );
2148 XMLNode &after = loc->get_state();
2150 begin_reversible_command (_("Set session start"));
2152 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2154 commit_reversible_command ();
2159 Editor::set_session_end_from_playhead ()
2165 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2166 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2168 XMLNode &before = loc->get_state();
2170 _session->set_session_extents ( loc->start(), _session->audible_frame() );
2172 XMLNode &after = loc->get_state();
2174 begin_reversible_command (_("Set session start"));
2176 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2178 commit_reversible_command ();
2183 Editor::add_location_from_playhead_cursor ()
2185 add_location_mark (_session->audible_frame());
2189 Editor::remove_location_at_playhead_cursor ()
2193 XMLNode &before = _session->locations()->get_state();
2194 bool removed = false;
2196 //find location(s) at this time
2197 Locations::LocationList locs;
2198 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2199 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2200 if ((*i)->is_mark()) {
2201 _session->locations()->remove (*i);
2208 begin_reversible_command (_("remove marker"));
2209 XMLNode &after = _session->locations()->get_state();
2210 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2211 commit_reversible_command ();
2216 /** Add a range marker around each selected region */
2218 Editor::add_locations_from_region ()
2220 RegionSelection rs = get_regions_from_selection_and_entered ();
2225 bool commit = false;
2227 XMLNode &before = _session->locations()->get_state();
2229 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2231 boost::shared_ptr<Region> region = (*i)->region ();
2233 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2235 _session->locations()->add (location, true);
2240 begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2241 XMLNode &after = _session->locations()->get_state();
2242 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2243 commit_reversible_command ();
2247 /** Add a single range marker around all selected regions */
2249 Editor::add_location_from_region ()
2251 RegionSelection rs = get_regions_from_selection_and_entered ();
2257 XMLNode &before = _session->locations()->get_state();
2261 if (rs.size() > 1) {
2262 _session->locations()->next_available_name(markername, "regions");
2264 RegionView* rv = *(rs.begin());
2265 boost::shared_ptr<Region> region = rv->region();
2266 markername = region->name();
2269 if (!choose_new_marker_name(markername)) {
2273 // single range spanning all selected
2274 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2275 _session->locations()->add (location, true);
2277 begin_reversible_command (_("add marker"));
2278 XMLNode &after = _session->locations()->get_state();
2279 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2280 commit_reversible_command ();
2286 Editor::jump_forward_to_mark ()
2292 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2298 _session->request_locate (pos, _session->transport_rolling());
2302 Editor::jump_backward_to_mark ()
2308 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2314 _session->request_locate (pos, _session->transport_rolling());
2320 framepos_t const pos = _session->audible_frame ();
2323 _session->locations()->next_available_name (markername, "mark");
2325 if (!choose_new_marker_name (markername)) {
2329 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2333 Editor::clear_markers ()
2336 begin_reversible_command (_("clear markers"));
2338 XMLNode &before = _session->locations()->get_state();
2339 _session->locations()->clear_markers ();
2340 XMLNode &after = _session->locations()->get_state();
2341 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2343 commit_reversible_command ();
2348 Editor::clear_ranges ()
2351 begin_reversible_command (_("clear ranges"));
2353 XMLNode &before = _session->locations()->get_state();
2355 _session->locations()->clear_ranges ();
2357 XMLNode &after = _session->locations()->get_state();
2358 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2360 commit_reversible_command ();
2365 Editor::clear_locations ()
2367 begin_reversible_command (_("clear locations"));
2369 XMLNode &before = _session->locations()->get_state();
2370 _session->locations()->clear ();
2371 XMLNode &after = _session->locations()->get_state();
2372 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2374 commit_reversible_command ();
2378 Editor::unhide_markers ()
2380 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2381 Location *l = (*i).first;
2382 if (l->is_hidden() && l->is_mark()) {
2383 l->set_hidden(false, this);
2389 Editor::unhide_ranges ()
2391 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2392 Location *l = (*i).first;
2393 if (l->is_hidden() && l->is_range_marker()) {
2394 l->set_hidden(false, this);
2399 /* INSERT/REPLACE */
2402 Editor::insert_region_list_selection (float times)
2404 RouteTimeAxisView *tv = 0;
2405 boost::shared_ptr<Playlist> playlist;
2407 if (clicked_routeview != 0) {
2408 tv = clicked_routeview;
2409 } else if (!selection->tracks.empty()) {
2410 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2413 } else if (entered_track != 0) {
2414 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2421 if ((playlist = tv->playlist()) == 0) {
2425 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2430 begin_reversible_command (_("insert region"));
2431 playlist->clear_changes ();
2432 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2433 if (Config->get_edit_mode() == Ripple)
2434 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2436 _session->add_command(new StatefulDiffCommand (playlist));
2437 commit_reversible_command ();
2440 /* BUILT-IN EFFECTS */
2443 Editor::reverse_selection ()
2448 /* GAIN ENVELOPE EDITING */
2451 Editor::edit_envelope ()
2458 Editor::transition_to_rolling (bool fwd)
2464 if (_session->config.get_external_sync()) {
2465 switch (Config->get_sync_source()) {
2469 /* transport controlled by the master */
2474 if (_session->is_auditioning()) {
2475 _session->cancel_audition ();
2479 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2483 Editor::play_from_start ()
2485 _session->request_locate (_session->current_start_frame(), true);
2489 Editor::play_from_edit_point ()
2491 _session->request_locate (get_preferred_edit_position(), true);
2495 Editor::play_from_edit_point_and_return ()
2497 framepos_t start_frame;
2498 framepos_t return_frame;
2500 start_frame = get_preferred_edit_position ( EDIT_IGNORE_PHEAD );
2502 if (_session->transport_rolling()) {
2503 _session->request_locate (start_frame, false);
2507 /* don't reset the return frame if its already set */
2509 if ((return_frame = _session->requested_return_frame()) < 0) {
2510 return_frame = _session->audible_frame();
2513 if (start_frame >= 0) {
2514 _session->request_roll_at_and_return (start_frame, return_frame);
2519 Editor::play_selection ()
2521 framepos_t start, end;
2522 if (!get_selection_extents ( start, end))
2525 AudioRange ar (start, end, 0);
2526 list<AudioRange> lar;
2529 _session->request_play_range (&lar, true);
2533 Editor::get_preroll ()
2535 return Config->get_preroll_seconds() * _session->frame_rate();
2540 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2542 if ( _session->transport_rolling() || !UIConfiguration::instance().get_follow_edits() || _ignore_follow_edits || _session->config.get_external_sync() )
2545 location -= get_preroll();
2547 //don't try to locate before the beginning of time
2551 //if follow_playhead is on, keep the playhead on the screen
2552 if ( _follow_playhead )
2553 if ( location < leftmost_frame )
2554 location = leftmost_frame;
2556 _session->request_locate( location );
2560 Editor::play_with_preroll ()
2563 framepos_t preroll = get_preroll();
2565 framepos_t start, end;
2566 if (!get_selection_extents ( start, end))
2569 if (start > preroll)
2570 start = start - preroll;
2572 end = end + preroll; //"post-roll"
2574 AudioRange ar (start, end, 0);
2575 list<AudioRange> lar;
2578 _session->request_play_range (&lar, true);
2583 Editor::play_location (Location& location)
2585 if (location.start() <= location.end()) {
2589 _session->request_bounded_roll (location.start(), location.end());
2593 Editor::loop_location (Location& location)
2595 if (location.start() <= location.end()) {
2601 if ((tll = transport_loop_location()) != 0) {
2602 tll->set (location.start(), location.end());
2604 // enable looping, reposition and start rolling
2605 _session->request_locate (tll->start(), true);
2606 _session->request_play_loop (true);
2611 Editor::do_layer_operation (LayerOperation op)
2613 if (selection->regions.empty ()) {
2617 bool const multiple = selection->regions.size() > 1;
2621 begin_reversible_command (_("raise regions"));
2623 begin_reversible_command (_("raise region"));
2629 begin_reversible_command (_("raise regions to top"));
2631 begin_reversible_command (_("raise region to top"));
2637 begin_reversible_command (_("lower regions"));
2639 begin_reversible_command (_("lower region"));
2645 begin_reversible_command (_("lower regions to bottom"));
2647 begin_reversible_command (_("lower region"));
2652 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2653 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2654 (*i)->clear_owned_changes ();
2657 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2658 boost::shared_ptr<Region> r = (*i)->region ();
2670 r->lower_to_bottom ();
2674 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2675 vector<Command*> cmds;
2677 _session->add_commands (cmds);
2680 commit_reversible_command ();
2684 Editor::raise_region ()
2686 do_layer_operation (Raise);
2690 Editor::raise_region_to_top ()
2692 do_layer_operation (RaiseToTop);
2696 Editor::lower_region ()
2698 do_layer_operation (Lower);
2702 Editor::lower_region_to_bottom ()
2704 do_layer_operation (LowerToBottom);
2707 /** Show the region editor for the selected regions */
2709 Editor::show_region_properties ()
2711 selection->foreach_regionview (&RegionView::show_region_editor);
2714 /** Show the midi list editor for the selected MIDI regions */
2716 Editor::show_midi_list_editor ()
2718 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2722 Editor::rename_region ()
2724 RegionSelection rs = get_regions_from_selection_and_entered ();
2730 ArdourDialog d (*this, _("Rename Region"), true, false);
2732 Label label (_("New name:"));
2735 hbox.set_spacing (6);
2736 hbox.pack_start (label, false, false);
2737 hbox.pack_start (entry, true, true);
2739 d.get_vbox()->set_border_width (12);
2740 d.get_vbox()->pack_start (hbox, false, false);
2742 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2743 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2745 d.set_size_request (300, -1);
2747 entry.set_text (rs.front()->region()->name());
2748 entry.select_region (0, -1);
2750 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2756 int const ret = d.run();
2760 if (ret != RESPONSE_OK) {
2764 std::string str = entry.get_text();
2765 strip_whitespace_edges (str);
2767 rs.front()->region()->set_name (str);
2768 _regions->redisplay ();
2772 /** Start an audition of the first selected region */
2774 Editor::play_edit_range ()
2776 framepos_t start, end;
2778 if (get_edit_op_range (start, end)) {
2779 _session->request_bounded_roll (start, end);
2784 Editor::play_selected_region ()
2786 framepos_t start = max_framepos;
2789 RegionSelection rs = get_regions_from_selection_and_entered ();
2795 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2796 if ((*i)->region()->position() < start) {
2797 start = (*i)->region()->position();
2799 if ((*i)->region()->last_frame() + 1 > end) {
2800 end = (*i)->region()->last_frame() + 1;
2804 _session->request_bounded_roll (start, end);
2808 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2810 _session->audition_region (region);
2814 Editor::region_from_selection ()
2816 if (clicked_axisview == 0) {
2820 if (selection->time.empty()) {
2824 framepos_t start = selection->time[clicked_selection].start;
2825 framepos_t end = selection->time[clicked_selection].end;
2827 TrackViewList tracks = get_tracks_for_range_action ();
2829 framepos_t selection_cnt = end - start + 1;
2831 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2832 boost::shared_ptr<Region> current;
2833 boost::shared_ptr<Playlist> pl;
2834 framepos_t internal_start;
2837 if ((pl = (*i)->playlist()) == 0) {
2841 if ((current = pl->top_region_at (start)) == 0) {
2845 internal_start = start - current->position();
2846 RegionFactory::region_name (new_name, current->name(), true);
2850 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2851 plist.add (ARDOUR::Properties::length, selection_cnt);
2852 plist.add (ARDOUR::Properties::name, new_name);
2853 plist.add (ARDOUR::Properties::layer, 0);
2855 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2860 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2862 if (selection->time.empty() || selection->tracks.empty()) {
2866 framepos_t start, end;
2867 if (clicked_selection) {
2868 start = selection->time[clicked_selection].start;
2869 end = selection->time[clicked_selection].end;
2871 start = selection->time.start();
2872 end = selection->time.end_frame();
2875 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2876 sort_track_selection (ts);
2878 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2879 boost::shared_ptr<Region> current;
2880 boost::shared_ptr<Playlist> playlist;
2881 framepos_t internal_start;
2884 if ((playlist = (*i)->playlist()) == 0) {
2888 if ((current = playlist->top_region_at(start)) == 0) {
2892 internal_start = start - current->position();
2893 RegionFactory::region_name (new_name, current->name(), true);
2897 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2898 plist.add (ARDOUR::Properties::length, end - start + 1);
2899 plist.add (ARDOUR::Properties::name, new_name);
2901 new_regions.push_back (RegionFactory::create (current, plist));
2906 Editor::split_multichannel_region ()
2908 RegionSelection rs = get_regions_from_selection_and_entered ();
2914 vector< boost::shared_ptr<Region> > v;
2916 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2917 (*x)->region()->separate_by_channel (*_session, v);
2922 Editor::new_region_from_selection ()
2924 region_from_selection ();
2925 cancel_selection ();
2929 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2931 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2932 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
2933 case Evoral::OverlapNone:
2941 * - selected tracks, or if there are none...
2942 * - tracks containing selected regions, or if there are none...
2947 Editor::get_tracks_for_range_action () const
2951 if (selection->tracks.empty()) {
2953 /* use tracks with selected regions */
2955 RegionSelection rs = selection->regions;
2957 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2958 TimeAxisView* tv = &(*i)->get_time_axis_view();
2960 if (!t.contains (tv)) {
2966 /* no regions and no tracks: use all tracks */
2972 t = selection->tracks;
2975 return t.filter_to_unique_playlists();
2979 Editor::separate_regions_between (const TimeSelection& ts)
2981 bool in_command = false;
2982 boost::shared_ptr<Playlist> playlist;
2983 RegionSelection new_selection;
2985 TrackViewList tmptracks = get_tracks_for_range_action ();
2986 sort_track_selection (tmptracks);
2988 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2990 RouteTimeAxisView* rtv;
2992 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2994 if (rtv->is_track()) {
2996 /* no edits to destructive tracks */
2998 if (rtv->track()->destructive()) {
3002 if ((playlist = rtv->playlist()) != 0) {
3004 playlist->clear_changes ();
3006 /* XXX need to consider musical time selections here at some point */
3008 double speed = rtv->track()->speed();
3011 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
3013 sigc::connection c = rtv->view()->RegionViewAdded.connect (
3014 sigc::mem_fun(*this, &Editor::collect_new_region_view));
3016 latest_regionviews.clear ();
3018 playlist->partition ((framepos_t)((*t).start * speed),
3019 (framepos_t)((*t).end * speed), false);
3023 if (!latest_regionviews.empty()) {
3025 rtv->view()->foreach_regionview (sigc::bind (
3026 sigc::ptr_fun (add_if_covered),
3027 &(*t), &new_selection));
3030 begin_reversible_command (_("separate"));
3034 /* pick up changes to existing regions */
3036 vector<Command*> cmds;
3037 playlist->rdiff (cmds);
3038 _session->add_commands (cmds);
3040 /* pick up changes to the playlist itself (adds/removes)
3043 _session->add_command(new StatefulDiffCommand (playlist));
3052 // selection->set (new_selection);
3054 commit_reversible_command ();
3058 struct PlaylistState {
3059 boost::shared_ptr<Playlist> playlist;
3063 /** Take tracks from get_tracks_for_range_action and cut any regions
3064 * on those tracks so that the tracks are empty over the time
3068 Editor::separate_region_from_selection ()
3070 /* preferentially use *all* ranges in the time selection if we're in range mode
3071 to allow discontiguous operation, since get_edit_op_range() currently
3072 returns a single range.
3075 if (!selection->time.empty()) {
3077 separate_regions_between (selection->time);
3084 if (get_edit_op_range (start, end)) {
3086 AudioRange ar (start, end, 1);
3090 separate_regions_between (ts);
3096 Editor::separate_region_from_punch ()
3098 Location* loc = _session->locations()->auto_punch_location();
3100 separate_regions_using_location (*loc);
3105 Editor::separate_region_from_loop ()
3107 Location* loc = _session->locations()->auto_loop_location();
3109 separate_regions_using_location (*loc);
3114 Editor::separate_regions_using_location (Location& loc)
3116 if (loc.is_mark()) {
3120 AudioRange ar (loc.start(), loc.end(), 1);
3125 separate_regions_between (ts);
3128 /** Separate regions under the selected region */
3130 Editor::separate_under_selected_regions ()
3132 vector<PlaylistState> playlists;
3136 rs = get_regions_from_selection_and_entered();
3138 if (!_session || rs.empty()) {
3142 begin_reversible_command (_("separate region under"));
3144 list<boost::shared_ptr<Region> > regions_to_remove;
3146 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3147 // we can't just remove the region(s) in this loop because
3148 // this removes them from the RegionSelection, and they thus
3149 // disappear from underneath the iterator, and the ++i above
3150 // SEGVs in a puzzling fashion.
3152 // so, first iterate over the regions to be removed from rs and
3153 // add them to the regions_to_remove list, and then
3154 // iterate over the list to actually remove them.
3156 regions_to_remove.push_back ((*i)->region());
3159 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3161 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3164 // is this check necessary?
3168 vector<PlaylistState>::iterator i;
3170 //only take state if this is a new playlist.
3171 for (i = playlists.begin(); i != playlists.end(); ++i) {
3172 if ((*i).playlist == playlist) {
3177 if (i == playlists.end()) {
3179 PlaylistState before;
3180 before.playlist = playlist;
3181 before.before = &playlist->get_state();
3183 playlist->freeze ();
3184 playlists.push_back(before);
3187 //Partition on the region bounds
3188 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3190 //Re-add region that was just removed due to the partition operation
3191 playlist->add_region( (*rl), (*rl)->first_frame() );
3194 vector<PlaylistState>::iterator pl;
3196 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3197 (*pl).playlist->thaw ();
3198 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3201 commit_reversible_command ();
3205 Editor::crop_region_to_selection ()
3207 if (!selection->time.empty()) {
3209 crop_region_to (selection->time.start(), selection->time.end_frame());
3216 if (get_edit_op_range (start, end)) {
3217 crop_region_to (start, end);
3224 Editor::crop_region_to (framepos_t start, framepos_t end)
3226 vector<boost::shared_ptr<Playlist> > playlists;
3227 boost::shared_ptr<Playlist> playlist;
3230 if (selection->tracks.empty()) {
3231 ts = track_views.filter_to_unique_playlists();
3233 ts = selection->tracks.filter_to_unique_playlists ();
3236 sort_track_selection (ts);
3238 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3240 RouteTimeAxisView* rtv;
3242 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3244 boost::shared_ptr<Track> t = rtv->track();
3246 if (t != 0 && ! t->destructive()) {
3248 if ((playlist = rtv->playlist()) != 0) {
3249 playlists.push_back (playlist);
3255 if (playlists.empty()) {
3260 framepos_t new_start;
3262 framecnt_t new_length;
3263 bool in_command = false;
3265 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3267 /* Only the top regions at start and end have to be cropped */
3268 boost::shared_ptr<Region> region_at_start = (*i)->top_region_at(start);
3269 boost::shared_ptr<Region> region_at_end = (*i)->top_region_at(end);
3271 vector<boost::shared_ptr<Region> > regions;
3273 if (region_at_start != 0) {
3274 regions.push_back (region_at_start);
3276 if (region_at_end != 0) {
3277 regions.push_back (region_at_end);
3280 /* now adjust lengths */
3281 for (vector<boost::shared_ptr<Region> >::iterator i = regions.begin(); i != regions.end(); ++i) {
3283 pos = (*i)->position();
3284 new_start = max (start, pos);
3285 if (max_framepos - pos > (*i)->length()) {
3286 new_end = pos + (*i)->length() - 1;
3288 new_end = max_framepos;
3290 new_end = min (end, new_end);
3291 new_length = new_end - new_start + 1;
3294 begin_reversible_command (_("trim to selection"));
3297 (*i)->clear_changes ();
3298 (*i)->trim_to (new_start, new_length);
3299 _session->add_command (new StatefulDiffCommand (*i));
3304 commit_reversible_command ();
3309 Editor::region_fill_track ()
3311 boost::shared_ptr<Playlist> playlist;
3312 RegionSelection regions = get_regions_from_selection_and_entered ();
3313 RegionSelection foo;
3315 framepos_t const end = _session->current_end_frame ();
3317 if (regions.empty () || regions.end_frame () + 1 >= end) {
3321 framepos_t const start_frame = regions.start ();
3322 framepos_t const end_frame = regions.end_frame ();
3323 framecnt_t const gap = end_frame - start_frame + 1;
3325 begin_reversible_command (Operations::region_fill);
3327 selection->clear_regions ();
3329 for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
3331 boost::shared_ptr<Region> r ((*i)->region());
3333 TimeAxisView& tv = (*i)->get_time_axis_view();
3334 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
3335 latest_regionviews.clear ();
3336 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3338 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
3339 playlist = (*i)->region()->playlist();
3340 playlist->clear_changes ();
3341 playlist->duplicate_until (r, position, gap, end);
3342 _session->add_command(new StatefulDiffCommand (playlist));
3346 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3350 selection->set (foo);
3353 commit_reversible_command ();
3357 Editor::set_region_sync_position ()
3359 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3363 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3365 bool in_command = false;
3367 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3369 if (!(*r)->region()->covers (where)) {
3373 boost::shared_ptr<Region> region ((*r)->region());
3376 begin_reversible_command (_("set sync point"));
3380 region->clear_changes ();
3381 region->set_sync_position (where);
3382 _session->add_command(new StatefulDiffCommand (region));
3386 commit_reversible_command ();
3390 /** Remove the sync positions of the selection */
3392 Editor::remove_region_sync ()
3394 RegionSelection rs = get_regions_from_selection_and_entered ();
3400 begin_reversible_command (_("remove region sync"));
3402 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3404 (*i)->region()->clear_changes ();
3405 (*i)->region()->clear_sync_position ();
3406 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3409 commit_reversible_command ();
3413 Editor::naturalize_region ()
3415 RegionSelection rs = get_regions_from_selection_and_entered ();
3421 if (rs.size() > 1) {
3422 begin_reversible_command (_("move regions to original position"));
3424 begin_reversible_command (_("move region to original position"));
3427 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3428 (*i)->region()->clear_changes ();
3429 (*i)->region()->move_to_natural_position ();
3430 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3433 commit_reversible_command ();
3437 Editor::align_regions (RegionPoint what)
3439 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3445 begin_reversible_command (_("align selection"));
3447 framepos_t const position = get_preferred_edit_position ();
3449 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3450 align_region_internal ((*i)->region(), what, position);
3453 commit_reversible_command ();
3456 struct RegionSortByTime {
3457 bool operator() (const RegionView* a, const RegionView* b) {
3458 return a->region()->position() < b->region()->position();
3463 Editor::align_regions_relative (RegionPoint point)
3465 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3471 framepos_t const position = get_preferred_edit_position ();
3473 framepos_t distance = 0;
3477 list<RegionView*> sorted;
3478 rs.by_position (sorted);
3480 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3485 if (position > r->position()) {
3486 distance = position - r->position();
3488 distance = r->position() - position;
3494 if (position > r->last_frame()) {
3495 distance = position - r->last_frame();
3496 pos = r->position() + distance;
3498 distance = r->last_frame() - position;
3499 pos = r->position() - distance;
3505 pos = r->adjust_to_sync (position);
3506 if (pos > r->position()) {
3507 distance = pos - r->position();
3509 distance = r->position() - pos;
3515 if (pos == r->position()) {
3519 begin_reversible_command (_("align selection (relative)"));
3521 /* move first one specially */
3523 r->clear_changes ();
3524 r->set_position (pos);
3525 _session->add_command(new StatefulDiffCommand (r));
3527 /* move rest by the same amount */
3531 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3533 boost::shared_ptr<Region> region ((*i)->region());
3535 region->clear_changes ();
3538 region->set_position (region->position() + distance);
3540 region->set_position (region->position() - distance);
3543 _session->add_command(new StatefulDiffCommand (region));
3547 commit_reversible_command ();
3551 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3553 begin_reversible_command (_("align region"));
3554 align_region_internal (region, point, position);
3555 commit_reversible_command ();
3559 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3561 region->clear_changes ();
3565 region->set_position (region->adjust_to_sync (position));
3569 if (position > region->length()) {
3570 region->set_position (position - region->length());
3575 region->set_position (position);
3579 _session->add_command(new StatefulDiffCommand (region));
3583 Editor::trim_region_front ()
3589 Editor::trim_region_back ()
3591 trim_region (false);
3595 Editor::trim_region (bool front)
3597 framepos_t where = get_preferred_edit_position();
3598 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3604 begin_reversible_command (front ? _("trim front") : _("trim back"));
3606 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3607 if (!(*i)->region()->locked()) {
3609 (*i)->region()->clear_changes ();
3612 (*i)->region()->trim_front (where);
3613 maybe_locate_with_edit_preroll ( where );
3615 (*i)->region()->trim_end (where);
3616 maybe_locate_with_edit_preroll ( where );
3619 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3623 commit_reversible_command ();
3626 /** Trim the end of the selected regions to the position of the edit cursor */
3628 Editor::trim_region_to_loop ()
3630 Location* loc = _session->locations()->auto_loop_location();
3634 trim_region_to_location (*loc, _("trim to loop"));
3638 Editor::trim_region_to_punch ()
3640 Location* loc = _session->locations()->auto_punch_location();
3644 trim_region_to_location (*loc, _("trim to punch"));
3648 Editor::trim_region_to_location (const Location& loc, const char* str)
3650 RegionSelection rs = get_regions_from_selection_and_entered ();
3651 bool in_command = false;
3653 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3654 RegionView* rv = (*x);
3656 /* require region to span proposed trim */
3657 switch (rv->region()->coverage (loc.start(), loc.end())) {
3658 case Evoral::OverlapInternal:
3664 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3673 if (tav->track() != 0) {
3674 speed = tav->track()->speed();
3677 start = session_frame_to_track_frame (loc.start(), speed);
3678 end = session_frame_to_track_frame (loc.end(), speed);
3680 rv->region()->clear_changes ();
3681 rv->region()->trim_to (start, (end - start));
3684 begin_reversible_command (str);
3687 _session->add_command(new StatefulDiffCommand (rv->region()));
3691 commit_reversible_command ();
3696 Editor::trim_region_to_previous_region_end ()
3698 return trim_to_region(false);
3702 Editor::trim_region_to_next_region_start ()
3704 return trim_to_region(true);
3708 Editor::trim_to_region(bool forward)
3710 RegionSelection rs = get_regions_from_selection_and_entered ();
3711 bool in_command = false;
3713 boost::shared_ptr<Region> next_region;
3715 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3717 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3723 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3731 if (atav->track() != 0) {
3732 speed = atav->track()->speed();
3736 boost::shared_ptr<Region> region = arv->region();
3737 boost::shared_ptr<Playlist> playlist (region->playlist());
3739 region->clear_changes ();
3743 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3749 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3750 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3754 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3760 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3762 arv->region_changed (ARDOUR::bounds_change);
3766 begin_reversible_command (_("trim to region"));
3769 _session->add_command(new StatefulDiffCommand (region));
3773 commit_reversible_command ();
3778 Editor::unfreeze_route ()
3780 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3784 clicked_routeview->track()->unfreeze ();
3788 Editor::_freeze_thread (void* arg)
3790 return static_cast<Editor*>(arg)->freeze_thread ();
3794 Editor::freeze_thread ()
3796 /* create event pool because we may need to talk to the session */
3797 SessionEvent::create_per_thread_pool ("freeze events", 64);
3798 /* create per-thread buffers for process() tree to use */
3799 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3800 current_interthread_info->done = true;
3805 Editor::freeze_route ()
3811 /* stop transport before we start. this is important */
3813 _session->request_transport_speed (0.0);
3815 /* wait for just a little while, because the above call is asynchronous */
3817 Glib::usleep (250000);
3819 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3823 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3825 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3826 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3828 d.set_title (_("Cannot freeze"));
3833 if (clicked_routeview->track()->has_external_redirects()) {
3834 MessageDialog d (string_compose (_("<b>%1</b>\n\nThis track has at least one send/insert/return as part of its signal flow.\n\n"
3835 "Freezing will only process the signal as far as the first send/insert/return."),
3836 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3838 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3839 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3840 d.set_title (_("Freeze Limits"));
3842 int response = d.run ();
3845 case Gtk::RESPONSE_CANCEL:
3852 InterThreadInfo itt;
3853 current_interthread_info = &itt;
3855 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3857 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3859 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3861 while (!itt.done && !itt.cancel) {
3862 gtk_main_iteration ();
3865 current_interthread_info = 0;
3869 Editor::bounce_range_selection (bool replace, bool enable_processing)
3871 if (selection->time.empty()) {
3875 TrackSelection views = selection->tracks;
3877 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3879 if (enable_processing) {
3881 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3883 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3885 _("You can't perform this operation because the processing of the signal "
3886 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3887 "You can do this without processing, which is a different operation.")
3889 d.set_title (_("Cannot bounce"));
3896 framepos_t start = selection->time[clicked_selection].start;
3897 framepos_t end = selection->time[clicked_selection].end;
3898 framepos_t cnt = end - start + 1;
3899 bool in_command = false;
3901 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3903 RouteTimeAxisView* rtv;
3905 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3909 boost::shared_ptr<Playlist> playlist;
3911 if ((playlist = rtv->playlist()) == 0) {
3915 InterThreadInfo itt;
3917 playlist->clear_changes ();
3918 playlist->clear_owned_changes ();
3920 boost::shared_ptr<Region> r;
3922 if (enable_processing) {
3923 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3925 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3933 list<AudioRange> ranges;
3934 ranges.push_back (AudioRange (start, start+cnt, 0));
3935 playlist->cut (ranges); // discard result
3936 playlist->add_region (r, start);
3940 begin_reversible_command (_("bounce range"));
3943 vector<Command*> cmds;
3944 playlist->rdiff (cmds);
3945 _session->add_commands (cmds);
3947 _session->add_command (new StatefulDiffCommand (playlist));
3951 commit_reversible_command ();
3955 /** Delete selected regions, automation points or a time range */
3959 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
3960 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
3961 bool deleted = false;
3962 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
3963 deleted = current_mixer_strip->delete_processors ();
3969 /** Cut selected regions, automation points or a time range */
3976 /** Copy selected regions, automation points or a time range */
3984 /** @return true if a Cut, Copy or Clear is possible */
3986 Editor::can_cut_copy () const
3988 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
3995 /** Cut, copy or clear selected regions, automation points or a time range.
3996 * @param op Operation (Delete, Cut, Copy or Clear)
3999 Editor::cut_copy (CutCopyOp op)
4001 /* only cancel selection if cut/copy is successful.*/
4007 opname = _("delete");
4016 opname = _("clear");
4020 /* if we're deleting something, and the mouse is still pressed,
4021 the thing we started a drag for will be gone when we release
4022 the mouse button(s). avoid this. see part 2 at the end of
4026 if (op == Delete || op == Cut || op == Clear) {
4027 if (_drags->active ()) {
4032 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
4033 cut_buffer->clear ();
4035 if (entered_marker) {
4037 /* cut/delete op while pointing at a marker */
4040 Location* loc = find_location_from_marker (entered_marker, ignored);
4042 if (_session && loc) {
4043 entered_marker = NULL;
4044 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4051 switch (mouse_mode) {
4054 begin_reversible_command (opname + ' ' + X_("MIDI"));
4056 commit_reversible_command ();
4062 bool did_edit = false;
4064 if (!selection->regions.empty() || !selection->points.empty()) {
4065 begin_reversible_command (opname + ' ' + _("objects"));
4068 if (!selection->regions.empty()) {
4069 cut_copy_regions (op, selection->regions);
4071 if (op == Cut || op == Delete) {
4072 selection->clear_regions ();
4076 if (!selection->points.empty()) {
4077 cut_copy_points (op);
4079 if (op == Cut || op == Delete) {
4080 selection->clear_points ();
4083 } else if (selection->time.empty()) {
4084 framepos_t start, end;
4085 /* no time selection, see if we can get an edit range
4088 if (get_edit_op_range (start, end)) {
4089 selection->set (start, end);
4091 } else if (!selection->time.empty()) {
4092 begin_reversible_command (opname + ' ' + _("range"));
4095 cut_copy_ranges (op);
4097 if (op == Cut || op == Delete) {
4098 selection->clear_time ();
4103 /* reset repeated paste state */
4106 commit_reversible_command ();
4109 if (op == Delete || op == Cut || op == Clear) {
4114 struct AutomationRecord {
4115 AutomationRecord () : state (0) , line(NULL) {}
4116 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4118 XMLNode* state; ///< state before any operation
4119 const AutomationLine* line; ///< line this came from
4120 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4123 /** Cut, copy or clear selected automation points.
4124 * @param op Operation (Cut, Copy or Clear)
4127 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4129 if (selection->points.empty ()) {
4133 /* XXX: not ideal, as there may be more than one track involved in the point selection */
4134 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4136 /* Keep a record of the AutomationLists that we end up using in this operation */
4137 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4140 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4141 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4142 const AutomationLine& line = (*i)->line();
4143 const boost::shared_ptr<AutomationList> al = line.the_list();
4144 if (lists.find (al) == lists.end ()) {
4145 /* We haven't seen this list yet, so make a record for it. This includes
4146 taking a copy of its current state, in case this is needed for undo later.
4148 lists[al] = AutomationRecord (&al->get_state (), &line);
4152 if (op == Cut || op == Copy) {
4153 /* This operation will involve putting things in the cut buffer, so create an empty
4154 ControlList for each of our source lists to put the cut buffer data in.
4156 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4157 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4160 /* Add all selected points to the relevant copy ControlLists */
4161 framepos_t start = std::numeric_limits<framepos_t>::max();
4162 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4163 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4164 AutomationList::const_iterator j = (*i)->model();
4166 lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
4168 /* Update earliest MIDI start time in beats */
4169 earliest = std::min(earliest, Evoral::Beats((*j)->when));
4171 /* Update earliest session start time in frames */
4172 start = std::min(start, (*i)->line().session_position(j));
4176 /* Snap start time backwards, so copy/paste is snap aligned. */
4178 if (earliest == Evoral::Beats::max()) {
4179 earliest = Evoral::Beats(); // Weird... don't offset
4181 earliest.round_down_to_beat();
4183 if (start == std::numeric_limits<double>::max()) {
4184 start = 0; // Weird... don't offset
4186 snap_to(start, RoundDownMaybe);
4189 const double line_offset = midi ? earliest.to_double() : start;
4190 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4191 /* Correct this copy list so that it is relative to the earliest
4192 start time, so relative ordering between points is preserved
4193 when copying from several lists and the paste starts at the
4194 earliest copied piece of data. */
4195 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
4196 (*j)->when -= line_offset;
4199 /* And add it to the cut buffer */
4200 cut_buffer->add (i->second.copy);
4204 if (op == Delete || op == Cut) {
4205 /* This operation needs to remove things from the main AutomationList, so do that now */
4207 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4208 i->first->freeze ();
4211 /* Remove each selected point from its AutomationList */
4212 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4213 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4214 al->erase ((*i)->model ());
4217 /* Thaw the lists and add undo records for them */
4218 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4219 boost::shared_ptr<AutomationList> al = i->first;
4221 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4226 /** Cut, copy or clear selected automation points.
4227 * @param op Operation (Cut, Copy or Clear)
4230 Editor::cut_copy_midi (CutCopyOp op)
4232 Evoral::Beats earliest = Evoral::Beats::max();
4233 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4234 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4236 if (!mrv->selection().empty()) {
4237 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4239 mrv->cut_copy_clear (op);
4241 /* XXX: not ideal, as there may be more than one track involved in the selection */
4242 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4246 if (!selection->points.empty()) {
4247 cut_copy_points (op, earliest, true);
4248 if (op == Cut || op == Delete) {
4249 selection->clear_points ();
4254 struct lt_playlist {
4255 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4256 return a.playlist < b.playlist;
4260 struct PlaylistMapping {
4262 boost::shared_ptr<Playlist> pl;
4264 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4267 /** Remove `clicked_regionview' */
4269 Editor::remove_clicked_region ()
4271 if (clicked_routeview == 0 || clicked_regionview == 0) {
4275 begin_reversible_command (_("remove region"));
4277 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4279 playlist->clear_changes ();
4280 playlist->clear_owned_changes ();
4281 playlist->remove_region (clicked_regionview->region());
4282 if (Config->get_edit_mode() == Ripple)
4283 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4285 /* We might have removed regions, which alters other regions' layering_index,
4286 so we need to do a recursive diff here.
4288 vector<Command*> cmds;
4289 playlist->rdiff (cmds);
4290 _session->add_commands (cmds);
4292 _session->add_command(new StatefulDiffCommand (playlist));
4293 commit_reversible_command ();
4297 /** Remove the selected regions */
4299 Editor::remove_selected_regions ()
4301 RegionSelection rs = get_regions_from_selection_and_entered ();
4303 if (!_session || rs.empty()) {
4307 list<boost::shared_ptr<Region> > regions_to_remove;
4309 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4310 // we can't just remove the region(s) in this loop because
4311 // this removes them from the RegionSelection, and they thus
4312 // disappear from underneath the iterator, and the ++i above
4313 // SEGVs in a puzzling fashion.
4315 // so, first iterate over the regions to be removed from rs and
4316 // add them to the regions_to_remove list, and then
4317 // iterate over the list to actually remove them.
4319 regions_to_remove.push_back ((*i)->region());
4322 vector<boost::shared_ptr<Playlist> > playlists;
4324 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4326 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4329 // is this check necessary?
4333 /* get_regions_from_selection_and_entered() guarantees that
4334 the playlists involved are unique, so there is no need
4338 playlists.push_back (playlist);
4340 playlist->clear_changes ();
4341 playlist->clear_owned_changes ();
4342 playlist->freeze ();
4343 playlist->remove_region (*rl);
4344 if (Config->get_edit_mode() == Ripple)
4345 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4349 vector<boost::shared_ptr<Playlist> >::iterator pl;
4350 bool in_command = false;
4352 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4355 /* We might have removed regions, which alters other regions' layering_index,
4356 so we need to do a recursive diff here.
4360 begin_reversible_command (_("remove region"));
4363 vector<Command*> cmds;
4364 (*pl)->rdiff (cmds);
4365 _session->add_commands (cmds);
4367 _session->add_command(new StatefulDiffCommand (*pl));
4371 commit_reversible_command ();
4375 /** Cut, copy or clear selected regions.
4376 * @param op Operation (Cut, Copy or Clear)
4379 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4381 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4382 a map when we want ordered access to both elements. i think.
4385 vector<PlaylistMapping> pmap;
4387 framepos_t first_position = max_framepos;
4389 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4390 FreezeList freezelist;
4392 /* get ordering correct before we cut/copy */
4394 rs.sort_by_position_and_track ();
4396 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4398 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4400 if (op == Cut || op == Clear || op == Delete) {
4401 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4404 FreezeList::iterator fl;
4406 // only take state if this is a new playlist.
4407 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4413 if (fl == freezelist.end()) {
4414 pl->clear_changes();
4415 pl->clear_owned_changes ();
4417 freezelist.insert (pl);
4422 TimeAxisView* tv = &(*x)->get_time_axis_view();
4423 vector<PlaylistMapping>::iterator z;
4425 for (z = pmap.begin(); z != pmap.end(); ++z) {
4426 if ((*z).tv == tv) {
4431 if (z == pmap.end()) {
4432 pmap.push_back (PlaylistMapping (tv));
4436 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4438 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4441 /* region not yet associated with a playlist (e.g. unfinished
4448 TimeAxisView& tv = (*x)->get_time_axis_view();
4449 boost::shared_ptr<Playlist> npl;
4450 RegionSelection::iterator tmp;
4457 vector<PlaylistMapping>::iterator z;
4459 for (z = pmap.begin(); z != pmap.end(); ++z) {
4460 if ((*z).tv == &tv) {
4465 assert (z != pmap.end());
4468 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4476 boost::shared_ptr<Region> r = (*x)->region();
4477 boost::shared_ptr<Region> _xx;
4483 pl->remove_region (r);
4484 if (Config->get_edit_mode() == Ripple)
4485 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4489 _xx = RegionFactory::create (r);
4490 npl->add_region (_xx, r->position() - first_position);
4491 pl->remove_region (r);
4492 if (Config->get_edit_mode() == Ripple)
4493 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4497 /* copy region before adding, so we're not putting same object into two different playlists */
4498 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4502 pl->remove_region (r);
4503 if (Config->get_edit_mode() == Ripple)
4504 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4513 list<boost::shared_ptr<Playlist> > foo;
4515 /* the pmap is in the same order as the tracks in which selected regions occured */
4517 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4520 foo.push_back ((*i).pl);
4525 cut_buffer->set (foo);
4529 _last_cut_copy_source_track = 0;
4531 _last_cut_copy_source_track = pmap.front().tv;
4535 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4538 /* We might have removed regions, which alters other regions' layering_index,
4539 so we need to do a recursive diff here.
4541 vector<Command*> cmds;
4542 (*pl)->rdiff (cmds);
4543 _session->add_commands (cmds);
4545 _session->add_command (new StatefulDiffCommand (*pl));
4550 Editor::cut_copy_ranges (CutCopyOp op)
4552 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4554 /* Sort the track selection now, so that it if is used, the playlists
4555 selected by the calls below to cut_copy_clear are in the order that
4556 their tracks appear in the editor. This makes things like paste
4557 of ranges work properly.
4560 sort_track_selection (ts);
4563 if (!entered_track) {
4566 ts.push_back (entered_track);
4569 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4570 (*i)->cut_copy_clear (*selection, op);
4575 Editor::paste (float times, bool from_context)
4577 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4579 paste_internal (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), times);
4583 Editor::mouse_paste ()
4588 if (!mouse_frame (where, ignored)) {
4593 paste_internal (where, 1);
4597 Editor::paste_internal (framepos_t position, float times)
4599 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4601 if (cut_buffer->empty(internal_editing())) {
4605 if (position == max_framepos) {
4606 position = get_preferred_edit_position();
4607 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4610 if (position == last_paste_pos) {
4611 /* repeated paste in the same position */
4614 /* paste in new location, reset repeated paste state */
4616 last_paste_pos = position;
4619 /* get everything in the correct order */
4622 if (!selection->tracks.empty()) {
4623 /* If there is a track selection, paste into exactly those tracks and
4624 only those tracks. This allows the user to be explicit and override
4625 the below "do the reasonable thing" logic. */
4626 ts = selection->tracks.filter_to_unique_playlists ();
4627 sort_track_selection (ts);
4629 /* Figure out which track to base the paste at. */
4630 TimeAxisView* base_track = NULL;
4631 if (_edit_point == Editing::EditAtMouse && entered_track) {
4632 /* With the mouse edit point, paste onto the track under the mouse. */
4633 base_track = entered_track;
4634 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4635 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4636 base_track = &entered_regionview->get_time_axis_view();
4637 } else if (_last_cut_copy_source_track) {
4638 /* Paste to the track that the cut/copy came from (see mantis #333). */
4639 base_track = _last_cut_copy_source_track;
4641 /* This is "impossible" since we've copied... well, do nothing. */
4645 /* Walk up to parent if necessary, so base track is a route. */
4646 while (base_track->get_parent()) {
4647 base_track = base_track->get_parent();
4650 /* Add base track and all tracks below it. The paste logic will select
4651 the appropriate object types from the cut buffer in relative order. */
4652 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4653 if ((*i)->order() >= base_track->order()) {
4658 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4659 sort_track_selection (ts);
4661 /* Add automation children of each track in order, for pasting several lines. */
4662 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4663 /* Add any automation children for pasting several lines */
4664 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4669 typedef RouteTimeAxisView::AutomationTracks ATracks;
4670 const ATracks& atracks = rtv->automation_tracks();
4671 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4672 i = ts.insert(i, a->second.get());
4677 /* We now have a list of trackviews starting at base_track, including
4678 automation children, in the order shown in the editor, e.g. R1,
4679 R1.A1, R1.A2, R2, R2.A1, ... */
4682 begin_reversible_command (Operations::paste);
4684 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4685 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4686 /* Only one line copied, and one automation track selected. Do a
4687 "greedy" paste from one automation type to another. */
4689 PasteContext ctx(paste_count, times, ItemCounts(), true);
4690 ts.front()->paste (position, *cut_buffer, ctx);
4694 /* Paste into tracks */
4696 PasteContext ctx(paste_count, times, ItemCounts(), false);
4697 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4698 (*i)->paste (position, *cut_buffer, ctx);
4702 commit_reversible_command ();
4706 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4708 if (regions.empty ()) {
4712 boost::shared_ptr<Playlist> playlist;
4713 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4714 RegionSelection foo;
4716 framepos_t const start_frame = regions.start ();
4717 framepos_t const end_frame = regions.end_frame ();
4718 framecnt_t const gap = end_frame - start_frame + 1;
4720 begin_reversible_command (Operations::duplicate_region);
4722 selection->clear_regions ();
4724 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4726 boost::shared_ptr<Region> r ((*i)->region());
4728 TimeAxisView& tv = (*i)->get_time_axis_view();
4729 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4730 latest_regionviews.clear ();
4731 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4733 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
4734 playlist = (*i)->region()->playlist();
4735 playlist->clear_changes ();
4736 playlist->duplicate (r, position, gap, times);
4737 _session->add_command(new StatefulDiffCommand (playlist));
4741 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4745 selection->set (foo);
4748 commit_reversible_command ();
4752 Editor::duplicate_selection (float times)
4754 if (selection->time.empty() || selection->tracks.empty()) {
4758 boost::shared_ptr<Playlist> playlist;
4759 vector<boost::shared_ptr<Region> > new_regions;
4760 vector<boost::shared_ptr<Region> >::iterator ri;
4762 create_region_from_selection (new_regions);
4764 if (new_regions.empty()) {
4768 ri = new_regions.begin();
4770 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4771 bool in_command = false;
4773 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4774 if ((playlist = (*i)->playlist()) == 0) {
4777 playlist->clear_changes ();
4779 if (clicked_selection) {
4780 end = selection->time[clicked_selection].end;
4782 end = selection->time.end_frame();
4784 playlist->duplicate (*ri, end + 1, times);
4787 begin_reversible_command (_("duplicate selection"));
4790 _session->add_command (new StatefulDiffCommand (playlist));
4793 if (ri == new_regions.end()) {
4799 commit_reversible_command ();
4803 /** Reset all selected points to the relevant default value */
4805 Editor::reset_point_selection ()
4807 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4808 ARDOUR::AutomationList::iterator j = (*i)->model ();
4809 (*j)->value = (*i)->line().the_list()->default_value ();
4814 Editor::center_playhead ()
4816 float const page = _visible_canvas_width * samples_per_pixel;
4817 center_screen_internal (playhead_cursor->current_frame (), page);
4821 Editor::center_edit_point ()
4823 float const page = _visible_canvas_width * samples_per_pixel;
4824 center_screen_internal (get_preferred_edit_position(), page);
4827 /** Caller must begin and commit a reversible command */
4829 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4831 playlist->clear_changes ();
4833 _session->add_command (new StatefulDiffCommand (playlist));
4837 Editor::nudge_track (bool use_edit, bool forwards)
4839 boost::shared_ptr<Playlist> playlist;
4840 framepos_t distance;
4841 framepos_t next_distance;
4845 start = get_preferred_edit_position();
4850 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4854 if (selection->tracks.empty()) {
4858 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4859 bool in_command = false;
4861 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4863 if ((playlist = (*i)->playlist()) == 0) {
4867 playlist->clear_changes ();
4868 playlist->clear_owned_changes ();
4870 playlist->nudge_after (start, distance, forwards);
4873 begin_reversible_command (_("nudge track"));
4876 vector<Command*> cmds;
4878 playlist->rdiff (cmds);
4879 _session->add_commands (cmds);
4881 _session->add_command (new StatefulDiffCommand (playlist));
4885 commit_reversible_command ();
4890 Editor::remove_last_capture ()
4892 vector<string> choices;
4899 if (Config->get_verify_remove_last_capture()) {
4900 prompt = _("Do you really want to destroy the last capture?"
4901 "\n(This is destructive and cannot be undone)");
4903 choices.push_back (_("No, do nothing."));
4904 choices.push_back (_("Yes, destroy it."));
4906 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4908 if (prompter.run () == 1) {
4909 _session->remove_last_capture ();
4910 _regions->redisplay ();
4914 _session->remove_last_capture();
4915 _regions->redisplay ();
4920 Editor::normalize_region ()
4926 RegionSelection rs = get_regions_from_selection_and_entered ();
4932 NormalizeDialog dialog (rs.size() > 1);
4934 if (dialog.run () == RESPONSE_CANCEL) {
4938 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
4941 /* XXX: should really only count audio regions here */
4942 int const regions = rs.size ();
4944 /* Make a list of the selected audio regions' maximum amplitudes, and also
4945 obtain the maximum amplitude of them all.
4947 list<double> max_amps;
4949 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4950 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4952 dialog.descend (1.0 / regions);
4953 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4956 /* the user cancelled the operation */
4960 max_amps.push_back (a);
4961 max_amp = max (max_amp, a);
4966 list<double>::const_iterator a = max_amps.begin ();
4967 bool in_command = false;
4969 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4970 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4975 arv->region()->clear_changes ();
4977 double const amp = dialog.normalize_individually() ? *a : max_amp;
4979 arv->audio_region()->normalize (amp, dialog.target ());
4982 begin_reversible_command (_("normalize"));
4985 _session->add_command (new StatefulDiffCommand (arv->region()));
4991 commit_reversible_command ();
4997 Editor::reset_region_scale_amplitude ()
5003 RegionSelection rs = get_regions_from_selection_and_entered ();
5009 bool in_command = false;
5011 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5012 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5015 arv->region()->clear_changes ();
5016 arv->audio_region()->set_scale_amplitude (1.0f);
5019 begin_reversible_command ("reset gain");
5022 _session->add_command (new StatefulDiffCommand (arv->region()));
5026 commit_reversible_command ();
5031 Editor::adjust_region_gain (bool up)
5033 RegionSelection rs = get_regions_from_selection_and_entered ();
5035 if (!_session || rs.empty()) {
5039 bool in_command = false;
5041 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5042 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5047 arv->region()->clear_changes ();
5049 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5057 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5060 begin_reversible_command ("adjust region gain");
5063 _session->add_command (new StatefulDiffCommand (arv->region()));
5067 commit_reversible_command ();
5073 Editor::reverse_region ()
5079 Reverse rev (*_session);
5080 apply_filter (rev, _("reverse regions"));
5084 Editor::strip_region_silence ()
5090 RegionSelection rs = get_regions_from_selection_and_entered ();
5096 std::list<RegionView*> audio_only;
5098 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5099 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5101 audio_only.push_back (arv);
5105 assert (!audio_only.empty());
5107 StripSilenceDialog d (_session, audio_only);
5108 int const r = d.run ();
5112 if (r == Gtk::RESPONSE_OK) {
5113 ARDOUR::AudioIntervalMap silences;
5114 d.silences (silences);
5115 StripSilence s (*_session, silences, d.fade_length());
5116 apply_filter (s, _("strip silence"), &d);
5121 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5123 Evoral::Sequence<Evoral::Beats>::Notes selected;
5124 mrv.selection_as_notelist (selected, true);
5126 vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5127 v.push_back (selected);
5129 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
5130 Evoral::Beats pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
5132 return op (mrv.midi_region()->model(), pos_beats, v);
5136 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5142 bool in_command = false;
5144 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5145 RegionSelection::const_iterator tmp = r;
5148 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5151 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5154 begin_reversible_command (op.name ());
5158 _session->add_command (cmd);
5166 commit_reversible_command ();
5171 Editor::fork_region ()
5173 RegionSelection rs = get_regions_from_selection_and_entered ();
5179 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5180 bool in_command = false;
5184 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5185 RegionSelection::iterator tmp = r;
5188 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5192 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5193 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5194 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5197 begin_reversible_command (_("Fork Region(s)"));
5200 playlist->clear_changes ();
5201 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5202 _session->add_command(new StatefulDiffCommand (playlist));
5204 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5212 commit_reversible_command ();
5217 Editor::quantize_region ()
5220 quantize_regions(get_regions_from_selection_and_entered ());
5225 Editor::quantize_regions (const RegionSelection& rs)
5227 if (rs.n_midi_regions() == 0) {
5231 if (!quantize_dialog) {
5232 quantize_dialog = new QuantizeDialog (*this);
5235 quantize_dialog->present ();
5236 const int r = quantize_dialog->run ();
5237 quantize_dialog->hide ();
5239 if (r == Gtk::RESPONSE_OK) {
5240 Quantize quant (quantize_dialog->snap_start(),
5241 quantize_dialog->snap_end(),
5242 quantize_dialog->start_grid_size(),
5243 quantize_dialog->end_grid_size(),
5244 quantize_dialog->strength(),
5245 quantize_dialog->swing(),
5246 quantize_dialog->threshold());
5248 apply_midi_note_edit_op (quant, rs);
5253 Editor::legatize_region (bool shrink_only)
5256 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5261 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5263 if (rs.n_midi_regions() == 0) {
5267 Legatize legatize(shrink_only);
5268 apply_midi_note_edit_op (legatize, rs);
5272 Editor::transform_region ()
5275 transform_regions(get_regions_from_selection_and_entered ());
5280 Editor::transform_regions (const RegionSelection& rs)
5282 if (rs.n_midi_regions() == 0) {
5289 const int r = td.run();
5292 if (r == Gtk::RESPONSE_OK) {
5293 Transform transform(td.get());
5294 apply_midi_note_edit_op(transform, rs);
5299 Editor::transpose_region ()
5302 transpose_regions(get_regions_from_selection_and_entered ());
5307 Editor::transpose_regions (const RegionSelection& rs)
5309 if (rs.n_midi_regions() == 0) {
5314 int const r = d.run ();
5316 if (r == RESPONSE_ACCEPT) {
5317 Transpose transpose(d.semitones ());
5318 apply_midi_note_edit_op (transpose, rs);
5323 Editor::insert_patch_change (bool from_context)
5325 RegionSelection rs = get_regions_from_selection_and_entered ();
5331 const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5333 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5334 there may be more than one, but the PatchChangeDialog can only offer
5335 one set of patch menus.
5337 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5339 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5340 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5342 if (d.run() == RESPONSE_CANCEL) {
5346 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5347 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5349 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5350 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5357 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5359 RegionSelection rs = get_regions_from_selection_and_entered ();
5365 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5366 bool in_command = false;
5371 int const N = rs.size ();
5373 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5374 RegionSelection::iterator tmp = r;
5377 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5379 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5382 progress->descend (1.0 / N);
5385 if (arv->audio_region()->apply (filter, progress) == 0) {
5387 playlist->clear_changes ();
5388 playlist->clear_owned_changes ();
5390 if (filter.results.empty ()) {
5392 /* no regions returned; remove the old one */
5393 playlist->remove_region (arv->region ());
5397 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5399 /* first region replaces the old one */
5400 playlist->replace_region (arv->region(), *res, (*res)->position());
5404 while (res != filter.results.end()) {
5405 playlist->add_region (*res, (*res)->position());
5410 /* We might have removed regions, which alters other regions' layering_index,
5411 so we need to do a recursive diff here.
5415 begin_reversible_command (command);
5418 vector<Command*> cmds;
5419 playlist->rdiff (cmds);
5420 _session->add_commands (cmds);
5422 _session->add_command(new StatefulDiffCommand (playlist));
5426 progress->ascend ();
5435 commit_reversible_command ();
5440 Editor::external_edit_region ()
5446 Editor::reset_region_gain_envelopes ()
5448 RegionSelection rs = get_regions_from_selection_and_entered ();
5450 if (!_session || rs.empty()) {
5454 bool in_command = false;
5456 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5457 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5459 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5460 XMLNode& before (alist->get_state());
5462 arv->audio_region()->set_default_envelope ();
5465 begin_reversible_command (_("reset region gain"));
5468 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5473 commit_reversible_command ();
5478 Editor::set_region_gain_visibility (RegionView* rv)
5480 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5482 arv->update_envelope_visibility();
5487 Editor::set_gain_envelope_visibility ()
5493 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5494 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5496 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5502 Editor::toggle_gain_envelope_active ()
5504 if (_ignore_region_action) {
5508 RegionSelection rs = get_regions_from_selection_and_entered ();
5510 if (!_session || rs.empty()) {
5514 bool in_command = false;
5516 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5517 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5519 arv->region()->clear_changes ();
5520 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5523 begin_reversible_command (_("region gain envelope active"));
5526 _session->add_command (new StatefulDiffCommand (arv->region()));
5531 commit_reversible_command ();
5536 Editor::toggle_region_lock ()
5538 if (_ignore_region_action) {
5542 RegionSelection rs = get_regions_from_selection_and_entered ();
5544 if (!_session || rs.empty()) {
5548 begin_reversible_command (_("toggle region lock"));
5550 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5551 (*i)->region()->clear_changes ();
5552 (*i)->region()->set_locked (!(*i)->region()->locked());
5553 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5556 commit_reversible_command ();
5560 Editor::toggle_region_video_lock ()
5562 if (_ignore_region_action) {
5566 RegionSelection rs = get_regions_from_selection_and_entered ();
5568 if (!_session || rs.empty()) {
5572 begin_reversible_command (_("Toggle Video Lock"));
5574 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5575 (*i)->region()->clear_changes ();
5576 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5577 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5580 commit_reversible_command ();
5584 Editor::toggle_region_lock_style ()
5586 if (_ignore_region_action) {
5590 RegionSelection rs = get_regions_from_selection_and_entered ();
5592 if (!_session || rs.empty()) {
5596 begin_reversible_command (_("region lock style"));
5598 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5599 (*i)->region()->clear_changes ();
5600 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5601 (*i)->region()->set_position_lock_style (ns);
5602 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5605 commit_reversible_command ();
5609 Editor::toggle_opaque_region ()
5611 if (_ignore_region_action) {
5615 RegionSelection rs = get_regions_from_selection_and_entered ();
5617 if (!_session || rs.empty()) {
5621 begin_reversible_command (_("change region opacity"));
5623 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5624 (*i)->region()->clear_changes ();
5625 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5626 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5629 commit_reversible_command ();
5633 Editor::toggle_record_enable ()
5635 bool new_state = false;
5637 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5638 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5641 if (!rtav->is_track())
5645 new_state = !rtav->track()->record_enabled();
5649 rtav->track()->set_record_enabled (new_state, this);
5654 Editor::toggle_solo ()
5656 bool new_state = false;
5658 boost::shared_ptr<RouteList> rl (new RouteList);
5660 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5661 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5668 new_state = !rtav->route()->soloed ();
5672 rl->push_back (rtav->route());
5675 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5679 Editor::toggle_mute ()
5681 bool new_state = false;
5683 boost::shared_ptr<RouteList> rl (new RouteList);
5685 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5686 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5693 new_state = !rtav->route()->muted();
5697 rl->push_back (rtav->route());
5700 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5704 Editor::toggle_solo_isolate ()
5710 Editor::fade_range ()
5712 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5714 begin_reversible_command (_("fade range"));
5716 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5717 (*i)->fade_range (selection->time);
5720 commit_reversible_command ();
5725 Editor::set_fade_length (bool in)
5727 RegionSelection rs = get_regions_from_selection_and_entered ();
5733 /* we need a region to measure the offset from the start */
5735 RegionView* rv = rs.front ();
5737 framepos_t pos = get_preferred_edit_position();
5741 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5742 /* edit point is outside the relevant region */
5747 if (pos <= rv->region()->position()) {
5751 len = pos - rv->region()->position();
5752 cmd = _("set fade in length");
5754 if (pos >= rv->region()->last_frame()) {
5758 len = rv->region()->last_frame() - pos;
5759 cmd = _("set fade out length");
5762 bool in_command = false;
5764 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5765 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5771 boost::shared_ptr<AutomationList> alist;
5773 alist = tmp->audio_region()->fade_in();
5775 alist = tmp->audio_region()->fade_out();
5778 XMLNode &before = alist->get_state();
5781 tmp->audio_region()->set_fade_in_length (len);
5782 tmp->audio_region()->set_fade_in_active (true);
5784 tmp->audio_region()->set_fade_out_length (len);
5785 tmp->audio_region()->set_fade_out_active (true);
5789 begin_reversible_command (cmd);
5792 XMLNode &after = alist->get_state();
5793 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5797 commit_reversible_command ();
5802 Editor::set_fade_in_shape (FadeShape shape)
5804 RegionSelection rs = get_regions_from_selection_and_entered ();
5809 bool in_command = false;
5811 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5812 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5818 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5819 XMLNode &before = alist->get_state();
5821 tmp->audio_region()->set_fade_in_shape (shape);
5824 begin_reversible_command (_("set fade in shape"));
5827 XMLNode &after = alist->get_state();
5828 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5832 commit_reversible_command ();
5837 Editor::set_fade_out_shape (FadeShape shape)
5839 RegionSelection rs = get_regions_from_selection_and_entered ();
5844 bool in_command = false;
5846 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5847 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5853 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5854 XMLNode &before = alist->get_state();
5856 tmp->audio_region()->set_fade_out_shape (shape);
5859 begin_reversible_command (_("set fade out shape"));
5862 XMLNode &after = alist->get_state();
5863 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5867 commit_reversible_command ();
5872 Editor::set_fade_in_active (bool yn)
5874 RegionSelection rs = get_regions_from_selection_and_entered ();
5879 bool in_command = false;
5881 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5882 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5889 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5891 ar->clear_changes ();
5892 ar->set_fade_in_active (yn);
5895 begin_reversible_command (_("set fade in active"));
5898 _session->add_command (new StatefulDiffCommand (ar));
5902 commit_reversible_command ();
5907 Editor::set_fade_out_active (bool yn)
5909 RegionSelection rs = get_regions_from_selection_and_entered ();
5914 bool in_command = false;
5916 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5917 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5923 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5925 ar->clear_changes ();
5926 ar->set_fade_out_active (yn);
5929 begin_reversible_command (_("set fade out active"));
5932 _session->add_command(new StatefulDiffCommand (ar));
5936 commit_reversible_command ();
5941 Editor::toggle_region_fades (int dir)
5943 if (_ignore_region_action) {
5947 boost::shared_ptr<AudioRegion> ar;
5950 RegionSelection rs = get_regions_from_selection_and_entered ();
5956 RegionSelection::iterator i;
5957 for (i = rs.begin(); i != rs.end(); ++i) {
5958 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5960 yn = ar->fade_out_active ();
5962 yn = ar->fade_in_active ();
5968 if (i == rs.end()) {
5972 /* XXX should this undo-able? */
5973 bool in_command = false;
5975 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5976 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5979 ar->clear_changes ();
5981 if (dir == 1 || dir == 0) {
5982 ar->set_fade_in_active (!yn);
5985 if (dir == -1 || dir == 0) {
5986 ar->set_fade_out_active (!yn);
5989 begin_reversible_command (_("toggle fade active"));
5992 _session->add_command(new StatefulDiffCommand (ar));
5996 commit_reversible_command ();
6001 /** Update region fade visibility after its configuration has been changed */
6003 Editor::update_region_fade_visibility ()
6005 bool _fade_visibility = _session->config.get_show_region_fades ();
6007 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6008 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
6010 if (_fade_visibility) {
6011 v->audio_view()->show_all_fades ();
6013 v->audio_view()->hide_all_fades ();
6020 Editor::set_edit_point ()
6025 if (!mouse_frame (where, ignored)) {
6031 if (selection->markers.empty()) {
6033 mouse_add_new_marker (where);
6038 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
6041 loc->move_to (where);
6047 Editor::set_playhead_cursor ()
6049 if (entered_marker) {
6050 _session->request_locate (entered_marker->position(), _session->transport_rolling());
6055 if (!mouse_frame (where, ignored)) {
6062 _session->request_locate (where, _session->transport_rolling());
6066 if (UIConfiguration::instance().get_follow_edits() && (!_session || !_session->config.get_external_sync())) {
6067 cancel_time_selection();
6072 Editor::split_region ()
6074 if (_drags->active ()) {
6078 //if a range is selected, separate it
6079 if ( !selection->time.empty()) {
6080 separate_regions_between (selection->time);
6084 //if no range was selected, try to find some regions to split
6085 if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
6087 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6089 framepos_t where = get_preferred_edit_position ();
6095 split_regions_at (where, rs);
6099 struct EditorOrderRouteSorter {
6100 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
6101 return a->order_key () < b->order_key ();
6106 Editor::select_next_route()
6108 if (selection->tracks.empty()) {
6109 selection->set (track_views.front());
6113 TimeAxisView* current = selection->tracks.front();
6117 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6118 if (*i == current) {
6120 if (i != track_views.end()) {
6123 current = (*(track_views.begin()));
6124 //selection->set (*(track_views.begin()));
6129 rui = dynamic_cast<RouteUI *>(current);
6130 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6132 selection->set(current);
6134 ensure_time_axis_view_is_visible (*current, false);
6138 Editor::select_prev_route()
6140 if (selection->tracks.empty()) {
6141 selection->set (track_views.front());
6145 TimeAxisView* current = selection->tracks.front();
6149 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6150 if (*i == current) {
6152 if (i != track_views.rend()) {
6155 current = *(track_views.rbegin());
6160 rui = dynamic_cast<RouteUI *>(current);
6161 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6163 selection->set (current);
6165 ensure_time_axis_view_is_visible (*current, false);
6169 Editor::set_loop_from_selection (bool play)
6171 if (_session == 0) {
6175 framepos_t start, end;
6176 if (!get_selection_extents ( start, end))
6179 set_loop_range (start, end, _("set loop range from selection"));
6182 _session->request_play_loop (true, true);
6187 Editor::set_loop_from_region (bool play)
6189 framepos_t start, end;
6190 if (!get_selection_extents ( start, end))
6193 set_loop_range (start, end, _("set loop range from region"));
6196 _session->request_locate (start, true);
6197 _session->request_play_loop (true);
6202 Editor::set_punch_from_selection ()
6204 if (_session == 0) {
6208 framepos_t start, end;
6209 if (!get_selection_extents ( start, end))
6212 set_punch_range (start, end, _("set punch range from selection"));
6216 Editor::set_session_extents_from_selection ()
6218 if (_session == 0) {
6222 framepos_t start, end;
6223 if (!get_selection_extents ( start, end))
6227 if ((loc = _session->locations()->session_range_location()) == 0) {
6228 _session->set_session_extents ( start, end ); // this will create a new session range; no need for UNDO
6230 XMLNode &before = loc->get_state();
6232 _session->set_session_extents ( start, end );
6234 XMLNode &after = loc->get_state();
6236 begin_reversible_command (_("set session start/end from selection"));
6238 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6240 commit_reversible_command ();
6245 Editor::set_punch_start_from_edit_point ()
6249 framepos_t start = 0;
6250 framepos_t end = max_framepos;
6252 //use the existing punch end, if any
6253 Location* tpl = transport_punch_location();
6258 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6259 start = _session->audible_frame();
6261 start = get_preferred_edit_position();
6264 //snap the selection start/end
6267 //if there's not already a sensible selection endpoint, go "forever"
6268 if ( start > end ) {
6272 set_punch_range (start, end, _("set punch start from EP"));
6278 Editor::set_punch_end_from_edit_point ()
6282 framepos_t start = 0;
6283 framepos_t end = max_framepos;
6285 //use the existing punch start, if any
6286 Location* tpl = transport_punch_location();
6288 start = tpl->start();
6291 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6292 end = _session->audible_frame();
6294 end = get_preferred_edit_position();
6297 //snap the selection start/end
6300 set_punch_range (start, end, _("set punch end from EP"));
6306 Editor::set_loop_start_from_edit_point ()
6310 framepos_t start = 0;
6311 framepos_t end = max_framepos;
6313 //use the existing loop end, if any
6314 Location* tpl = transport_loop_location();
6319 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6320 start = _session->audible_frame();
6322 start = get_preferred_edit_position();
6325 //snap the selection start/end
6328 //if there's not already a sensible selection endpoint, go "forever"
6329 if ( start > end ) {
6333 set_loop_range (start, end, _("set loop start from EP"));
6339 Editor::set_loop_end_from_edit_point ()
6343 framepos_t start = 0;
6344 framepos_t end = max_framepos;
6346 //use the existing loop start, if any
6347 Location* tpl = transport_loop_location();
6349 start = tpl->start();
6352 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6353 end = _session->audible_frame();
6355 end = get_preferred_edit_position();
6358 //snap the selection start/end
6361 set_loop_range (start, end, _("set loop end from EP"));
6366 Editor::set_punch_from_region ()
6368 framepos_t start, end;
6369 if (!get_selection_extents ( start, end))
6372 set_punch_range (start, end, _("set punch range from region"));
6376 Editor::pitch_shift_region ()
6378 RegionSelection rs = get_regions_from_selection_and_entered ();
6380 RegionSelection audio_rs;
6381 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6382 if (dynamic_cast<AudioRegionView*> (*i)) {
6383 audio_rs.push_back (*i);
6387 if (audio_rs.empty()) {
6391 pitch_shift (audio_rs, 1.2);
6395 Editor::set_tempo_from_region ()
6397 RegionSelection rs = get_regions_from_selection_and_entered ();
6399 if (!_session || rs.empty()) {
6403 RegionView* rv = rs.front();
6405 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6409 Editor::use_range_as_bar ()
6411 framepos_t start, end;
6412 if (get_edit_op_range (start, end)) {
6413 define_one_bar (start, end);
6418 Editor::define_one_bar (framepos_t start, framepos_t end)
6420 framepos_t length = end - start;
6422 const Meter& m (_session->tempo_map().meter_at (start));
6424 /* length = 1 bar */
6426 /* now we want frames per beat.
6427 we have frames per bar, and beats per bar, so ...
6430 /* XXXX METER MATH */
6432 double frames_per_beat = length / m.divisions_per_bar();
6434 /* beats per minute = */
6436 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6438 /* now decide whether to:
6440 (a) set global tempo
6441 (b) add a new tempo marker
6445 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
6447 bool do_global = false;
6449 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6451 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6452 at the start, or create a new marker
6455 vector<string> options;
6456 options.push_back (_("Cancel"));
6457 options.push_back (_("Add new marker"));
6458 options.push_back (_("Set global tempo"));
6461 _("Define one bar"),
6462 _("Do you want to set the global tempo or add a new tempo marker?"),
6466 c.set_default_response (2);
6482 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6483 if the marker is at the region starter, change it, otherwise add
6488 begin_reversible_command (_("set tempo from region"));
6489 XMLNode& before (_session->tempo_map().get_state());
6492 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6493 } else if (t.frame() == start) {
6494 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6496 Timecode::BBT_Time bbt;
6497 _session->tempo_map().bbt_time (start, bbt);
6498 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6501 XMLNode& after (_session->tempo_map().get_state());
6503 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6504 commit_reversible_command ();
6508 Editor::split_region_at_transients ()
6510 AnalysisFeatureList positions;
6512 RegionSelection rs = get_regions_from_selection_and_entered ();
6514 if (!_session || rs.empty()) {
6518 begin_reversible_command (_("split regions"));
6520 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6522 RegionSelection::iterator tmp;
6527 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6529 if (ar && (ar->get_transients (positions) == 0)) {
6530 split_region_at_points ((*i)->region(), positions, true);
6537 commit_reversible_command ();
6542 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6544 bool use_rhythmic_rodent = false;
6546 boost::shared_ptr<Playlist> pl = r->playlist();
6548 list<boost::shared_ptr<Region> > new_regions;
6554 if (positions.empty()) {
6559 if (positions.size() > 20 && can_ferret) {
6560 std::string msgstr = string_compose (_("You are about to split\n%1\ninto %2 pieces.\nThis could take a long time."), r->name(), positions.size() + 1);
6561 MessageDialog msg (msgstr,
6564 Gtk::BUTTONS_OK_CANCEL);
6567 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6568 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6570 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6573 msg.set_title (_("Excessive split?"));
6576 int response = msg.run();
6582 case RESPONSE_APPLY:
6583 use_rhythmic_rodent = true;
6590 if (use_rhythmic_rodent) {
6591 show_rhythm_ferret ();
6595 AnalysisFeatureList::const_iterator x;
6597 pl->clear_changes ();
6598 pl->clear_owned_changes ();
6600 x = positions.begin();
6602 if (x == positions.end()) {
6607 pl->remove_region (r);
6611 while (x != positions.end()) {
6613 /* deal with positons that are out of scope of present region bounds */
6614 if (*x <= 0 || *x > r->length()) {
6619 /* file start = original start + how far we from the initial position ?
6622 framepos_t file_start = r->start() + pos;
6624 /* length = next position - current position
6627 framepos_t len = (*x) - pos;
6629 /* XXX we do we really want to allow even single-sample regions?
6630 shouldn't we have some kind of lower limit on region size?
6639 if (RegionFactory::region_name (new_name, r->name())) {
6643 /* do NOT announce new regions 1 by one, just wait till they are all done */
6647 plist.add (ARDOUR::Properties::start, file_start);
6648 plist.add (ARDOUR::Properties::length, len);
6649 plist.add (ARDOUR::Properties::name, new_name);
6650 plist.add (ARDOUR::Properties::layer, 0);
6652 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6653 /* because we set annouce to false, manually add the new region to the
6656 RegionFactory::map_add (nr);
6658 pl->add_region (nr, r->position() + pos);
6661 new_regions.push_front(nr);
6670 RegionFactory::region_name (new_name, r->name());
6672 /* Add the final region */
6675 plist.add (ARDOUR::Properties::start, r->start() + pos);
6676 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6677 plist.add (ARDOUR::Properties::name, new_name);
6678 plist.add (ARDOUR::Properties::layer, 0);
6680 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6681 /* because we set annouce to false, manually add the new region to the
6684 RegionFactory::map_add (nr);
6685 pl->add_region (nr, r->position() + pos);
6688 new_regions.push_front(nr);
6693 /* We might have removed regions, which alters other regions' layering_index,
6694 so we need to do a recursive diff here.
6696 vector<Command*> cmds;
6698 _session->add_commands (cmds);
6700 _session->add_command (new StatefulDiffCommand (pl));
6704 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6705 set_selected_regionview_from_region_list ((*i), Selection::Add);
6711 Editor::place_transient()
6717 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6723 framepos_t where = get_preferred_edit_position();
6725 begin_reversible_command (_("place transient"));
6727 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6728 framepos_t position = (*r)->region()->position();
6729 (*r)->region()->add_transient(where - position);
6732 commit_reversible_command ();
6736 Editor::remove_transient(ArdourCanvas::Item* item)
6742 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6745 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6746 _arv->remove_transient (*(float*) _line->get_data ("position"));
6750 Editor::snap_regions_to_grid ()
6752 list <boost::shared_ptr<Playlist > > used_playlists;
6754 RegionSelection rs = get_regions_from_selection_and_entered ();
6756 if (!_session || rs.empty()) {
6760 begin_reversible_command (_("snap regions to grid"));
6762 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6764 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6766 if (!pl->frozen()) {
6767 /* we haven't seen this playlist before */
6769 /* remember used playlists so we can thaw them later */
6770 used_playlists.push_back(pl);
6774 framepos_t start_frame = (*r)->region()->first_frame ();
6775 snap_to (start_frame);
6776 (*r)->region()->set_position (start_frame);
6779 while (used_playlists.size() > 0) {
6780 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6782 used_playlists.pop_front();
6785 commit_reversible_command ();
6789 Editor::close_region_gaps ()
6791 list <boost::shared_ptr<Playlist > > used_playlists;
6793 RegionSelection rs = get_regions_from_selection_and_entered ();
6795 if (!_session || rs.empty()) {
6799 Dialog dialog (_("Close Region Gaps"));
6802 table.set_spacings (12);
6803 table.set_border_width (12);
6804 Label* l = manage (left_aligned_label (_("Crossfade length")));
6805 table.attach (*l, 0, 1, 0, 1);
6807 SpinButton spin_crossfade (1, 0);
6808 spin_crossfade.set_range (0, 15);
6809 spin_crossfade.set_increments (1, 1);
6810 spin_crossfade.set_value (5);
6811 table.attach (spin_crossfade, 1, 2, 0, 1);
6813 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6815 l = manage (left_aligned_label (_("Pull-back length")));
6816 table.attach (*l, 0, 1, 1, 2);
6818 SpinButton spin_pullback (1, 0);
6819 spin_pullback.set_range (0, 100);
6820 spin_pullback.set_increments (1, 1);
6821 spin_pullback.set_value(30);
6822 table.attach (spin_pullback, 1, 2, 1, 2);
6824 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6826 dialog.get_vbox()->pack_start (table);
6827 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6828 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6831 if (dialog.run () == RESPONSE_CANCEL) {
6835 framepos_t crossfade_len = spin_crossfade.get_value();
6836 framepos_t pull_back_frames = spin_pullback.get_value();
6838 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6839 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6841 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6843 begin_reversible_command (_("close region gaps"));
6846 boost::shared_ptr<Region> last_region;
6848 rs.sort_by_position_and_track();
6850 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6852 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6854 if (!pl->frozen()) {
6855 /* we haven't seen this playlist before */
6857 /* remember used playlists so we can thaw them later */
6858 used_playlists.push_back(pl);
6862 framepos_t position = (*r)->region()->position();
6864 if (idx == 0 || position < last_region->position()){
6865 last_region = (*r)->region();
6870 (*r)->region()->trim_front( (position - pull_back_frames));
6871 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6873 last_region = (*r)->region();
6878 while (used_playlists.size() > 0) {
6879 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6881 used_playlists.pop_front();
6884 commit_reversible_command ();
6888 Editor::tab_to_transient (bool forward)
6890 AnalysisFeatureList positions;
6892 RegionSelection rs = get_regions_from_selection_and_entered ();
6898 framepos_t pos = _session->audible_frame ();
6900 if (!selection->tracks.empty()) {
6902 /* don't waste time searching for transients in duplicate playlists.
6905 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6907 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6909 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6912 boost::shared_ptr<Track> tr = rtv->track();
6914 boost::shared_ptr<Playlist> pl = tr->playlist ();
6916 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6919 positions.push_back (result);
6932 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6933 (*r)->region()->get_transients (positions);
6937 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6940 AnalysisFeatureList::iterator x;
6942 for (x = positions.begin(); x != positions.end(); ++x) {
6948 if (x != positions.end ()) {
6949 _session->request_locate (*x);
6953 AnalysisFeatureList::reverse_iterator x;
6955 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6961 if (x != positions.rend ()) {
6962 _session->request_locate (*x);
6968 Editor::playhead_forward_to_grid ()
6974 framepos_t pos = playhead_cursor->current_frame ();
6975 if (pos < max_framepos - 1) {
6977 snap_to_internal (pos, RoundUpAlways, false);
6978 _session->request_locate (pos);
6984 Editor::playhead_backward_to_grid ()
6990 framepos_t pos = playhead_cursor->current_frame ();
6993 snap_to_internal (pos, RoundDownAlways, false);
6994 _session->request_locate (pos);
6999 Editor::set_track_height (Height h)
7001 TrackSelection& ts (selection->tracks);
7003 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7004 (*x)->set_height_enum (h);
7009 Editor::toggle_tracks_active ()
7011 TrackSelection& ts (selection->tracks);
7013 bool target = false;
7019 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7020 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
7024 target = !rtv->_route->active();
7027 rtv->_route->set_active (target, this);
7033 Editor::remove_tracks ()
7035 /* this will delete GUI objects that may be the subject of an event
7036 handler in which this method is called. Defer actual deletion to the
7037 next idle callback, when all event handling is finished.
7039 Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
7043 Editor::idle_remove_tracks ()
7046 return false; /* do not call again */
7050 Editor::_remove_tracks ()
7052 TrackSelection& ts (selection->tracks);
7058 vector<string> choices;
7062 const char* trackstr;
7064 vector<boost::shared_ptr<Route> > routes;
7065 bool special_bus = false;
7067 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7068 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
7072 if (rtv->is_track()) {
7077 routes.push_back (rtv->_route);
7079 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
7084 if (special_bus && !Config->get_allow_special_bus_removal()) {
7085 MessageDialog msg (_("That would be bad news ...."),
7089 msg.set_secondary_text (string_compose (_(
7090 "Removing the master or monitor bus is such a bad idea\n\
7091 that %1 is not going to allow it.\n\
7093 If you really want to do this sort of thing\n\
7094 edit your ardour.rc file to set the\n\
7095 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
7102 if (ntracks + nbusses == 0) {
7106 trackstr = P_("track", "tracks", ntracks);
7107 busstr = P_("bus", "busses", nbusses);
7111 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
7112 "(You may also lose the playlists associated with the %2)\n\n"
7113 "This action cannot be undone, and the session file will be overwritten!"),
7114 ntracks, trackstr, nbusses, busstr);
7116 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
7117 "(You may also lose the playlists associated with the %2)\n\n"
7118 "This action cannot be undone, and the session file will be overwritten!"),
7121 } else if (nbusses) {
7122 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
7123 "This action cannot be undone, and the session file will be overwritten"),
7127 choices.push_back (_("No, do nothing."));
7128 if (ntracks + nbusses > 1) {
7129 choices.push_back (_("Yes, remove them."));
7131 choices.push_back (_("Yes, remove it."));
7136 title = string_compose (_("Remove %1"), trackstr);
7138 title = string_compose (_("Remove %1"), busstr);
7141 Choice prompter (title, prompt, choices);
7143 if (prompter.run () != 1) {
7148 Session::StateProtector sp (_session);
7149 DisplaySuspender ds;
7150 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
7151 _session->remove_route (*x);
7157 Editor::do_insert_time ()
7159 if (selection->tracks.empty()) {
7163 InsertRemoveTimeDialog d (*this);
7164 int response = d.run ();
7166 if (response != RESPONSE_OK) {
7170 if (d.distance() == 0) {
7174 InsertTimeOption opt = d.intersected_region_action ();
7177 get_preferred_edit_position(),
7183 d.move_glued_markers(),
7184 d.move_locked_markers(),
7190 Editor::insert_time (
7191 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7192 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7196 if (Config->get_edit_mode() == Lock) {
7199 bool in_command = false;
7201 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7203 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7207 /* don't operate on any playlist more than once, which could
7208 * happen if "all playlists" is enabled, but there is more
7209 * than 1 track using playlists "from" a given track.
7212 set<boost::shared_ptr<Playlist> > pl;
7214 if (all_playlists) {
7215 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7216 if (rtav && rtav->track ()) {
7217 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7218 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7223 if ((*x)->playlist ()) {
7224 pl.insert ((*x)->playlist ());
7228 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7230 (*i)->clear_changes ();
7231 (*i)->clear_owned_changes ();
7233 if (opt == SplitIntersected) {
7237 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7240 begin_reversible_command (_("insert time"));
7243 vector<Command*> cmds;
7245 _session->add_commands (cmds);
7247 _session->add_command (new StatefulDiffCommand (*i));
7251 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7254 begin_reversible_command (_("insert time"));
7257 rtav->route ()->shift (pos, frames);
7264 XMLNode& before (_session->locations()->get_state());
7265 Locations::LocationList copy (_session->locations()->list());
7267 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7269 Locations::LocationList::const_iterator tmp;
7271 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7272 bool const was_locked = (*i)->locked ();
7273 if (locked_markers_too) {
7277 if ((*i)->start() >= pos) {
7278 // move end first, in case we're moving by more than the length of the range
7279 if (!(*i)->is_mark()) {
7280 (*i)->set_end ((*i)->end() + frames);
7282 (*i)->set_start ((*i)->start() + frames);
7294 begin_reversible_command (_("insert time"));
7297 XMLNode& after (_session->locations()->get_state());
7298 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7304 begin_reversible_command (_("insert time"));
7307 XMLNode& before (_session->tempo_map().get_state());
7308 _session->tempo_map().insert_time (pos, frames);
7309 XMLNode& after (_session->tempo_map().get_state());
7310 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7314 commit_reversible_command ();
7319 Editor::do_remove_time ()
7321 if (selection->tracks.empty()) {
7325 framepos_t pos = get_preferred_edit_position (EDIT_IGNORE_MOUSE);
7326 InsertRemoveTimeDialog d (*this, true);
7328 int response = d.run ();
7330 if (response != RESPONSE_OK) {
7334 framecnt_t distance = d.distance();
7336 if (distance == 0) {
7346 d.move_glued_markers(),
7347 d.move_locked_markers(),
7353 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7354 bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7356 if (Config->get_edit_mode() == Lock) {
7357 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7360 bool in_command = false;
7362 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7364 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7368 XMLNode &before = pl->get_state();
7370 std::list<AudioRange> rl;
7371 AudioRange ar(pos, pos+frames, 0);
7374 pl->shift (pos, -frames, true, ignore_music_glue);
7377 begin_reversible_command (_("cut time"));
7380 XMLNode &after = pl->get_state();
7382 _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7386 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7389 begin_reversible_command (_("cut time"));
7392 rtav->route ()->shift (pos, -frames);
7396 std::list<Location*> loc_kill_list;
7401 XMLNode& before (_session->locations()->get_state());
7402 Locations::LocationList copy (_session->locations()->list());
7404 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7405 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7407 bool const was_locked = (*i)->locked ();
7408 if (locked_markers_too) {
7412 if (!(*i)->is_mark()) { // it's a range; have to handle both start and end
7413 if ((*i)->end() >= pos
7414 && (*i)->end() < pos+frames
7415 && (*i)->start() >= pos
7416 && (*i)->end() < pos+frames) { // range is completely enclosed; kill it
7418 loc_kill_list.push_back(*i);
7419 } else { // only start or end is included, try to do the right thing
7420 // move start before moving end, to avoid trying to move the end to before the start
7421 // if we're removing more time than the length of the range
7422 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7423 // start is within cut
7424 (*i)->set_start (pos); // bring the start marker to the beginning of the cut
7426 } else if ((*i)->start() >= pos+frames) {
7427 // start (and thus entire range) lies beyond end of cut
7428 (*i)->set_start ((*i)->start() - frames); // slip the start marker back
7431 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7432 // end is inside cut
7433 (*i)->set_end (pos); // bring the end to the cut
7435 } else if ((*i)->end() >= pos+frames) {
7436 // end is beyond end of cut
7437 (*i)->set_end ((*i)->end() - frames); // slip the end marker back
7442 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7443 loc_kill_list.push_back(*i);
7445 } else if ((*i)->start() >= pos) {
7446 (*i)->set_start ((*i)->start() -frames);
7456 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7457 _session->locations()->remove( *i );
7462 begin_reversible_command (_("cut time"));
7465 XMLNode& after (_session->locations()->get_state());
7466 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7471 XMLNode& before (_session->tempo_map().get_state());
7473 if (_session->tempo_map().remove_time (pos, frames) ) {
7475 begin_reversible_command (_("remove time"));
7478 XMLNode& after (_session->tempo_map().get_state());
7479 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7484 commit_reversible_command ();
7489 Editor::fit_selection ()
7491 if (!selection->tracks.empty()) {
7492 fit_tracks (selection->tracks);
7496 /* no selected tracks - use tracks with selected regions */
7498 if (!selection->regions.empty()) {
7499 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7500 tvl.push_back (&(*r)->get_time_axis_view ());
7506 } else if (internal_editing()) {
7507 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7510 if (entered_track) {
7511 tvl.push_back (entered_track);
7520 Editor::fit_tracks (TrackViewList & tracks)
7522 if (tracks.empty()) {
7526 uint32_t child_heights = 0;
7527 int visible_tracks = 0;
7529 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7531 if (!(*t)->marked_for_display()) {
7535 child_heights += (*t)->effective_height() - (*t)->current_height();
7539 /* compute the per-track height from:
7541 total canvas visible height -
7542 height that will be taken by visible children of selected
7543 tracks - height of the ruler/hscroll area
7545 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7546 double first_y_pos = DBL_MAX;
7548 if (h < TimeAxisView::preset_height (HeightSmall)) {
7549 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
7550 /* too small to be displayed */
7554 undo_visual_stack.push_back (current_visual_state (true));
7555 PBD::Unwinder<bool> nsv (no_save_visual, true);
7557 /* build a list of all tracks, including children */
7560 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7562 TimeAxisView::Children c = (*i)->get_child_list ();
7563 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7564 all.push_back (j->get());
7569 // find selection range.
7570 // if someone knows how to user TrackViewList::iterator for this
7572 int selected_top = -1;
7573 int selected_bottom = -1;
7575 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7576 if ((*t)->marked_for_display ()) {
7577 if (tracks.contains(*t)) {
7578 if (selected_top == -1) {
7581 selected_bottom = i;
7587 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7588 if ((*t)->marked_for_display ()) {
7589 if (tracks.contains(*t)) {
7590 (*t)->set_height (h);
7591 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7593 if (i > selected_top && i < selected_bottom) {
7594 hide_track_in_display (*t);
7601 set the controls_layout height now, because waiting for its size
7602 request signal handler will cause the vertical adjustment setting to fail
7605 controls_layout.property_height () = _full_canvas_height;
7606 vertical_adjustment.set_value (first_y_pos);
7608 redo_visual_stack.push_back (current_visual_state (true));
7610 visible_tracks_selector.set_text (_("Sel"));
7614 Editor::save_visual_state (uint32_t n)
7616 while (visual_states.size() <= n) {
7617 visual_states.push_back (0);
7620 if (visual_states[n] != 0) {
7621 delete visual_states[n];
7624 visual_states[n] = current_visual_state (true);
7629 Editor::goto_visual_state (uint32_t n)
7631 if (visual_states.size() <= n) {
7635 if (visual_states[n] == 0) {
7639 use_visual_state (*visual_states[n]);
7643 Editor::start_visual_state_op (uint32_t n)
7645 save_visual_state (n);
7647 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7649 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7650 pup->set_text (buf);
7655 Editor::cancel_visual_state_op (uint32_t n)
7657 goto_visual_state (n);
7661 Editor::toggle_region_mute ()
7663 if (_ignore_region_action) {
7667 RegionSelection rs = get_regions_from_selection_and_entered ();
7673 if (rs.size() > 1) {
7674 begin_reversible_command (_("mute regions"));
7676 begin_reversible_command (_("mute region"));
7679 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7681 (*i)->region()->playlist()->clear_changes ();
7682 (*i)->region()->set_muted (!(*i)->region()->muted ());
7683 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7687 commit_reversible_command ();
7691 Editor::combine_regions ()
7693 /* foreach track with selected regions, take all selected regions
7694 and join them into a new region containing the subregions (as a
7698 typedef set<RouteTimeAxisView*> RTVS;
7701 if (selection->regions.empty()) {
7705 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7706 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7709 tracks.insert (rtv);
7713 begin_reversible_command (_("combine regions"));
7715 vector<RegionView*> new_selection;
7717 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7720 if ((rv = (*i)->combine_regions ()) != 0) {
7721 new_selection.push_back (rv);
7725 selection->clear_regions ();
7726 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7727 selection->add (*i);
7730 commit_reversible_command ();
7734 Editor::uncombine_regions ()
7736 typedef set<RouteTimeAxisView*> RTVS;
7739 if (selection->regions.empty()) {
7743 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7744 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7747 tracks.insert (rtv);
7751 begin_reversible_command (_("uncombine regions"));
7753 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7754 (*i)->uncombine_regions ();
7757 commit_reversible_command ();
7761 Editor::toggle_midi_input_active (bool flip_others)
7764 boost::shared_ptr<RouteList> rl (new RouteList);
7766 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7767 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7773 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7776 rl->push_back (rtav->route());
7777 onoff = !mt->input_active();
7781 _session->set_exclusive_input_active (rl, onoff, flip_others);
7788 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7790 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7791 lock_dialog->get_vbox()->pack_start (*padlock);
7793 ArdourButton* b = manage (new ArdourButton);
7794 b->set_name ("lock button");
7795 b->set_text (_("Click to unlock"));
7796 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7797 lock_dialog->get_vbox()->pack_start (*b);
7799 lock_dialog->get_vbox()->show_all ();
7800 lock_dialog->set_size_request (200, 200);
7803 delete _main_menu_disabler;
7804 _main_menu_disabler = new MainMenuDisabler;
7806 lock_dialog->present ();
7812 lock_dialog->hide ();
7814 delete _main_menu_disabler;
7815 _main_menu_disabler = 0;
7817 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
7818 start_lock_event_timing ();
7823 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7825 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7829 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7831 Timers::TimerSuspender t;
7832 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7833 Gtkmm2ext::UI::instance()->flush_pending ();
7837 Editor::bring_all_sources_into_session ()
7844 ArdourDialog w (_("Moving embedded files into session folder"));
7845 w.get_vbox()->pack_start (msg);
7848 /* flush all pending GUI events because we're about to start copying
7852 Timers::TimerSuspender t;
7853 Gtkmm2ext::UI::instance()->flush_pending ();
7857 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));