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 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4050 switch (mouse_mode) {
4053 begin_reversible_command (opname + ' ' + X_("MIDI"));
4055 commit_reversible_command ();
4061 bool did_edit = false;
4063 if (!selection->regions.empty() || !selection->points.empty()) {
4064 begin_reversible_command (opname + ' ' + _("objects"));
4067 if (!selection->regions.empty()) {
4068 cut_copy_regions (op, selection->regions);
4070 if (op == Cut || op == Delete) {
4071 selection->clear_regions ();
4075 if (!selection->points.empty()) {
4076 cut_copy_points (op);
4078 if (op == Cut || op == Delete) {
4079 selection->clear_points ();
4082 } else if (selection->time.empty()) {
4083 framepos_t start, end;
4084 /* no time selection, see if we can get an edit range
4087 if (get_edit_op_range (start, end)) {
4088 selection->set (start, end);
4090 } else if (!selection->time.empty()) {
4091 begin_reversible_command (opname + ' ' + _("range"));
4094 cut_copy_ranges (op);
4096 if (op == Cut || op == Delete) {
4097 selection->clear_time ();
4102 /* reset repeated paste state */
4105 commit_reversible_command ();
4108 if (op == Delete || op == Cut || op == Clear) {
4113 struct AutomationRecord {
4114 AutomationRecord () : state (0) , line(NULL) {}
4115 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4117 XMLNode* state; ///< state before any operation
4118 const AutomationLine* line; ///< line this came from
4119 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4122 /** Cut, copy or clear selected automation points.
4123 * @param op Operation (Cut, Copy or Clear)
4126 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4128 if (selection->points.empty ()) {
4132 /* XXX: not ideal, as there may be more than one track involved in the point selection */
4133 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4135 /* Keep a record of the AutomationLists that we end up using in this operation */
4136 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4139 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4140 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4141 const AutomationLine& line = (*i)->line();
4142 const boost::shared_ptr<AutomationList> al = line.the_list();
4143 if (lists.find (al) == lists.end ()) {
4144 /* We haven't seen this list yet, so make a record for it. This includes
4145 taking a copy of its current state, in case this is needed for undo later.
4147 lists[al] = AutomationRecord (&al->get_state (), &line);
4151 if (op == Cut || op == Copy) {
4152 /* This operation will involve putting things in the cut buffer, so create an empty
4153 ControlList for each of our source lists to put the cut buffer data in.
4155 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4156 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4159 /* Add all selected points to the relevant copy ControlLists */
4160 framepos_t start = std::numeric_limits<framepos_t>::max();
4161 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4162 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4163 AutomationList::const_iterator j = (*i)->model();
4165 lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
4167 /* Update earliest MIDI start time in beats */
4168 earliest = std::min(earliest, Evoral::Beats((*j)->when));
4170 /* Update earliest session start time in frames */
4171 start = std::min(start, (*i)->line().session_position(j));
4175 /* Snap start time backwards, so copy/paste is snap aligned. */
4177 if (earliest == Evoral::Beats::max()) {
4178 earliest = Evoral::Beats(); // Weird... don't offset
4180 earliest.round_down_to_beat();
4182 if (start == std::numeric_limits<double>::max()) {
4183 start = 0; // Weird... don't offset
4185 snap_to(start, RoundDownMaybe);
4188 const double line_offset = midi ? earliest.to_double() : start;
4189 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4190 /* Correct this copy list so that it is relative to the earliest
4191 start time, so relative ordering between points is preserved
4192 when copying from several lists and the paste starts at the
4193 earliest copied piece of data. */
4194 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
4195 (*j)->when -= line_offset;
4198 /* And add it to the cut buffer */
4199 cut_buffer->add (i->second.copy);
4203 if (op == Delete || op == Cut) {
4204 /* This operation needs to remove things from the main AutomationList, so do that now */
4206 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4207 i->first->freeze ();
4210 /* Remove each selected point from its AutomationList */
4211 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4212 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4213 al->erase ((*i)->model ());
4216 /* Thaw the lists and add undo records for them */
4217 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4218 boost::shared_ptr<AutomationList> al = i->first;
4220 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4225 /** Cut, copy or clear selected automation points.
4226 * @param op Operation (Cut, Copy or Clear)
4229 Editor::cut_copy_midi (CutCopyOp op)
4231 Evoral::Beats earliest = Evoral::Beats::max();
4232 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4233 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4235 if (!mrv->selection().empty()) {
4236 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4238 mrv->cut_copy_clear (op);
4240 /* XXX: not ideal, as there may be more than one track involved in the selection */
4241 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4245 if (!selection->points.empty()) {
4246 cut_copy_points (op, earliest, true);
4247 if (op == Cut || op == Delete) {
4248 selection->clear_points ();
4253 struct lt_playlist {
4254 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4255 return a.playlist < b.playlist;
4259 struct PlaylistMapping {
4261 boost::shared_ptr<Playlist> pl;
4263 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4266 /** Remove `clicked_regionview' */
4268 Editor::remove_clicked_region ()
4270 if (clicked_routeview == 0 || clicked_regionview == 0) {
4274 begin_reversible_command (_("remove region"));
4276 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4278 playlist->clear_changes ();
4279 playlist->clear_owned_changes ();
4280 playlist->remove_region (clicked_regionview->region());
4281 if (Config->get_edit_mode() == Ripple)
4282 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4284 /* We might have removed regions, which alters other regions' layering_index,
4285 so we need to do a recursive diff here.
4287 vector<Command*> cmds;
4288 playlist->rdiff (cmds);
4289 _session->add_commands (cmds);
4291 _session->add_command(new StatefulDiffCommand (playlist));
4292 commit_reversible_command ();
4296 /** Remove the selected regions */
4298 Editor::remove_selected_regions ()
4300 RegionSelection rs = get_regions_from_selection_and_entered ();
4302 if (!_session || rs.empty()) {
4306 list<boost::shared_ptr<Region> > regions_to_remove;
4308 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4309 // we can't just remove the region(s) in this loop because
4310 // this removes them from the RegionSelection, and they thus
4311 // disappear from underneath the iterator, and the ++i above
4312 // SEGVs in a puzzling fashion.
4314 // so, first iterate over the regions to be removed from rs and
4315 // add them to the regions_to_remove list, and then
4316 // iterate over the list to actually remove them.
4318 regions_to_remove.push_back ((*i)->region());
4321 vector<boost::shared_ptr<Playlist> > playlists;
4323 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4325 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4328 // is this check necessary?
4332 /* get_regions_from_selection_and_entered() guarantees that
4333 the playlists involved are unique, so there is no need
4337 playlists.push_back (playlist);
4339 playlist->clear_changes ();
4340 playlist->clear_owned_changes ();
4341 playlist->freeze ();
4342 playlist->remove_region (*rl);
4343 if (Config->get_edit_mode() == Ripple)
4344 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4348 vector<boost::shared_ptr<Playlist> >::iterator pl;
4349 bool in_command = false;
4351 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4354 /* We might have removed regions, which alters other regions' layering_index,
4355 so we need to do a recursive diff here.
4359 begin_reversible_command (_("remove region"));
4362 vector<Command*> cmds;
4363 (*pl)->rdiff (cmds);
4364 _session->add_commands (cmds);
4366 _session->add_command(new StatefulDiffCommand (*pl));
4370 commit_reversible_command ();
4374 /** Cut, copy or clear selected regions.
4375 * @param op Operation (Cut, Copy or Clear)
4378 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4380 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4381 a map when we want ordered access to both elements. i think.
4384 vector<PlaylistMapping> pmap;
4386 framepos_t first_position = max_framepos;
4388 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4389 FreezeList freezelist;
4391 /* get ordering correct before we cut/copy */
4393 rs.sort_by_position_and_track ();
4395 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4397 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4399 if (op == Cut || op == Clear || op == Delete) {
4400 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4403 FreezeList::iterator fl;
4405 // only take state if this is a new playlist.
4406 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4412 if (fl == freezelist.end()) {
4413 pl->clear_changes();
4414 pl->clear_owned_changes ();
4416 freezelist.insert (pl);
4421 TimeAxisView* tv = &(*x)->get_time_axis_view();
4422 vector<PlaylistMapping>::iterator z;
4424 for (z = pmap.begin(); z != pmap.end(); ++z) {
4425 if ((*z).tv == tv) {
4430 if (z == pmap.end()) {
4431 pmap.push_back (PlaylistMapping (tv));
4435 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4437 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4440 /* region not yet associated with a playlist (e.g. unfinished
4447 TimeAxisView& tv = (*x)->get_time_axis_view();
4448 boost::shared_ptr<Playlist> npl;
4449 RegionSelection::iterator tmp;
4456 vector<PlaylistMapping>::iterator z;
4458 for (z = pmap.begin(); z != pmap.end(); ++z) {
4459 if ((*z).tv == &tv) {
4464 assert (z != pmap.end());
4467 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4475 boost::shared_ptr<Region> r = (*x)->region();
4476 boost::shared_ptr<Region> _xx;
4482 pl->remove_region (r);
4483 if (Config->get_edit_mode() == Ripple)
4484 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4488 _xx = RegionFactory::create (r);
4489 npl->add_region (_xx, r->position() - first_position);
4490 pl->remove_region (r);
4491 if (Config->get_edit_mode() == Ripple)
4492 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4496 /* copy region before adding, so we're not putting same object into two different playlists */
4497 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4501 pl->remove_region (r);
4502 if (Config->get_edit_mode() == Ripple)
4503 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4512 list<boost::shared_ptr<Playlist> > foo;
4514 /* the pmap is in the same order as the tracks in which selected regions occured */
4516 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4519 foo.push_back ((*i).pl);
4524 cut_buffer->set (foo);
4528 _last_cut_copy_source_track = 0;
4530 _last_cut_copy_source_track = pmap.front().tv;
4534 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4537 /* We might have removed regions, which alters other regions' layering_index,
4538 so we need to do a recursive diff here.
4540 vector<Command*> cmds;
4541 (*pl)->rdiff (cmds);
4542 _session->add_commands (cmds);
4544 _session->add_command (new StatefulDiffCommand (*pl));
4549 Editor::cut_copy_ranges (CutCopyOp op)
4551 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4553 /* Sort the track selection now, so that it if is used, the playlists
4554 selected by the calls below to cut_copy_clear are in the order that
4555 their tracks appear in the editor. This makes things like paste
4556 of ranges work properly.
4559 sort_track_selection (ts);
4562 if (!entered_track) {
4565 ts.push_back (entered_track);
4568 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4569 (*i)->cut_copy_clear (*selection, op);
4574 Editor::paste (float times, bool from_context)
4576 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4578 paste_internal (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), times);
4582 Editor::mouse_paste ()
4587 if (!mouse_frame (where, ignored)) {
4592 paste_internal (where, 1);
4596 Editor::paste_internal (framepos_t position, float times)
4598 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4600 if (cut_buffer->empty(internal_editing())) {
4604 if (position == max_framepos) {
4605 position = get_preferred_edit_position();
4606 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4609 if (position == last_paste_pos) {
4610 /* repeated paste in the same position */
4613 /* paste in new location, reset repeated paste state */
4615 last_paste_pos = position;
4618 /* get everything in the correct order */
4621 if (!selection->tracks.empty()) {
4622 /* If there is a track selection, paste into exactly those tracks and
4623 only those tracks. This allows the user to be explicit and override
4624 the below "do the reasonable thing" logic. */
4625 ts = selection->tracks.filter_to_unique_playlists ();
4626 sort_track_selection (ts);
4628 /* Figure out which track to base the paste at. */
4629 TimeAxisView* base_track = NULL;
4630 if (_edit_point == Editing::EditAtMouse && entered_track) {
4631 /* With the mouse edit point, paste onto the track under the mouse. */
4632 base_track = entered_track;
4633 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4634 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4635 base_track = &entered_regionview->get_time_axis_view();
4636 } else if (_last_cut_copy_source_track) {
4637 /* Paste to the track that the cut/copy came from (see mantis #333). */
4638 base_track = _last_cut_copy_source_track;
4640 /* This is "impossible" since we've copied... well, do nothing. */
4644 /* Walk up to parent if necessary, so base track is a route. */
4645 while (base_track->get_parent()) {
4646 base_track = base_track->get_parent();
4649 /* Add base track and all tracks below it. The paste logic will select
4650 the appropriate object types from the cut buffer in relative order. */
4651 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4652 if ((*i)->order() >= base_track->order()) {
4657 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4658 sort_track_selection (ts);
4660 /* Add automation children of each track in order, for pasting several lines. */
4661 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4662 /* Add any automation children for pasting several lines */
4663 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4668 typedef RouteTimeAxisView::AutomationTracks ATracks;
4669 const ATracks& atracks = rtv->automation_tracks();
4670 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4671 i = ts.insert(i, a->second.get());
4676 /* We now have a list of trackviews starting at base_track, including
4677 automation children, in the order shown in the editor, e.g. R1,
4678 R1.A1, R1.A2, R2, R2.A1, ... */
4681 begin_reversible_command (Operations::paste);
4683 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4684 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4685 /* Only one line copied, and one automation track selected. Do a
4686 "greedy" paste from one automation type to another. */
4688 PasteContext ctx(paste_count, times, ItemCounts(), true);
4689 ts.front()->paste (position, *cut_buffer, ctx);
4693 /* Paste into tracks */
4695 PasteContext ctx(paste_count, times, ItemCounts(), false);
4696 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4697 (*i)->paste (position, *cut_buffer, ctx);
4701 commit_reversible_command ();
4705 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4707 if (regions.empty ()) {
4711 boost::shared_ptr<Playlist> playlist;
4712 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4713 RegionSelection foo;
4715 framepos_t const start_frame = regions.start ();
4716 framepos_t const end_frame = regions.end_frame ();
4717 framecnt_t const gap = end_frame - start_frame + 1;
4719 begin_reversible_command (Operations::duplicate_region);
4721 selection->clear_regions ();
4723 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4725 boost::shared_ptr<Region> r ((*i)->region());
4727 TimeAxisView& tv = (*i)->get_time_axis_view();
4728 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4729 latest_regionviews.clear ();
4730 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4732 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
4733 playlist = (*i)->region()->playlist();
4734 playlist->clear_changes ();
4735 playlist->duplicate (r, position, gap, times);
4736 _session->add_command(new StatefulDiffCommand (playlist));
4740 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4744 selection->set (foo);
4747 commit_reversible_command ();
4751 Editor::duplicate_selection (float times)
4753 if (selection->time.empty() || selection->tracks.empty()) {
4757 boost::shared_ptr<Playlist> playlist;
4758 vector<boost::shared_ptr<Region> > new_regions;
4759 vector<boost::shared_ptr<Region> >::iterator ri;
4761 create_region_from_selection (new_regions);
4763 if (new_regions.empty()) {
4767 ri = new_regions.begin();
4769 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4770 bool in_command = false;
4772 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4773 if ((playlist = (*i)->playlist()) == 0) {
4776 playlist->clear_changes ();
4778 if (clicked_selection) {
4779 end = selection->time[clicked_selection].end;
4781 end = selection->time.end_frame();
4783 playlist->duplicate (*ri, end + 1, times);
4786 begin_reversible_command (_("duplicate selection"));
4789 _session->add_command (new StatefulDiffCommand (playlist));
4792 if (ri == new_regions.end()) {
4798 commit_reversible_command ();
4802 /** Reset all selected points to the relevant default value */
4804 Editor::reset_point_selection ()
4806 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4807 ARDOUR::AutomationList::iterator j = (*i)->model ();
4808 (*j)->value = (*i)->line().the_list()->default_value ();
4813 Editor::center_playhead ()
4815 float const page = _visible_canvas_width * samples_per_pixel;
4816 center_screen_internal (playhead_cursor->current_frame (), page);
4820 Editor::center_edit_point ()
4822 float const page = _visible_canvas_width * samples_per_pixel;
4823 center_screen_internal (get_preferred_edit_position(), page);
4826 /** Caller must begin and commit a reversible command */
4828 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4830 playlist->clear_changes ();
4832 _session->add_command (new StatefulDiffCommand (playlist));
4836 Editor::nudge_track (bool use_edit, bool forwards)
4838 boost::shared_ptr<Playlist> playlist;
4839 framepos_t distance;
4840 framepos_t next_distance;
4844 start = get_preferred_edit_position();
4849 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4853 if (selection->tracks.empty()) {
4857 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4858 bool in_command = false;
4860 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4862 if ((playlist = (*i)->playlist()) == 0) {
4866 playlist->clear_changes ();
4867 playlist->clear_owned_changes ();
4869 playlist->nudge_after (start, distance, forwards);
4872 begin_reversible_command (_("nudge track"));
4875 vector<Command*> cmds;
4877 playlist->rdiff (cmds);
4878 _session->add_commands (cmds);
4880 _session->add_command (new StatefulDiffCommand (playlist));
4884 commit_reversible_command ();
4889 Editor::remove_last_capture ()
4891 vector<string> choices;
4898 if (Config->get_verify_remove_last_capture()) {
4899 prompt = _("Do you really want to destroy the last capture?"
4900 "\n(This is destructive and cannot be undone)");
4902 choices.push_back (_("No, do nothing."));
4903 choices.push_back (_("Yes, destroy it."));
4905 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4907 if (prompter.run () == 1) {
4908 _session->remove_last_capture ();
4909 _regions->redisplay ();
4913 _session->remove_last_capture();
4914 _regions->redisplay ();
4919 Editor::normalize_region ()
4925 RegionSelection rs = get_regions_from_selection_and_entered ();
4931 NormalizeDialog dialog (rs.size() > 1);
4933 if (dialog.run () == RESPONSE_CANCEL) {
4937 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
4940 /* XXX: should really only count audio regions here */
4941 int const regions = rs.size ();
4943 /* Make a list of the selected audio regions' maximum amplitudes, and also
4944 obtain the maximum amplitude of them all.
4946 list<double> max_amps;
4948 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4949 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4951 dialog.descend (1.0 / regions);
4952 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4955 /* the user cancelled the operation */
4959 max_amps.push_back (a);
4960 max_amp = max (max_amp, a);
4965 list<double>::const_iterator a = max_amps.begin ();
4966 bool in_command = false;
4968 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4969 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4974 arv->region()->clear_changes ();
4976 double const amp = dialog.normalize_individually() ? *a : max_amp;
4978 arv->audio_region()->normalize (amp, dialog.target ());
4981 begin_reversible_command (_("normalize"));
4984 _session->add_command (new StatefulDiffCommand (arv->region()));
4990 commit_reversible_command ();
4996 Editor::reset_region_scale_amplitude ()
5002 RegionSelection rs = get_regions_from_selection_and_entered ();
5008 bool in_command = false;
5010 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5011 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5014 arv->region()->clear_changes ();
5015 arv->audio_region()->set_scale_amplitude (1.0f);
5018 begin_reversible_command ("reset gain");
5021 _session->add_command (new StatefulDiffCommand (arv->region()));
5025 commit_reversible_command ();
5030 Editor::adjust_region_gain (bool up)
5032 RegionSelection rs = get_regions_from_selection_and_entered ();
5034 if (!_session || rs.empty()) {
5038 bool in_command = false;
5040 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5041 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5046 arv->region()->clear_changes ();
5048 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5056 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5059 begin_reversible_command ("adjust region gain");
5062 _session->add_command (new StatefulDiffCommand (arv->region()));
5066 commit_reversible_command ();
5072 Editor::reverse_region ()
5078 Reverse rev (*_session);
5079 apply_filter (rev, _("reverse regions"));
5083 Editor::strip_region_silence ()
5089 RegionSelection rs = get_regions_from_selection_and_entered ();
5095 std::list<RegionView*> audio_only;
5097 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5098 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5100 audio_only.push_back (arv);
5104 assert (!audio_only.empty());
5106 StripSilenceDialog d (_session, audio_only);
5107 int const r = d.run ();
5111 if (r == Gtk::RESPONSE_OK) {
5112 ARDOUR::AudioIntervalMap silences;
5113 d.silences (silences);
5114 StripSilence s (*_session, silences, d.fade_length());
5115 apply_filter (s, _("strip silence"), &d);
5120 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5122 Evoral::Sequence<Evoral::Beats>::Notes selected;
5123 mrv.selection_as_notelist (selected, true);
5125 vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5126 v.push_back (selected);
5128 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
5129 Evoral::Beats pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
5131 return op (mrv.midi_region()->model(), pos_beats, v);
5135 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5141 bool in_command = false;
5143 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5144 RegionSelection::const_iterator tmp = r;
5147 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5150 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5153 begin_reversible_command (op.name ());
5157 _session->add_command (cmd);
5165 commit_reversible_command ();
5170 Editor::fork_region ()
5172 RegionSelection rs = get_regions_from_selection_and_entered ();
5178 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5179 bool in_command = false;
5183 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5184 RegionSelection::iterator tmp = r;
5187 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5191 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5192 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5193 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5196 begin_reversible_command (_("Fork Region(s)"));
5199 playlist->clear_changes ();
5200 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5201 _session->add_command(new StatefulDiffCommand (playlist));
5203 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5211 commit_reversible_command ();
5216 Editor::quantize_region ()
5219 quantize_regions(get_regions_from_selection_and_entered ());
5224 Editor::quantize_regions (const RegionSelection& rs)
5226 if (rs.n_midi_regions() == 0) {
5230 if (!quantize_dialog) {
5231 quantize_dialog = new QuantizeDialog (*this);
5234 quantize_dialog->present ();
5235 const int r = quantize_dialog->run ();
5236 quantize_dialog->hide ();
5238 if (r == Gtk::RESPONSE_OK) {
5239 Quantize quant (quantize_dialog->snap_start(),
5240 quantize_dialog->snap_end(),
5241 quantize_dialog->start_grid_size(),
5242 quantize_dialog->end_grid_size(),
5243 quantize_dialog->strength(),
5244 quantize_dialog->swing(),
5245 quantize_dialog->threshold());
5247 apply_midi_note_edit_op (quant, rs);
5252 Editor::legatize_region (bool shrink_only)
5255 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5260 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5262 if (rs.n_midi_regions() == 0) {
5266 Legatize legatize(shrink_only);
5267 apply_midi_note_edit_op (legatize, rs);
5271 Editor::transform_region ()
5274 transform_regions(get_regions_from_selection_and_entered ());
5279 Editor::transform_regions (const RegionSelection& rs)
5281 if (rs.n_midi_regions() == 0) {
5288 const int r = td.run();
5291 if (r == Gtk::RESPONSE_OK) {
5292 Transform transform(td.get());
5293 apply_midi_note_edit_op(transform, rs);
5298 Editor::transpose_region ()
5301 transpose_regions(get_regions_from_selection_and_entered ());
5306 Editor::transpose_regions (const RegionSelection& rs)
5308 if (rs.n_midi_regions() == 0) {
5313 int const r = d.run ();
5315 if (r == RESPONSE_ACCEPT) {
5316 Transpose transpose(d.semitones ());
5317 apply_midi_note_edit_op (transpose, rs);
5322 Editor::insert_patch_change (bool from_context)
5324 RegionSelection rs = get_regions_from_selection_and_entered ();
5330 const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5332 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5333 there may be more than one, but the PatchChangeDialog can only offer
5334 one set of patch menus.
5336 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5338 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5339 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5341 if (d.run() == RESPONSE_CANCEL) {
5345 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5346 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5348 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5349 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5356 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5358 RegionSelection rs = get_regions_from_selection_and_entered ();
5364 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5365 bool in_command = false;
5370 int const N = rs.size ();
5372 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5373 RegionSelection::iterator tmp = r;
5376 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5378 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5381 progress->descend (1.0 / N);
5384 if (arv->audio_region()->apply (filter, progress) == 0) {
5386 playlist->clear_changes ();
5387 playlist->clear_owned_changes ();
5389 if (filter.results.empty ()) {
5391 /* no regions returned; remove the old one */
5392 playlist->remove_region (arv->region ());
5396 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5398 /* first region replaces the old one */
5399 playlist->replace_region (arv->region(), *res, (*res)->position());
5403 while (res != filter.results.end()) {
5404 playlist->add_region (*res, (*res)->position());
5409 /* We might have removed regions, which alters other regions' layering_index,
5410 so we need to do a recursive diff here.
5414 begin_reversible_command (command);
5417 vector<Command*> cmds;
5418 playlist->rdiff (cmds);
5419 _session->add_commands (cmds);
5421 _session->add_command(new StatefulDiffCommand (playlist));
5425 progress->ascend ();
5434 commit_reversible_command ();
5439 Editor::external_edit_region ()
5445 Editor::reset_region_gain_envelopes ()
5447 RegionSelection rs = get_regions_from_selection_and_entered ();
5449 if (!_session || rs.empty()) {
5453 bool in_command = false;
5455 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5456 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5458 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5459 XMLNode& before (alist->get_state());
5461 arv->audio_region()->set_default_envelope ();
5464 begin_reversible_command (_("reset region gain"));
5467 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5472 commit_reversible_command ();
5477 Editor::set_region_gain_visibility (RegionView* rv)
5479 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5481 arv->update_envelope_visibility();
5486 Editor::set_gain_envelope_visibility ()
5492 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5493 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5495 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5501 Editor::toggle_gain_envelope_active ()
5503 if (_ignore_region_action) {
5507 RegionSelection rs = get_regions_from_selection_and_entered ();
5509 if (!_session || rs.empty()) {
5513 bool in_command = false;
5515 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5516 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5518 arv->region()->clear_changes ();
5519 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5522 begin_reversible_command (_("region gain envelope active"));
5525 _session->add_command (new StatefulDiffCommand (arv->region()));
5530 commit_reversible_command ();
5535 Editor::toggle_region_lock ()
5537 if (_ignore_region_action) {
5541 RegionSelection rs = get_regions_from_selection_and_entered ();
5543 if (!_session || rs.empty()) {
5547 begin_reversible_command (_("toggle region lock"));
5549 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5550 (*i)->region()->clear_changes ();
5551 (*i)->region()->set_locked (!(*i)->region()->locked());
5552 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5555 commit_reversible_command ();
5559 Editor::toggle_region_video_lock ()
5561 if (_ignore_region_action) {
5565 RegionSelection rs = get_regions_from_selection_and_entered ();
5567 if (!_session || rs.empty()) {
5571 begin_reversible_command (_("Toggle Video Lock"));
5573 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5574 (*i)->region()->clear_changes ();
5575 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5576 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5579 commit_reversible_command ();
5583 Editor::toggle_region_lock_style ()
5585 if (_ignore_region_action) {
5589 RegionSelection rs = get_regions_from_selection_and_entered ();
5591 if (!_session || rs.empty()) {
5595 begin_reversible_command (_("region lock style"));
5597 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5598 (*i)->region()->clear_changes ();
5599 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5600 (*i)->region()->set_position_lock_style (ns);
5601 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5604 commit_reversible_command ();
5608 Editor::toggle_opaque_region ()
5610 if (_ignore_region_action) {
5614 RegionSelection rs = get_regions_from_selection_and_entered ();
5616 if (!_session || rs.empty()) {
5620 begin_reversible_command (_("change region opacity"));
5622 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5623 (*i)->region()->clear_changes ();
5624 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5625 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5628 commit_reversible_command ();
5632 Editor::toggle_record_enable ()
5634 bool new_state = false;
5636 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5637 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5640 if (!rtav->is_track())
5644 new_state = !rtav->track()->record_enabled();
5648 rtav->track()->set_record_enabled (new_state, this);
5653 Editor::toggle_solo ()
5655 bool new_state = false;
5657 boost::shared_ptr<RouteList> rl (new RouteList);
5659 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5660 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5667 new_state = !rtav->route()->soloed ();
5671 rl->push_back (rtav->route());
5674 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5678 Editor::toggle_mute ()
5680 bool new_state = false;
5682 boost::shared_ptr<RouteList> rl (new RouteList);
5684 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5685 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5692 new_state = !rtav->route()->muted();
5696 rl->push_back (rtav->route());
5699 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5703 Editor::toggle_solo_isolate ()
5709 Editor::fade_range ()
5711 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5713 begin_reversible_command (_("fade range"));
5715 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5716 (*i)->fade_range (selection->time);
5719 commit_reversible_command ();
5724 Editor::set_fade_length (bool in)
5726 RegionSelection rs = get_regions_from_selection_and_entered ();
5732 /* we need a region to measure the offset from the start */
5734 RegionView* rv = rs.front ();
5736 framepos_t pos = get_preferred_edit_position();
5740 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5741 /* edit point is outside the relevant region */
5746 if (pos <= rv->region()->position()) {
5750 len = pos - rv->region()->position();
5751 cmd = _("set fade in length");
5753 if (pos >= rv->region()->last_frame()) {
5757 len = rv->region()->last_frame() - pos;
5758 cmd = _("set fade out length");
5761 bool in_command = false;
5763 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5764 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5770 boost::shared_ptr<AutomationList> alist;
5772 alist = tmp->audio_region()->fade_in();
5774 alist = tmp->audio_region()->fade_out();
5777 XMLNode &before = alist->get_state();
5780 tmp->audio_region()->set_fade_in_length (len);
5781 tmp->audio_region()->set_fade_in_active (true);
5783 tmp->audio_region()->set_fade_out_length (len);
5784 tmp->audio_region()->set_fade_out_active (true);
5788 begin_reversible_command (cmd);
5791 XMLNode &after = alist->get_state();
5792 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5796 commit_reversible_command ();
5801 Editor::set_fade_in_shape (FadeShape shape)
5803 RegionSelection rs = get_regions_from_selection_and_entered ();
5808 bool in_command = false;
5810 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5811 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5817 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5818 XMLNode &before = alist->get_state();
5820 tmp->audio_region()->set_fade_in_shape (shape);
5823 begin_reversible_command (_("set fade in shape"));
5826 XMLNode &after = alist->get_state();
5827 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5831 commit_reversible_command ();
5836 Editor::set_fade_out_shape (FadeShape shape)
5838 RegionSelection rs = get_regions_from_selection_and_entered ();
5843 bool in_command = false;
5845 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5846 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5852 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5853 XMLNode &before = alist->get_state();
5855 tmp->audio_region()->set_fade_out_shape (shape);
5858 begin_reversible_command (_("set fade out shape"));
5861 XMLNode &after = alist->get_state();
5862 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5866 commit_reversible_command ();
5871 Editor::set_fade_in_active (bool yn)
5873 RegionSelection rs = get_regions_from_selection_and_entered ();
5878 bool in_command = false;
5880 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5881 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5888 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5890 ar->clear_changes ();
5891 ar->set_fade_in_active (yn);
5894 begin_reversible_command (_("set fade in active"));
5897 _session->add_command (new StatefulDiffCommand (ar));
5901 commit_reversible_command ();
5906 Editor::set_fade_out_active (bool yn)
5908 RegionSelection rs = get_regions_from_selection_and_entered ();
5913 bool in_command = false;
5915 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5916 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5922 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5924 ar->clear_changes ();
5925 ar->set_fade_out_active (yn);
5928 begin_reversible_command (_("set fade out active"));
5931 _session->add_command(new StatefulDiffCommand (ar));
5935 commit_reversible_command ();
5940 Editor::toggle_region_fades (int dir)
5942 if (_ignore_region_action) {
5946 boost::shared_ptr<AudioRegion> ar;
5949 RegionSelection rs = get_regions_from_selection_and_entered ();
5955 RegionSelection::iterator i;
5956 for (i = rs.begin(); i != rs.end(); ++i) {
5957 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5959 yn = ar->fade_out_active ();
5961 yn = ar->fade_in_active ();
5967 if (i == rs.end()) {
5971 /* XXX should this undo-able? */
5972 bool in_command = false;
5974 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5975 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5978 ar->clear_changes ();
5980 if (dir == 1 || dir == 0) {
5981 ar->set_fade_in_active (!yn);
5984 if (dir == -1 || dir == 0) {
5985 ar->set_fade_out_active (!yn);
5988 begin_reversible_command (_("toggle fade active"));
5991 _session->add_command(new StatefulDiffCommand (ar));
5995 commit_reversible_command ();
6000 /** Update region fade visibility after its configuration has been changed */
6002 Editor::update_region_fade_visibility ()
6004 bool _fade_visibility = _session->config.get_show_region_fades ();
6006 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6007 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
6009 if (_fade_visibility) {
6010 v->audio_view()->show_all_fades ();
6012 v->audio_view()->hide_all_fades ();
6019 Editor::set_edit_point ()
6024 if (!mouse_frame (where, ignored)) {
6030 if (selection->markers.empty()) {
6032 mouse_add_new_marker (where);
6037 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
6040 loc->move_to (where);
6046 Editor::set_playhead_cursor ()
6048 if (entered_marker) {
6049 _session->request_locate (entered_marker->position(), _session->transport_rolling());
6054 if (!mouse_frame (where, ignored)) {
6061 _session->request_locate (where, _session->transport_rolling());
6065 if (UIConfiguration::instance().get_follow_edits() && (!_session || !_session->config.get_external_sync())) {
6066 cancel_time_selection();
6071 Editor::split_region ()
6073 if (_drags->active ()) {
6077 //if a range is selected, separate it
6078 if ( !selection->time.empty()) {
6079 separate_regions_between (selection->time);
6083 //if no range was selected, try to find some regions to split
6084 if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
6086 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6088 framepos_t where = get_preferred_edit_position ();
6094 split_regions_at (where, rs);
6098 struct EditorOrderRouteSorter {
6099 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
6100 return a->order_key () < b->order_key ();
6105 Editor::select_next_route()
6107 if (selection->tracks.empty()) {
6108 selection->set (track_views.front());
6112 TimeAxisView* current = selection->tracks.front();
6116 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6117 if (*i == current) {
6119 if (i != track_views.end()) {
6122 current = (*(track_views.begin()));
6123 //selection->set (*(track_views.begin()));
6128 rui = dynamic_cast<RouteUI *>(current);
6129 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6131 selection->set(current);
6133 ensure_time_axis_view_is_visible (*current, false);
6137 Editor::select_prev_route()
6139 if (selection->tracks.empty()) {
6140 selection->set (track_views.front());
6144 TimeAxisView* current = selection->tracks.front();
6148 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6149 if (*i == current) {
6151 if (i != track_views.rend()) {
6154 current = *(track_views.rbegin());
6159 rui = dynamic_cast<RouteUI *>(current);
6160 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6162 selection->set (current);
6164 ensure_time_axis_view_is_visible (*current, false);
6168 Editor::set_loop_from_selection (bool play)
6170 if (_session == 0) {
6174 framepos_t start, end;
6175 if (!get_selection_extents ( start, end))
6178 set_loop_range (start, end, _("set loop range from selection"));
6181 _session->request_play_loop (true, true);
6186 Editor::set_loop_from_region (bool play)
6188 framepos_t start, end;
6189 if (!get_selection_extents ( start, end))
6192 set_loop_range (start, end, _("set loop range from region"));
6195 _session->request_locate (start, true);
6196 _session->request_play_loop (true);
6201 Editor::set_punch_from_selection ()
6203 if (_session == 0) {
6207 framepos_t start, end;
6208 if (!get_selection_extents ( start, end))
6211 set_punch_range (start, end, _("set punch range from selection"));
6215 Editor::set_session_extents_from_selection ()
6217 if (_session == 0) {
6221 framepos_t start, end;
6222 if (!get_selection_extents ( start, end))
6226 if ((loc = _session->locations()->session_range_location()) == 0) {
6227 _session->set_session_extents ( start, end ); // this will create a new session range; no need for UNDO
6229 XMLNode &before = loc->get_state();
6231 _session->set_session_extents ( start, end );
6233 XMLNode &after = loc->get_state();
6235 begin_reversible_command (_("set session start/end from selection"));
6237 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6239 commit_reversible_command ();
6244 Editor::set_punch_start_from_edit_point ()
6248 framepos_t start = 0;
6249 framepos_t end = max_framepos;
6251 //use the existing punch end, if any
6252 Location* tpl = transport_punch_location();
6257 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6258 start = _session->audible_frame();
6260 start = get_preferred_edit_position();
6263 //snap the selection start/end
6266 //if there's not already a sensible selection endpoint, go "forever"
6267 if ( start > end ) {
6271 set_punch_range (start, end, _("set punch start from EP"));
6277 Editor::set_punch_end_from_edit_point ()
6281 framepos_t start = 0;
6282 framepos_t end = max_framepos;
6284 //use the existing punch start, if any
6285 Location* tpl = transport_punch_location();
6287 start = tpl->start();
6290 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6291 end = _session->audible_frame();
6293 end = get_preferred_edit_position();
6296 //snap the selection start/end
6299 set_punch_range (start, end, _("set punch end from EP"));
6305 Editor::set_loop_start_from_edit_point ()
6309 framepos_t start = 0;
6310 framepos_t end = max_framepos;
6312 //use the existing loop end, if any
6313 Location* tpl = transport_loop_location();
6318 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6319 start = _session->audible_frame();
6321 start = get_preferred_edit_position();
6324 //snap the selection start/end
6327 //if there's not already a sensible selection endpoint, go "forever"
6328 if ( start > end ) {
6332 set_loop_range (start, end, _("set loop start from EP"));
6338 Editor::set_loop_end_from_edit_point ()
6342 framepos_t start = 0;
6343 framepos_t end = max_framepos;
6345 //use the existing loop start, if any
6346 Location* tpl = transport_loop_location();
6348 start = tpl->start();
6351 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6352 end = _session->audible_frame();
6354 end = get_preferred_edit_position();
6357 //snap the selection start/end
6360 set_loop_range (start, end, _("set loop end from EP"));
6365 Editor::set_punch_from_region ()
6367 framepos_t start, end;
6368 if (!get_selection_extents ( start, end))
6371 set_punch_range (start, end, _("set punch range from region"));
6375 Editor::pitch_shift_region ()
6377 RegionSelection rs = get_regions_from_selection_and_entered ();
6379 RegionSelection audio_rs;
6380 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6381 if (dynamic_cast<AudioRegionView*> (*i)) {
6382 audio_rs.push_back (*i);
6386 if (audio_rs.empty()) {
6390 pitch_shift (audio_rs, 1.2);
6394 Editor::set_tempo_from_region ()
6396 RegionSelection rs = get_regions_from_selection_and_entered ();
6398 if (!_session || rs.empty()) {
6402 RegionView* rv = rs.front();
6404 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6408 Editor::use_range_as_bar ()
6410 framepos_t start, end;
6411 if (get_edit_op_range (start, end)) {
6412 define_one_bar (start, end);
6417 Editor::define_one_bar (framepos_t start, framepos_t end)
6419 framepos_t length = end - start;
6421 const Meter& m (_session->tempo_map().meter_at (start));
6423 /* length = 1 bar */
6425 /* now we want frames per beat.
6426 we have frames per bar, and beats per bar, so ...
6429 /* XXXX METER MATH */
6431 double frames_per_beat = length / m.divisions_per_bar();
6433 /* beats per minute = */
6435 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6437 /* now decide whether to:
6439 (a) set global tempo
6440 (b) add a new tempo marker
6444 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
6446 bool do_global = false;
6448 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6450 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6451 at the start, or create a new marker
6454 vector<string> options;
6455 options.push_back (_("Cancel"));
6456 options.push_back (_("Add new marker"));
6457 options.push_back (_("Set global tempo"));
6460 _("Define one bar"),
6461 _("Do you want to set the global tempo or add a new tempo marker?"),
6465 c.set_default_response (2);
6481 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6482 if the marker is at the region starter, change it, otherwise add
6487 begin_reversible_command (_("set tempo from region"));
6488 XMLNode& before (_session->tempo_map().get_state());
6491 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6492 } else if (t.frame() == start) {
6493 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6495 Timecode::BBT_Time bbt;
6496 _session->tempo_map().bbt_time (start, bbt);
6497 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6500 XMLNode& after (_session->tempo_map().get_state());
6502 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6503 commit_reversible_command ();
6507 Editor::split_region_at_transients ()
6509 AnalysisFeatureList positions;
6511 RegionSelection rs = get_regions_from_selection_and_entered ();
6513 if (!_session || rs.empty()) {
6517 begin_reversible_command (_("split regions"));
6519 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6521 RegionSelection::iterator tmp;
6526 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6528 if (ar && (ar->get_transients (positions) == 0)) {
6529 split_region_at_points ((*i)->region(), positions, true);
6536 commit_reversible_command ();
6541 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6543 bool use_rhythmic_rodent = false;
6545 boost::shared_ptr<Playlist> pl = r->playlist();
6547 list<boost::shared_ptr<Region> > new_regions;
6553 if (positions.empty()) {
6558 if (positions.size() > 20 && can_ferret) {
6559 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);
6560 MessageDialog msg (msgstr,
6563 Gtk::BUTTONS_OK_CANCEL);
6566 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6567 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6569 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6572 msg.set_title (_("Excessive split?"));
6575 int response = msg.run();
6581 case RESPONSE_APPLY:
6582 use_rhythmic_rodent = true;
6589 if (use_rhythmic_rodent) {
6590 show_rhythm_ferret ();
6594 AnalysisFeatureList::const_iterator x;
6596 pl->clear_changes ();
6597 pl->clear_owned_changes ();
6599 x = positions.begin();
6601 if (x == positions.end()) {
6606 pl->remove_region (r);
6610 while (x != positions.end()) {
6612 /* deal with positons that are out of scope of present region bounds */
6613 if (*x <= 0 || *x > r->length()) {
6618 /* file start = original start + how far we from the initial position ?
6621 framepos_t file_start = r->start() + pos;
6623 /* length = next position - current position
6626 framepos_t len = (*x) - pos;
6628 /* XXX we do we really want to allow even single-sample regions?
6629 shouldn't we have some kind of lower limit on region size?
6638 if (RegionFactory::region_name (new_name, r->name())) {
6642 /* do NOT announce new regions 1 by one, just wait till they are all done */
6646 plist.add (ARDOUR::Properties::start, file_start);
6647 plist.add (ARDOUR::Properties::length, len);
6648 plist.add (ARDOUR::Properties::name, new_name);
6649 plist.add (ARDOUR::Properties::layer, 0);
6651 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6652 /* because we set annouce to false, manually add the new region to the
6655 RegionFactory::map_add (nr);
6657 pl->add_region (nr, r->position() + pos);
6660 new_regions.push_front(nr);
6669 RegionFactory::region_name (new_name, r->name());
6671 /* Add the final region */
6674 plist.add (ARDOUR::Properties::start, r->start() + pos);
6675 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6676 plist.add (ARDOUR::Properties::name, new_name);
6677 plist.add (ARDOUR::Properties::layer, 0);
6679 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6680 /* because we set annouce to false, manually add the new region to the
6683 RegionFactory::map_add (nr);
6684 pl->add_region (nr, r->position() + pos);
6687 new_regions.push_front(nr);
6692 /* We might have removed regions, which alters other regions' layering_index,
6693 so we need to do a recursive diff here.
6695 vector<Command*> cmds;
6697 _session->add_commands (cmds);
6699 _session->add_command (new StatefulDiffCommand (pl));
6703 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6704 set_selected_regionview_from_region_list ((*i), Selection::Add);
6710 Editor::place_transient()
6716 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6722 framepos_t where = get_preferred_edit_position();
6724 begin_reversible_command (_("place transient"));
6726 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6727 framepos_t position = (*r)->region()->position();
6728 (*r)->region()->add_transient(where - position);
6731 commit_reversible_command ();
6735 Editor::remove_transient(ArdourCanvas::Item* item)
6741 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6744 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6745 _arv->remove_transient (*(float*) _line->get_data ("position"));
6749 Editor::snap_regions_to_grid ()
6751 list <boost::shared_ptr<Playlist > > used_playlists;
6753 RegionSelection rs = get_regions_from_selection_and_entered ();
6755 if (!_session || rs.empty()) {
6759 begin_reversible_command (_("snap regions to grid"));
6761 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6763 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6765 if (!pl->frozen()) {
6766 /* we haven't seen this playlist before */
6768 /* remember used playlists so we can thaw them later */
6769 used_playlists.push_back(pl);
6773 framepos_t start_frame = (*r)->region()->first_frame ();
6774 snap_to (start_frame);
6775 (*r)->region()->set_position (start_frame);
6778 while (used_playlists.size() > 0) {
6779 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6781 used_playlists.pop_front();
6784 commit_reversible_command ();
6788 Editor::close_region_gaps ()
6790 list <boost::shared_ptr<Playlist > > used_playlists;
6792 RegionSelection rs = get_regions_from_selection_and_entered ();
6794 if (!_session || rs.empty()) {
6798 Dialog dialog (_("Close Region Gaps"));
6801 table.set_spacings (12);
6802 table.set_border_width (12);
6803 Label* l = manage (left_aligned_label (_("Crossfade length")));
6804 table.attach (*l, 0, 1, 0, 1);
6806 SpinButton spin_crossfade (1, 0);
6807 spin_crossfade.set_range (0, 15);
6808 spin_crossfade.set_increments (1, 1);
6809 spin_crossfade.set_value (5);
6810 table.attach (spin_crossfade, 1, 2, 0, 1);
6812 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6814 l = manage (left_aligned_label (_("Pull-back length")));
6815 table.attach (*l, 0, 1, 1, 2);
6817 SpinButton spin_pullback (1, 0);
6818 spin_pullback.set_range (0, 100);
6819 spin_pullback.set_increments (1, 1);
6820 spin_pullback.set_value(30);
6821 table.attach (spin_pullback, 1, 2, 1, 2);
6823 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6825 dialog.get_vbox()->pack_start (table);
6826 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6827 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6830 if (dialog.run () == RESPONSE_CANCEL) {
6834 framepos_t crossfade_len = spin_crossfade.get_value();
6835 framepos_t pull_back_frames = spin_pullback.get_value();
6837 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6838 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6840 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6842 begin_reversible_command (_("close region gaps"));
6845 boost::shared_ptr<Region> last_region;
6847 rs.sort_by_position_and_track();
6849 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6851 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6853 if (!pl->frozen()) {
6854 /* we haven't seen this playlist before */
6856 /* remember used playlists so we can thaw them later */
6857 used_playlists.push_back(pl);
6861 framepos_t position = (*r)->region()->position();
6863 if (idx == 0 || position < last_region->position()){
6864 last_region = (*r)->region();
6869 (*r)->region()->trim_front( (position - pull_back_frames));
6870 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6872 last_region = (*r)->region();
6877 while (used_playlists.size() > 0) {
6878 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6880 used_playlists.pop_front();
6883 commit_reversible_command ();
6887 Editor::tab_to_transient (bool forward)
6889 AnalysisFeatureList positions;
6891 RegionSelection rs = get_regions_from_selection_and_entered ();
6897 framepos_t pos = _session->audible_frame ();
6899 if (!selection->tracks.empty()) {
6901 /* don't waste time searching for transients in duplicate playlists.
6904 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6906 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6908 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6911 boost::shared_ptr<Track> tr = rtv->track();
6913 boost::shared_ptr<Playlist> pl = tr->playlist ();
6915 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6918 positions.push_back (result);
6931 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6932 (*r)->region()->get_transients (positions);
6936 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6939 AnalysisFeatureList::iterator x;
6941 for (x = positions.begin(); x != positions.end(); ++x) {
6947 if (x != positions.end ()) {
6948 _session->request_locate (*x);
6952 AnalysisFeatureList::reverse_iterator x;
6954 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6960 if (x != positions.rend ()) {
6961 _session->request_locate (*x);
6967 Editor::playhead_forward_to_grid ()
6973 framepos_t pos = playhead_cursor->current_frame ();
6974 if (pos < max_framepos - 1) {
6976 snap_to_internal (pos, RoundUpAlways, false);
6977 _session->request_locate (pos);
6983 Editor::playhead_backward_to_grid ()
6989 framepos_t pos = playhead_cursor->current_frame ();
6992 snap_to_internal (pos, RoundDownAlways, false);
6993 _session->request_locate (pos);
6998 Editor::set_track_height (Height h)
7000 TrackSelection& ts (selection->tracks);
7002 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7003 (*x)->set_height_enum (h);
7008 Editor::toggle_tracks_active ()
7010 TrackSelection& ts (selection->tracks);
7012 bool target = false;
7018 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7019 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
7023 target = !rtv->_route->active();
7026 rtv->_route->set_active (target, this);
7032 Editor::remove_tracks ()
7034 /* this will delete GUI objects that may be the subject of an event
7035 handler in which this method is called. Defer actual deletion to the
7036 next idle callback, when all event handling is finished.
7038 Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
7042 Editor::idle_remove_tracks ()
7045 return false; /* do not call again */
7049 Editor::_remove_tracks ()
7051 TrackSelection& ts (selection->tracks);
7057 vector<string> choices;
7061 const char* trackstr;
7063 vector<boost::shared_ptr<Route> > routes;
7064 bool special_bus = false;
7066 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7067 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
7071 if (rtv->is_track()) {
7076 routes.push_back (rtv->_route);
7078 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
7083 if (special_bus && !Config->get_allow_special_bus_removal()) {
7084 MessageDialog msg (_("That would be bad news ...."),
7088 msg.set_secondary_text (string_compose (_(
7089 "Removing the master or monitor bus is such a bad idea\n\
7090 that %1 is not going to allow it.\n\
7092 If you really want to do this sort of thing\n\
7093 edit your ardour.rc file to set the\n\
7094 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
7101 if (ntracks + nbusses == 0) {
7105 trackstr = P_("track", "tracks", ntracks);
7106 busstr = P_("bus", "busses", nbusses);
7110 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
7111 "(You may also lose the playlists associated with the %2)\n\n"
7112 "This action cannot be undone, and the session file will be overwritten!"),
7113 ntracks, trackstr, nbusses, busstr);
7115 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
7116 "(You may also lose the playlists associated with the %2)\n\n"
7117 "This action cannot be undone, and the session file will be overwritten!"),
7120 } else if (nbusses) {
7121 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
7122 "This action cannot be undone, and the session file will be overwritten"),
7126 choices.push_back (_("No, do nothing."));
7127 if (ntracks + nbusses > 1) {
7128 choices.push_back (_("Yes, remove them."));
7130 choices.push_back (_("Yes, remove it."));
7135 title = string_compose (_("Remove %1"), trackstr);
7137 title = string_compose (_("Remove %1"), busstr);
7140 Choice prompter (title, prompt, choices);
7142 if (prompter.run () != 1) {
7147 Session::StateProtector sp (_session);
7148 DisplaySuspender ds;
7149 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
7150 _session->remove_route (*x);
7156 Editor::do_insert_time ()
7158 if (selection->tracks.empty()) {
7162 InsertRemoveTimeDialog d (*this);
7163 int response = d.run ();
7165 if (response != RESPONSE_OK) {
7169 if (d.distance() == 0) {
7173 InsertTimeOption opt = d.intersected_region_action ();
7176 get_preferred_edit_position(),
7182 d.move_glued_markers(),
7183 d.move_locked_markers(),
7189 Editor::insert_time (
7190 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7191 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7195 if (Config->get_edit_mode() == Lock) {
7198 bool in_command = false;
7200 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7202 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7206 /* don't operate on any playlist more than once, which could
7207 * happen if "all playlists" is enabled, but there is more
7208 * than 1 track using playlists "from" a given track.
7211 set<boost::shared_ptr<Playlist> > pl;
7213 if (all_playlists) {
7214 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7215 if (rtav && rtav->track ()) {
7216 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7217 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7222 if ((*x)->playlist ()) {
7223 pl.insert ((*x)->playlist ());
7227 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7229 (*i)->clear_changes ();
7230 (*i)->clear_owned_changes ();
7232 if (opt == SplitIntersected) {
7236 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7239 begin_reversible_command (_("insert time"));
7242 vector<Command*> cmds;
7244 _session->add_commands (cmds);
7246 _session->add_command (new StatefulDiffCommand (*i));
7250 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7253 begin_reversible_command (_("insert time"));
7256 rtav->route ()->shift (pos, frames);
7263 XMLNode& before (_session->locations()->get_state());
7264 Locations::LocationList copy (_session->locations()->list());
7266 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7268 Locations::LocationList::const_iterator tmp;
7270 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7271 bool const was_locked = (*i)->locked ();
7272 if (locked_markers_too) {
7276 if ((*i)->start() >= pos) {
7277 // move end first, in case we're moving by more than the length of the range
7278 if (!(*i)->is_mark()) {
7279 (*i)->set_end ((*i)->end() + frames);
7281 (*i)->set_start ((*i)->start() + frames);
7293 begin_reversible_command (_("insert time"));
7296 XMLNode& after (_session->locations()->get_state());
7297 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7303 begin_reversible_command (_("insert time"));
7306 XMLNode& before (_session->tempo_map().get_state());
7307 _session->tempo_map().insert_time (pos, frames);
7308 XMLNode& after (_session->tempo_map().get_state());
7309 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7313 commit_reversible_command ();
7318 Editor::do_remove_time ()
7320 if (selection->tracks.empty()) {
7324 framepos_t pos = get_preferred_edit_position (EDIT_IGNORE_MOUSE);
7325 InsertRemoveTimeDialog d (*this, true);
7327 int response = d.run ();
7329 if (response != RESPONSE_OK) {
7333 framecnt_t distance = d.distance();
7335 if (distance == 0) {
7345 d.move_glued_markers(),
7346 d.move_locked_markers(),
7352 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7353 bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7355 if (Config->get_edit_mode() == Lock) {
7356 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7359 bool in_command = false;
7361 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7363 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7367 XMLNode &before = pl->get_state();
7369 std::list<AudioRange> rl;
7370 AudioRange ar(pos, pos+frames, 0);
7373 pl->shift (pos, -frames, true, ignore_music_glue);
7376 begin_reversible_command (_("cut time"));
7379 XMLNode &after = pl->get_state();
7381 _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7385 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7388 begin_reversible_command (_("cut time"));
7391 rtav->route ()->shift (pos, -frames);
7395 std::list<Location*> loc_kill_list;
7400 XMLNode& before (_session->locations()->get_state());
7401 Locations::LocationList copy (_session->locations()->list());
7403 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7404 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7406 bool const was_locked = (*i)->locked ();
7407 if (locked_markers_too) {
7411 if (!(*i)->is_mark()) { // it's a range; have to handle both start and end
7412 if ((*i)->end() >= pos
7413 && (*i)->end() < pos+frames
7414 && (*i)->start() >= pos
7415 && (*i)->end() < pos+frames) { // range is completely enclosed; kill it
7417 loc_kill_list.push_back(*i);
7418 } else { // only start or end is included, try to do the right thing
7419 // move start before moving end, to avoid trying to move the end to before the start
7420 // if we're removing more time than the length of the range
7421 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7422 // start is within cut
7423 (*i)->set_start (pos); // bring the start marker to the beginning of the cut
7425 } else if ((*i)->start() >= pos+frames) {
7426 // start (and thus entire range) lies beyond end of cut
7427 (*i)->set_start ((*i)->start() - frames); // slip the start marker back
7430 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7431 // end is inside cut
7432 (*i)->set_end (pos); // bring the end to the cut
7434 } else if ((*i)->end() >= pos+frames) {
7435 // end is beyond end of cut
7436 (*i)->set_end ((*i)->end() - frames); // slip the end marker back
7441 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7442 loc_kill_list.push_back(*i);
7444 } else if ((*i)->start() >= pos) {
7445 (*i)->set_start ((*i)->start() -frames);
7455 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7456 _session->locations()->remove( *i );
7461 begin_reversible_command (_("cut time"));
7464 XMLNode& after (_session->locations()->get_state());
7465 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7470 XMLNode& before (_session->tempo_map().get_state());
7472 if (_session->tempo_map().remove_time (pos, frames) ) {
7474 begin_reversible_command (_("remove time"));
7477 XMLNode& after (_session->tempo_map().get_state());
7478 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7483 commit_reversible_command ();
7488 Editor::fit_selection ()
7490 if (!selection->tracks.empty()) {
7491 fit_tracks (selection->tracks);
7495 /* no selected tracks - use tracks with selected regions */
7497 if (!selection->regions.empty()) {
7498 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7499 tvl.push_back (&(*r)->get_time_axis_view ());
7505 } else if (internal_editing()) {
7506 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7509 if (entered_track) {
7510 tvl.push_back (entered_track);
7519 Editor::fit_tracks (TrackViewList & tracks)
7521 if (tracks.empty()) {
7525 uint32_t child_heights = 0;
7526 int visible_tracks = 0;
7528 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7530 if (!(*t)->marked_for_display()) {
7534 child_heights += (*t)->effective_height() - (*t)->current_height();
7538 /* compute the per-track height from:
7540 total canvas visible height -
7541 height that will be taken by visible children of selected
7542 tracks - height of the ruler/hscroll area
7544 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7545 double first_y_pos = DBL_MAX;
7547 if (h < TimeAxisView::preset_height (HeightSmall)) {
7548 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
7549 /* too small to be displayed */
7553 undo_visual_stack.push_back (current_visual_state (true));
7554 PBD::Unwinder<bool> nsv (no_save_visual, true);
7556 /* build a list of all tracks, including children */
7559 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7561 TimeAxisView::Children c = (*i)->get_child_list ();
7562 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7563 all.push_back (j->get());
7568 // find selection range.
7569 // if someone knows how to user TrackViewList::iterator for this
7571 int selected_top = -1;
7572 int selected_bottom = -1;
7574 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7575 if ((*t)->marked_for_display ()) {
7576 if (tracks.contains(*t)) {
7577 if (selected_top == -1) {
7580 selected_bottom = i;
7586 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7587 if ((*t)->marked_for_display ()) {
7588 if (tracks.contains(*t)) {
7589 (*t)->set_height (h);
7590 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7592 if (i > selected_top && i < selected_bottom) {
7593 hide_track_in_display (*t);
7600 set the controls_layout height now, because waiting for its size
7601 request signal handler will cause the vertical adjustment setting to fail
7604 controls_layout.property_height () = _full_canvas_height;
7605 vertical_adjustment.set_value (first_y_pos);
7607 redo_visual_stack.push_back (current_visual_state (true));
7609 visible_tracks_selector.set_text (_("Sel"));
7613 Editor::save_visual_state (uint32_t n)
7615 while (visual_states.size() <= n) {
7616 visual_states.push_back (0);
7619 if (visual_states[n] != 0) {
7620 delete visual_states[n];
7623 visual_states[n] = current_visual_state (true);
7628 Editor::goto_visual_state (uint32_t n)
7630 if (visual_states.size() <= n) {
7634 if (visual_states[n] == 0) {
7638 use_visual_state (*visual_states[n]);
7642 Editor::start_visual_state_op (uint32_t n)
7644 save_visual_state (n);
7646 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7648 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7649 pup->set_text (buf);
7654 Editor::cancel_visual_state_op (uint32_t n)
7656 goto_visual_state (n);
7660 Editor::toggle_region_mute ()
7662 if (_ignore_region_action) {
7666 RegionSelection rs = get_regions_from_selection_and_entered ();
7672 if (rs.size() > 1) {
7673 begin_reversible_command (_("mute regions"));
7675 begin_reversible_command (_("mute region"));
7678 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7680 (*i)->region()->playlist()->clear_changes ();
7681 (*i)->region()->set_muted (!(*i)->region()->muted ());
7682 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7686 commit_reversible_command ();
7690 Editor::combine_regions ()
7692 /* foreach track with selected regions, take all selected regions
7693 and join them into a new region containing the subregions (as a
7697 typedef set<RouteTimeAxisView*> RTVS;
7700 if (selection->regions.empty()) {
7704 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7705 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7708 tracks.insert (rtv);
7712 begin_reversible_command (_("combine regions"));
7714 vector<RegionView*> new_selection;
7716 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7719 if ((rv = (*i)->combine_regions ()) != 0) {
7720 new_selection.push_back (rv);
7724 selection->clear_regions ();
7725 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7726 selection->add (*i);
7729 commit_reversible_command ();
7733 Editor::uncombine_regions ()
7735 typedef set<RouteTimeAxisView*> RTVS;
7738 if (selection->regions.empty()) {
7742 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7743 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7746 tracks.insert (rtv);
7750 begin_reversible_command (_("uncombine regions"));
7752 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7753 (*i)->uncombine_regions ();
7756 commit_reversible_command ();
7760 Editor::toggle_midi_input_active (bool flip_others)
7763 boost::shared_ptr<RouteList> rl (new RouteList);
7765 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7766 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7772 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7775 rl->push_back (rtav->route());
7776 onoff = !mt->input_active();
7780 _session->set_exclusive_input_active (rl, onoff, flip_others);
7787 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7789 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7790 lock_dialog->get_vbox()->pack_start (*padlock);
7792 ArdourButton* b = manage (new ArdourButton);
7793 b->set_name ("lock button");
7794 b->set_text (_("Click to unlock"));
7795 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7796 lock_dialog->get_vbox()->pack_start (*b);
7798 lock_dialog->get_vbox()->show_all ();
7799 lock_dialog->set_size_request (200, 200);
7802 delete _main_menu_disabler;
7803 _main_menu_disabler = new MainMenuDisabler;
7805 lock_dialog->present ();
7811 lock_dialog->hide ();
7813 delete _main_menu_disabler;
7814 _main_menu_disabler = 0;
7816 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
7817 start_lock_event_timing ();
7822 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7824 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7828 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7830 Timers::TimerSuspender t;
7831 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7832 Gtkmm2ext::UI::instance()->flush_pending ();
7836 Editor::bring_all_sources_into_session ()
7843 ArdourDialog w (_("Moving embedded files into session folder"));
7844 w.get_vbox()->pack_start (msg);
7847 /* flush all pending GUI events because we're about to start copying
7851 Timers::TimerSuspender t;
7852 Gtkmm2ext::UI::instance()->flush_pending ();
7856 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));